diff options
author | Cédric Le Goater <clg@fr.ibm.com> | 2014-01-09 05:51:16 -0500 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2014-01-27 10:00:39 -0500 |
commit | 736017752d2f6ed0d64f5e15cf48e79779b11c85 (patch) | |
tree | f8f11f7b4daf14e76e8e3d716c85f5a56a949476 /arch/powerpc/kvm/powerpc.c | |
parent | 7a8ff56be68239bd36a2b639cb40bfbcfc58dad3 (diff) |
KVM: PPC: Book3S: MMIO emulation support for little endian guests
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.
Finally, kvmppc_handle_load() of kvmppc_handle_store() are modified
to reverse the endianness of the MMIO if required.
Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
[agraf: add booke handling]
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm/powerpc.c')
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 7ca9e0a80499..026dfaaa4772 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_vcpu *vcpu, | |||
673 | } | 673 | } |
674 | 674 | ||
675 | int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | 675 | int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, |
676 | unsigned int rt, unsigned int bytes, int is_bigendian) | 676 | unsigned int rt, unsigned int bytes, |
677 | int is_default_endian) | ||
677 | { | 678 | { |
678 | int idx, ret; | 679 | int idx, ret; |
680 | int is_bigendian; | ||
681 | |||
682 | if (kvmppc_need_byteswap(vcpu)) { | ||
683 | /* Default endianness is "little endian". */ | ||
684 | is_bigendian = !is_default_endian; | ||
685 | } else { | ||
686 | /* Default endianness is "big endian". */ | ||
687 | is_bigendian = is_default_endian; | ||
688 | } | ||
679 | 689 | ||
680 | if (bytes > sizeof(run->mmio.data)) { | 690 | if (bytes > sizeof(run->mmio.data)) { |
681 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, | 691 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, |
@@ -711,21 +721,31 @@ EXPORT_SYMBOL_GPL(kvmppc_handle_load); | |||
711 | 721 | ||
712 | /* Same as above, but sign extends */ | 722 | /* Same as above, but sign extends */ |
713 | int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, | 723 | int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, |
714 | unsigned int rt, unsigned int bytes, int is_bigendian) | 724 | unsigned int rt, unsigned int bytes, |
725 | int is_default_endian) | ||
715 | { | 726 | { |
716 | int r; | 727 | int r; |
717 | 728 | ||
718 | vcpu->arch.mmio_sign_extend = 1; | 729 | vcpu->arch.mmio_sign_extend = 1; |
719 | r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); | 730 | r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian); |
720 | 731 | ||
721 | return r; | 732 | return r; |
722 | } | 733 | } |
723 | 734 | ||
724 | int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | 735 | int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, |
725 | u64 val, unsigned int bytes, int is_bigendian) | 736 | u64 val, unsigned int bytes, int is_default_endian) |
726 | { | 737 | { |
727 | void *data = run->mmio.data; | 738 | void *data = run->mmio.data; |
728 | int idx, ret; | 739 | int idx, ret; |
740 | int is_bigendian; | ||
741 | |||
742 | if (kvmppc_need_byteswap(vcpu)) { | ||
743 | /* Default endianness is "little endian". */ | ||
744 | is_bigendian = !is_default_endian; | ||
745 | } else { | ||
746 | /* Default endianness is "big endian". */ | ||
747 | is_bigendian = is_default_endian; | ||
748 | } | ||
729 | 749 | ||
730 | if (bytes > sizeof(run->mmio.data)) { | 750 | if (bytes > sizeof(run->mmio.data)) { |
731 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, | 751 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, |