Path: blob/master/arch/powerpc/kvm/book3s_emulate.c
10818 views
/*1* This program is free software; you can redistribute it and/or modify2* it under the terms of the GNU General Public License, version 2, as3* published by the Free Software Foundation.4*5* This program is distributed in the hope that it will be useful,6* but WITHOUT ANY WARRANTY; without even the implied warranty of7* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the8* GNU General Public License for more details.9*10* You should have received a copy of the GNU General Public License11* along with this program; if not, write to the Free Software12* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.13*14* Copyright SUSE Linux Products GmbH 200915*16* Authors: Alexander Graf <[email protected]>17*/1819#include <asm/kvm_ppc.h>20#include <asm/disassemble.h>21#include <asm/kvm_book3s.h>22#include <asm/reg.h>2324#define OP_19_XOP_RFID 1825#define OP_19_XOP_RFI 502627#define OP_31_XOP_MFMSR 8328#define OP_31_XOP_MTMSR 14629#define OP_31_XOP_MTMSRD 17830#define OP_31_XOP_MTSR 21031#define OP_31_XOP_MTSRIN 24232#define OP_31_XOP_TLBIEL 27433#define OP_31_XOP_TLBIE 30634#define OP_31_XOP_SLBMTE 40235#define OP_31_XOP_SLBIE 43436#define OP_31_XOP_SLBIA 49837#define OP_31_XOP_MFSR 59538#define OP_31_XOP_MFSRIN 65939#define OP_31_XOP_DCBA 75840#define OP_31_XOP_SLBMFEV 85141#define OP_31_XOP_EIOIO 85442#define OP_31_XOP_SLBMFEE 9154344/* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */45#define OP_31_XOP_DCBZ 10104647#define OP_LFS 4848#define OP_LFD 5049#define OP_STFS 5250#define OP_STFD 545152#define SPRN_GQR0 91253#define SPRN_GQR1 91354#define SPRN_GQR2 91455#define SPRN_GQR3 91556#define SPRN_GQR4 91657#define SPRN_GQR5 91758#define SPRN_GQR6 91859#define SPRN_GQR7 9196061/* Book3S_32 defines mfsrin(v) - but that messes up our abstract62* function pointers, so let's just disable the define. */63#undef mfsrin6465int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,66unsigned int inst, int *advance)67{68int emulated = EMULATE_DONE;6970switch (get_op(inst)) {71case 19:72switch (get_xop(inst)) {73case OP_19_XOP_RFID:74case OP_19_XOP_RFI:75kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);76kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);77*advance = 0;78break;7980default:81emulated = EMULATE_FAIL;82break;83}84break;85case 31:86switch (get_xop(inst)) {87case OP_31_XOP_MFMSR:88kvmppc_set_gpr(vcpu, get_rt(inst),89vcpu->arch.shared->msr);90break;91case OP_31_XOP_MTMSRD:92{93ulong rs = kvmppc_get_gpr(vcpu, get_rs(inst));94if (inst & 0x10000) {95vcpu->arch.shared->msr &= ~(MSR_RI | MSR_EE);96vcpu->arch.shared->msr |= rs & (MSR_RI | MSR_EE);97} else98kvmppc_set_msr(vcpu, rs);99break;100}101case OP_31_XOP_MTMSR:102kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, get_rs(inst)));103break;104case OP_31_XOP_MFSR:105{106int srnum;107108srnum = kvmppc_get_field(inst, 12 + 32, 15 + 32);109if (vcpu->arch.mmu.mfsrin) {110u32 sr;111sr = vcpu->arch.mmu.mfsrin(vcpu, srnum);112kvmppc_set_gpr(vcpu, get_rt(inst), sr);113}114break;115}116case OP_31_XOP_MFSRIN:117{118int srnum;119120srnum = (kvmppc_get_gpr(vcpu, get_rb(inst)) >> 28) & 0xf;121if (vcpu->arch.mmu.mfsrin) {122u32 sr;123sr = vcpu->arch.mmu.mfsrin(vcpu, srnum);124kvmppc_set_gpr(vcpu, get_rt(inst), sr);125}126break;127}128case OP_31_XOP_MTSR:129vcpu->arch.mmu.mtsrin(vcpu,130(inst >> 16) & 0xf,131kvmppc_get_gpr(vcpu, get_rs(inst)));132break;133case OP_31_XOP_MTSRIN:134vcpu->arch.mmu.mtsrin(vcpu,135(kvmppc_get_gpr(vcpu, get_rb(inst)) >> 28) & 0xf,136kvmppc_get_gpr(vcpu, get_rs(inst)));137break;138case OP_31_XOP_TLBIE:139case OP_31_XOP_TLBIEL:140{141bool large = (inst & 0x00200000) ? true : false;142ulong addr = kvmppc_get_gpr(vcpu, get_rb(inst));143vcpu->arch.mmu.tlbie(vcpu, addr, large);144break;145}146case OP_31_XOP_EIOIO:147break;148case OP_31_XOP_SLBMTE:149if (!vcpu->arch.mmu.slbmte)150return EMULATE_FAIL;151152vcpu->arch.mmu.slbmte(vcpu,153kvmppc_get_gpr(vcpu, get_rs(inst)),154kvmppc_get_gpr(vcpu, get_rb(inst)));155break;156case OP_31_XOP_SLBIE:157if (!vcpu->arch.mmu.slbie)158return EMULATE_FAIL;159160vcpu->arch.mmu.slbie(vcpu,161kvmppc_get_gpr(vcpu, get_rb(inst)));162break;163case OP_31_XOP_SLBIA:164if (!vcpu->arch.mmu.slbia)165return EMULATE_FAIL;166167vcpu->arch.mmu.slbia(vcpu);168break;169case OP_31_XOP_SLBMFEE:170if (!vcpu->arch.mmu.slbmfee) {171emulated = EMULATE_FAIL;172} else {173ulong t, rb;174175rb = kvmppc_get_gpr(vcpu, get_rb(inst));176t = vcpu->arch.mmu.slbmfee(vcpu, rb);177kvmppc_set_gpr(vcpu, get_rt(inst), t);178}179break;180case OP_31_XOP_SLBMFEV:181if (!vcpu->arch.mmu.slbmfev) {182emulated = EMULATE_FAIL;183} else {184ulong t, rb;185186rb = kvmppc_get_gpr(vcpu, get_rb(inst));187t = vcpu->arch.mmu.slbmfev(vcpu, rb);188kvmppc_set_gpr(vcpu, get_rt(inst), t);189}190break;191case OP_31_XOP_DCBA:192/* Gets treated as NOP */193break;194case OP_31_XOP_DCBZ:195{196ulong rb = kvmppc_get_gpr(vcpu, get_rb(inst));197ulong ra = 0;198ulong addr, vaddr;199u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };200u32 dsisr;201int r;202203if (get_ra(inst))204ra = kvmppc_get_gpr(vcpu, get_ra(inst));205206addr = (ra + rb) & ~31ULL;207if (!(vcpu->arch.shared->msr & MSR_SF))208addr &= 0xffffffff;209vaddr = addr;210211r = kvmppc_st(vcpu, &addr, 32, zeros, true);212if ((r == -ENOENT) || (r == -EPERM)) {213*advance = 0;214vcpu->arch.shared->dar = vaddr;215to_svcpu(vcpu)->fault_dar = vaddr;216217dsisr = DSISR_ISSTORE;218if (r == -ENOENT)219dsisr |= DSISR_NOHPTE;220else if (r == -EPERM)221dsisr |= DSISR_PROTFAULT;222223vcpu->arch.shared->dsisr = dsisr;224to_svcpu(vcpu)->fault_dsisr = dsisr;225226kvmppc_book3s_queue_irqprio(vcpu,227BOOK3S_INTERRUPT_DATA_STORAGE);228}229230break;231}232default:233emulated = EMULATE_FAIL;234}235break;236default:237emulated = EMULATE_FAIL;238}239240if (emulated == EMULATE_FAIL)241emulated = kvmppc_emulate_paired_single(run, vcpu);242243return emulated;244}245246void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,247u32 val)248{249if (upper) {250/* Upper BAT */251u32 bl = (val >> 2) & 0x7ff;252bat->bepi_mask = (~bl << 17);253bat->bepi = val & 0xfffe0000;254bat->vs = (val & 2) ? 1 : 0;255bat->vp = (val & 1) ? 1 : 0;256bat->raw = (bat->raw & 0xffffffff00000000ULL) | val;257} else {258/* Lower BAT */259bat->brpn = val & 0xfffe0000;260bat->wimg = (val >> 3) & 0xf;261bat->pp = val & 3;262bat->raw = (bat->raw & 0x00000000ffffffffULL) | ((u64)val << 32);263}264}265266static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn)267{268struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);269struct kvmppc_bat *bat;270271switch (sprn) {272case SPRN_IBAT0U ... SPRN_IBAT3L:273bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];274break;275case SPRN_IBAT4U ... SPRN_IBAT7L:276bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];277break;278case SPRN_DBAT0U ... SPRN_DBAT3L:279bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];280break;281case SPRN_DBAT4U ... SPRN_DBAT7L:282bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];283break;284default:285BUG();286}287288return bat;289}290291int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)292{293int emulated = EMULATE_DONE;294ulong spr_val = kvmppc_get_gpr(vcpu, rs);295296switch (sprn) {297case SPRN_SDR1:298to_book3s(vcpu)->sdr1 = spr_val;299break;300case SPRN_DSISR:301vcpu->arch.shared->dsisr = spr_val;302break;303case SPRN_DAR:304vcpu->arch.shared->dar = spr_val;305break;306case SPRN_HIOR:307to_book3s(vcpu)->hior = spr_val;308break;309case SPRN_IBAT0U ... SPRN_IBAT3L:310case SPRN_IBAT4U ... SPRN_IBAT7L:311case SPRN_DBAT0U ... SPRN_DBAT3L:312case SPRN_DBAT4U ... SPRN_DBAT7L:313{314struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);315316kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val);317/* BAT writes happen so rarely that we're ok to flush318* everything here */319kvmppc_mmu_pte_flush(vcpu, 0, 0);320kvmppc_mmu_flush_segments(vcpu);321break;322}323case SPRN_HID0:324to_book3s(vcpu)->hid[0] = spr_val;325break;326case SPRN_HID1:327to_book3s(vcpu)->hid[1] = spr_val;328break;329case SPRN_HID2:330to_book3s(vcpu)->hid[2] = spr_val;331break;332case SPRN_HID2_GEKKO:333to_book3s(vcpu)->hid[2] = spr_val;334/* HID2.PSE controls paired single on gekko */335switch (vcpu->arch.pvr) {336case 0x00080200: /* lonestar 2.0 */337case 0x00088202: /* lonestar 2.2 */338case 0x70000100: /* gekko 1.0 */339case 0x00080100: /* gekko 2.0 */340case 0x00083203: /* gekko 2.3a */341case 0x00083213: /* gekko 2.3b */342case 0x00083204: /* gekko 2.4 */343case 0x00083214: /* gekko 2.4e (8SE) - retail HW2 */344case 0x00087200: /* broadway */345if (vcpu->arch.hflags & BOOK3S_HFLAG_NATIVE_PS) {346/* Native paired singles */347} else if (spr_val & (1 << 29)) { /* HID2.PSE */348vcpu->arch.hflags |= BOOK3S_HFLAG_PAIRED_SINGLE;349kvmppc_giveup_ext(vcpu, MSR_FP);350} else {351vcpu->arch.hflags &= ~BOOK3S_HFLAG_PAIRED_SINGLE;352}353break;354}355break;356case SPRN_HID4:357case SPRN_HID4_GEKKO:358to_book3s(vcpu)->hid[4] = spr_val;359break;360case SPRN_HID5:361to_book3s(vcpu)->hid[5] = spr_val;362/* guest HID5 set can change is_dcbz32 */363if (vcpu->arch.mmu.is_dcbz32(vcpu) &&364(mfmsr() & MSR_HV))365vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;366break;367case SPRN_GQR0:368case SPRN_GQR1:369case SPRN_GQR2:370case SPRN_GQR3:371case SPRN_GQR4:372case SPRN_GQR5:373case SPRN_GQR6:374case SPRN_GQR7:375to_book3s(vcpu)->gqr[sprn - SPRN_GQR0] = spr_val;376break;377case SPRN_ICTC:378case SPRN_THRM1:379case SPRN_THRM2:380case SPRN_THRM3:381case SPRN_CTRLF:382case SPRN_CTRLT:383case SPRN_L2CR:384case SPRN_MMCR0_GEKKO:385case SPRN_MMCR1_GEKKO:386case SPRN_PMC1_GEKKO:387case SPRN_PMC2_GEKKO:388case SPRN_PMC3_GEKKO:389case SPRN_PMC4_GEKKO:390case SPRN_WPAR_GEKKO:391break;392default:393printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);394#ifndef DEBUG_SPR395emulated = EMULATE_FAIL;396#endif397break;398}399400return emulated;401}402403int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)404{405int emulated = EMULATE_DONE;406407switch (sprn) {408case SPRN_IBAT0U ... SPRN_IBAT3L:409case SPRN_IBAT4U ... SPRN_IBAT7L:410case SPRN_DBAT0U ... SPRN_DBAT3L:411case SPRN_DBAT4U ... SPRN_DBAT7L:412{413struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);414415if (sprn % 2)416kvmppc_set_gpr(vcpu, rt, bat->raw >> 32);417else418kvmppc_set_gpr(vcpu, rt, bat->raw);419420break;421}422case SPRN_SDR1:423kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);424break;425case SPRN_DSISR:426kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dsisr);427break;428case SPRN_DAR:429kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar);430break;431case SPRN_HIOR:432kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hior);433break;434case SPRN_HID0:435kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[0]);436break;437case SPRN_HID1:438kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[1]);439break;440case SPRN_HID2:441case SPRN_HID2_GEKKO:442kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[2]);443break;444case SPRN_HID4:445case SPRN_HID4_GEKKO:446kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[4]);447break;448case SPRN_HID5:449kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[5]);450break;451case SPRN_GQR0:452case SPRN_GQR1:453case SPRN_GQR2:454case SPRN_GQR3:455case SPRN_GQR4:456case SPRN_GQR5:457case SPRN_GQR6:458case SPRN_GQR7:459kvmppc_set_gpr(vcpu, rt,460to_book3s(vcpu)->gqr[sprn - SPRN_GQR0]);461break;462case SPRN_THRM1:463case SPRN_THRM2:464case SPRN_THRM3:465case SPRN_CTRLF:466case SPRN_CTRLT:467case SPRN_L2CR:468case SPRN_MMCR0_GEKKO:469case SPRN_MMCR1_GEKKO:470case SPRN_PMC1_GEKKO:471case SPRN_PMC2_GEKKO:472case SPRN_PMC3_GEKKO:473case SPRN_PMC4_GEKKO:474case SPRN_WPAR_GEKKO:475kvmppc_set_gpr(vcpu, rt, 0);476break;477default:478printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn);479#ifndef DEBUG_SPR480emulated = EMULATE_FAIL;481#endif482break;483}484485return emulated;486}487488u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst)489{490u32 dsisr = 0;491492/*493* This is what the spec says about DSISR bits (not mentioned = 0):494*495* 12:13 [DS] Set to bits 30:31496* 15:16 [X] Set to bits 29:30497* 17 [X] Set to bit 25498* [D/DS] Set to bit 5499* 18:21 [X] Set to bits 21:24500* [D/DS] Set to bits 1:4501* 22:26 Set to bits 6:10 (RT/RS/FRT/FRS)502* 27:31 Set to bits 11:15 (RA)503*/504505switch (get_op(inst)) {506/* D-form */507case OP_LFS:508case OP_LFD:509case OP_STFD:510case OP_STFS:511dsisr |= (inst >> 12) & 0x4000; /* bit 17 */512dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */513break;514/* X-form */515case 31:516dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */517dsisr |= (inst << 8) & 0x04000; /* bit 17 */518dsisr |= (inst << 3) & 0x03c00; /* bits 18:21 */519break;520default:521printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);522break;523}524525dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */526527return dsisr;528}529530ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)531{532ulong dar = 0;533ulong ra;534535switch (get_op(inst)) {536case OP_LFS:537case OP_LFD:538case OP_STFD:539case OP_STFS:540ra = get_ra(inst);541if (ra)542dar = kvmppc_get_gpr(vcpu, ra);543dar += (s32)((s16)inst);544break;545case 31:546ra = get_ra(inst);547if (ra)548dar = kvmppc_get_gpr(vcpu, ra);549dar += kvmppc_get_gpr(vcpu, get_rb(inst));550break;551default:552printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);553break;554}555556return dar;557}558559560