KVM: PPC: Book3S HV: Fix endianness of instruction obtained from HEIR register
authorPaul Mackerras <paulus@samba.org>
Wed, 3 Dec 2014 02:30:39 +0000 (13:30 +1100)
committerAlexander Graf <agraf@suse.de>
Wed, 17 Dec 2014 12:50:39 +0000 (13:50 +0100)
There are two ways in which a guest instruction can be obtained from
the guest in the guest exit code in book3s_hv_rmhandlers.S.  If the
exit was caused by a Hypervisor Emulation interrupt (i.e. an illegal
instruction), the offending instruction is in the HEIR register
(Hypervisor Emulation Instruction Register).  If the exit was caused
by a load or store to an emulated MMIO device, we load the instruction
from the guest by turning data relocation on and loading the instruction
with an lwz instruction.

Unfortunately, in the case where the guest has opposite endianness to
the host, these two methods give results of different endianness, but
both get put into vcpu->arch.last_inst.  The HEIR value has been loaded
using guest endianness, whereas the lwz will load the instruction using
host endianness.  The rest of the code that uses vcpu->arch.last_inst
assumes it was loaded using host endianness.

To fix this, we define a new vcpu field to store the HEIR value.  Then,
in kvmppc_handle_exit_hv(), we transfer the value from this new field to
vcpu->arch.last_inst, doing a byte-swap if the guest and host endianness
differ.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 5686a429d4b7ffc688dcb371ddff0caf4bd44c98..65441875b025247c90a0fe101d9461e83d493ba6 100644 (file)
@@ -651,6 +651,8 @@ struct kvm_vcpu_arch {
        spinlock_t tbacct_lock;
        u64 busy_stolen;
        u64 busy_preempt;
+
+       u32 emul_inst;
 #endif
 };
 
index 815212e9d7ba653444a2395681f26d9cc4ef61aa..b14716bbb7b517eba9c44a6ab36c36046f862888 100644 (file)
@@ -498,6 +498,7 @@ int main(void)
        DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
        DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
        DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
+       DEFINE(VCPU_HEIR, offsetof(struct kvm_vcpu, arch.emul_inst));
 #endif
 #ifdef CONFIG_PPC_BOOK3S
        DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
index 1ee4e9e786ccca32d19f8f5b8a2413f31ffe2718..299351e77eb98cd5922284672a3aaa6299163071 100644 (file)
@@ -831,6 +831,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
         * Accordingly return to Guest or Host.
         */
        case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
+               if (vcpu->arch.emul_inst != KVM_INST_FETCH_FAILED)
+                       vcpu->arch.last_inst = kvmppc_need_byteswap(vcpu) ?
+                               swab32(vcpu->arch.emul_inst) :
+                               vcpu->arch.emul_inst;
                if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
                        r = kvmppc_emulate_debug_inst(run, vcpu);
                } else {
index c0f9e68c5db2054d9292a7a81aa6b287abb38fe1..26a5b8d4dd3c14bdbacabd68985b94858916be06 100644 (file)
@@ -983,13 +983,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 
        stw     r12,VCPU_TRAP(r9)
 
-       /* Save HEIR (HV emulation assist reg) in last_inst
+       /* Save HEIR (HV emulation assist reg) in emul_inst
           if this is an HEI (HV emulation interrupt, e40) */
        li      r3,KVM_INST_FETCH_FAILED
        cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
        bne     11f
        mfspr   r3,SPRN_HEIR
-11:    stw     r3,VCPU_LAST_INST(r9)
+11:    stw     r3,VCPU_HEIR(r9)
 
        /* these are volatile across C function calls */
        mfctr   r3