From: Christian Ehrhardt <ehrhardt@xxxxxxxxxxxxxxxxxx> This adds another guest code rewrite support replacing the wrtee instructions using the magic page mechanism. This affects all checks of the MSR_EE bit of the guest as well as all writes to vcpu->arch.msr which now need to be in sync with the guest visible EE bit (mfmsr needs to fetch the right value of the EE bit). Therefor the paravirtualization of mfmsr and wrtee using the magic page mechanism is mutually exclusive since we would miss updates or would need multi instruction rewrites with both rewritten. Signed-off-by: Christian Ehrhardt <ehrhardt@xxxxxxxxxxxxxxxxxx> --- [diffstat] arch/powerpc/kvm/booke_guest.c | 18 +++++++++++------- arch/powerpc/kvm/emulate.c | 20 +++++++++++++++++--- arch/powerpc/kvm/powerpc.c | 1 + include/asm-powerpc/kvm_para.h | 1 + include/asm-powerpc/kvm_ppc.h | 5 +++++ 5 files changed, 35 insertions(+), 10 deletions(-) [diff] diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c --- a/arch/powerpc/kvm/booke_guest.c +++ b/arch/powerpc/kvm/booke_guest.c @@ -181,13 +181,13 @@ r = vcpu->arch.msr & MSR_ME; break; case BOOKE_INTERRUPT_EXTERNAL: - r = vcpu->arch.msr & MSR_EE; - break; case BOOKE_INTERRUPT_DECREMENTER: - r = vcpu->arch.msr & MSR_EE; - break; case BOOKE_INTERRUPT_FIT: - r = vcpu->arch.msr & MSR_EE; + if (vcpu->arch.pvmem) + r = kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT) + & MSR_EE; + else + r = vcpu->arch.msr & MSR_EE; break; case BOOKE_INTERRUPT_WATCHDOG: r = vcpu->arch.msr & MSR_CE; @@ -212,7 +212,9 @@ if (vcpu->arch.pvmem) { kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_SRR0, vcpu->arch.pc); - kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_SRR1, vcpu->arch.msr); + kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_SRR1, + (vcpu->arch.msr & ~MSR_EE) + | kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT)); /* only modified on interrupt delivery path */ kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_DEAR, vcpu->arch.dear); kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_ESR, vcpu->arch.esr); @@ -562,6 +564,8 @@ regs->sprg3 = kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_SPRG3); regs->srr0 = kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_SRR0); regs->srr1 = kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_SRR1); + regs->msr = (vcpu->arch.msr & ~MSR_EE) + | kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT); } return 0; @@ -576,7 +580,7 @@ vcpu->arch.ctr = regs->ctr; vcpu->arch.lr = regs->lr; vcpu->arch.xer = regs->xer; - vcpu->arch.msr = regs->msr; + kvmppc_set_msr(vcpu, regs->msr); vcpu->arch.srr0 = regs->srr0; vcpu->arch.srr1 = regs->srr1; vcpu->arch.sprg0 = regs->sprg0; diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -279,6 +279,8 @@ vcpu->arch.dear); kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_ESR, vcpu->arch.esr); + kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT, + vcpu->arch.msr & MSR_EE); break; default: printk(KERN_ERR "unknown hypercall %d\n", vcpu->arch.gpr[0]); @@ -304,6 +306,10 @@ switch (get_op(inst)) { case 31: switch (get_xop(inst)) { + case 131: /* wrtee */ + rw = KVM_PPCPV_PVMEM_WRITE; + offset = KVM_PPCPV_OFFSET_EEBIT; + break; case 339: /* mfspr */ sprn = get_sprn(inst); rw = KVM_PPCPV_PVMEM_READ; @@ -496,7 +502,11 @@ case 83: /* mfmsr */ rt = get_rt(inst); - vcpu->arch.gpr[rt] = vcpu->arch.msr; + if (vcpu->arch.pvmem) + vcpu->arch.gpr[rt] = (vcpu->arch.msr & ~MSR_EE) + | kvmppc_get_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT); + else + vcpu->arch.gpr[rt] = vcpu->arch.msr; break; case 87: /* lbzx */ @@ -523,8 +533,12 @@ break; case 163: /* wrteei */ - vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) - | (inst & MSR_EE); + if (vcpu->arch.pvmem) + kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT, + (inst & MSR_EE)); + else + vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) + | (inst & MSR_EE); break; case 215: /* stbx */ diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -459,6 +459,7 @@ kvmppc_check_and_deliver_interrupts(vcpu); local_irq_disable(); + kvm_guest_enter(); r = __kvmppc_vcpu_run(run, vcpu); kvm_guest_exit(); diff --git a/include/asm-powerpc/kvm_para.h b/include/asm-powerpc/kvm_para.h --- a/include/asm-powerpc/kvm_para.h +++ b/include/asm-powerpc/kvm_para.h @@ -48,6 +48,7 @@ #define KVM_PPCPV_OFFSET_SRR1 0x14 #define KVM_PPCPV_OFFSET_DEAR 0x18 #define KVM_PPCPV_OFFSET_ESR 0x1C +#define KVM_PPCPV_OFFSET_EEBIT 0x20 static inline int kvm_para_available(void) { diff --git a/include/asm-powerpc/kvm_ppc.h b/include/asm-powerpc/kvm_ppc.h --- a/include/asm-powerpc/kvm_ppc.h +++ b/include/asm-powerpc/kvm_ppc.h @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/kvm_types.h> #include <linux/kvm_host.h> +#include <asm/kvm_para.h> struct kvm_tlb { struct tlbe guest_tlb[PPC44x_TLB_SIZE]; @@ -87,6 +88,10 @@ if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR)) kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR); + if (vcpu->arch.pvmem) + kvmppc_set_pvreg(vcpu, KVM_PPCPV_OFFSET_EEBIT, + (new_msr & MSR_EE)); + vcpu->arch.msr = new_msr; if (vcpu->arch.msr & MSR_WE) -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html