aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-12-02 21:30:39 -0500
committerAlexander Graf <agraf@suse.de>2014-12-17 07:50:39 -0500
commit4a157d61b48c7cdb8d751001442a14ebac80229f (patch)
treed9ad6c9e1809c8965a5af16c86b50707ad7decaa
parentc17b98cf6028704e1f953d6a25ed6140425ccfd0 (diff)
KVM: PPC: Book3S HV: Fix endianness of instruction obtained from HEIR register
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>
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/kernel/asm-offsets.c1
-rw-r--r--arch/powerpc/kvm/book3s_hv.c4
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S4
4 files changed, 9 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 5686a429d4b7..65441875b025 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -651,6 +651,8 @@ struct kvm_vcpu_arch {
651 spinlock_t tbacct_lock; 651 spinlock_t tbacct_lock;
652 u64 busy_stolen; 652 u64 busy_stolen;
653 u64 busy_preempt; 653 u64 busy_preempt;
654
655 u32 emul_inst;
654#endif 656#endif
655}; 657};
656 658
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 815212e9d7ba..b14716bbb7b5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -498,6 +498,7 @@ int main(void)
498 DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); 498 DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
499 DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr)); 499 DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
500 DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty)); 500 DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
501 DEFINE(VCPU_HEIR, offsetof(struct kvm_vcpu, arch.emul_inst));
501#endif 502#endif
502#ifdef CONFIG_PPC_BOOK3S 503#ifdef CONFIG_PPC_BOOK3S
503 DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); 504 DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 1ee4e9e786cc..299351e77eb9 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -831,6 +831,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
831 * Accordingly return to Guest or Host. 831 * Accordingly return to Guest or Host.
832 */ 832 */
833 case BOOK3S_INTERRUPT_H_EMUL_ASSIST: 833 case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
834 if (vcpu->arch.emul_inst != KVM_INST_FETCH_FAILED)
835 vcpu->arch.last_inst = kvmppc_need_byteswap(vcpu) ?
836 swab32(vcpu->arch.emul_inst) :
837 vcpu->arch.emul_inst;
834 if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { 838 if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
835 r = kvmppc_emulate_debug_inst(run, vcpu); 839 r = kvmppc_emulate_debug_inst(run, vcpu);
836 } else { 840 } else {
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index c0f9e68c5db2..26a5b8d4dd3c 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -983,13 +983,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
983 983
984 stw r12,VCPU_TRAP(r9) 984 stw r12,VCPU_TRAP(r9)
985 985
986 /* Save HEIR (HV emulation assist reg) in last_inst 986 /* Save HEIR (HV emulation assist reg) in emul_inst
987 if this is an HEI (HV emulation interrupt, e40) */ 987 if this is an HEI (HV emulation interrupt, e40) */
988 li r3,KVM_INST_FETCH_FAILED 988 li r3,KVM_INST_FETCH_FAILED
989 cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST 989 cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
990 bne 11f 990 bne 11f
991 mfspr r3,SPRN_HEIR 991 mfspr r3,SPRN_HEIR
99211: stw r3,VCPU_LAST_INST(r9) 99211: stw r3,VCPU_HEIR(r9)
993 993
994 /* these are volatile across C function calls */ 994 /* these are volatile across C function calls */
995 mfctr r3 995 mfctr r3