From mboxrd@z Thu Jan 1 00:00:00 1970 From: Alexander Graf Subject: [PULL 17/36] KVM: PPC: Book3S: MMIO emulation support for little endian guests Date: Wed, 29 Jan 2014 17:12:56 +0100 Message-ID: <1391011995-4891-18-git-send-email-agraf@suse.de> References: <1391011995-4891-1-git-send-email-agraf@suse.de> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm-ppc@vger.kernel.org, gleb@redhat.com, Paolo Bonzini , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= To: kvm@vger.kernel.org Return-path: Received: from cantor2.suse.de ([195.135.220.15]:54447 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752540AbaA2QNZ (ORCPT ); Wed, 29 Jan 2014 11:13:25 -0500 In-Reply-To: <1391011995-4891-1-git-send-email-agraf@suse.de> Sender: kvm-owner@vger.kernel.org List-ID: =46rom: C=C3=A9dric Le Goater MMIO emulation reads the last instruction executed by the guest and then emulates. If the guest is running in Little Endian order, or more generally in a different endian order of the host, the instruction needs to be byte-swapped before being emulated. This patch adds a helper routine which tests the endian order of the host and the guest in order to decide whether a byteswap is needed or not. It is then used to byteswap the last instruction of the guest in the endian order of the host before MMIO emulation is performed. =46inally, kvmppc_handle_load() of kvmppc_handle_store() are modified to reverse the endianness of the MMIO if required. Signed-off-by: C=C3=A9dric Le Goater [agraf: add booke handling] Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_book3s.h | 8 +++++++- arch/powerpc/include/asm/kvm_booke.h | 6 ++++++ arch/powerpc/include/asm/kvm_ppc.h | 7 ++++--- arch/powerpc/kvm/book3s_64_mmu_hv.c | 2 +- arch/powerpc/kvm/emulate.c | 1 - arch/powerpc/kvm/powerpc.c | 28 ++++++++++++++++++++++++---= - 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/inclu= de/asm/kvm_book3s.h index f8b2320..1e9c26f 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -264,6 +264,11 @@ static inline ulong kvmppc_get_pc(struct kvm_vcpu = *vcpu) return vcpu->arch.pc; } =20 +static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu) +{ + return (vcpu->arch.shared->msr & MSR_LE) !=3D (MSR_KERNEL & MSR_LE); +} + static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu,= ulong pc) { /* Load the instruction manually if it failed to do so in the @@ -271,7 +276,8 @@ static inline u32 kvmppc_get_last_inst_internal(str= uct kvm_vcpu *vcpu, ulong pc) if (vcpu->arch.last_inst =3D=3D KVM_INST_FETCH_FAILED) kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false); =20 - return vcpu->arch.last_inst; + return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) : + vcpu->arch.last_inst; } =20 static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/includ= e/asm/kvm_booke.h index dd8f615..80d46b5 100644 --- a/arch/powerpc/include/asm/kvm_booke.h +++ b/arch/powerpc/include/asm/kvm_booke.h @@ -63,6 +63,12 @@ static inline u32 kvmppc_get_xer(struct kvm_vcpu *vc= pu) return vcpu->arch.xer; } =20 +static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu) +{ + /* XXX Would need to check TLB entry */ + return false; +} + static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) { return vcpu->arch.last_inst; diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/= asm/kvm_ppc.h index c8317fb..629277d 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -54,12 +54,13 @@ extern void kvmppc_handler_highmem(void); extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vc= pu, unsigned int rt, unsigned int bytes, - int is_bigendian); + int is_default_endian); extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *v= cpu, unsigned int rt, unsigned int bytes, - int is_bigendian); + int is_default_endian); extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *v= cpu, - u64 val, unsigned int bytes, int is_big= endian); + u64 val, unsigned int bytes, + int is_default_endian); =20 extern int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/boo= k3s_64_mmu_hv.c index f3ff587..efb8aa5 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -558,7 +558,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *r= un, struct kvm_vcpu *vcpu, * we just return and retry the instruction. */ =20 - if (instruction_is_store(vcpu->arch.last_inst) !=3D !!is_store) + if (instruction_is_store(kvmppc_get_last_inst(vcpu)) !=3D !!is_store) return RESUME_GUEST; =20 /* diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index 2f9a087..c2b887b 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -219,7 +219,6 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vc= pu, int sprn, int rt) * lmw * stmw * - * XXX is_bigendian should depend on MMU mapping or MSR[LE] */ /* XXX Should probably auto-generate instruction decoding for a partic= ular core * from opcode tables in the future. */ diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 7ca9e0a..026dfaa 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -673,9 +673,19 @@ static void kvmppc_complete_mmio_load(struct kvm_v= cpu *vcpu, } =20 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_big= endian) + unsigned int rt, unsigned int bytes, + int is_default_endian) { int idx, ret; + int is_bigendian; + + if (kvmppc_need_byteswap(vcpu)) { + /* Default endianness is "little endian". */ + is_bigendian =3D !is_default_endian; + } else { + /* Default endianness is "big endian". */ + is_bigendian =3D is_default_endian; + } =20 if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -711,21 +721,31 @@ EXPORT_SYMBOL_GPL(kvmppc_handle_load); =20 /* Same as above, but sign extends */ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned int rt, unsigned int bytes, int is_bi= gendian) + unsigned int rt, unsigned int bytes, + int is_default_endian) { int r; =20 vcpu->arch.mmio_sign_extend =3D 1; - r =3D kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); + r =3D kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian); =20 return r; } =20 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, - u64 val, unsigned int bytes, int is_bigendian) + u64 val, unsigned int bytes, int is_default_endian) { void *data =3D run->mmio.data; int idx, ret; + int is_bigendian; + + if (kvmppc_need_byteswap(vcpu)) { + /* Default endianness is "little endian". */ + is_bigendian =3D !is_default_endian; + } else { + /* Default endianness is "big endian". */ + is_bigendian =3D is_default_endian; + } =20 if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, --=20 1.8.1.4