KVM: PPC: Fix emulated MMIO sign-extension

When the guest does a sign-extending load instruction (such as lha
or lwa) to an emulated MMIO location, it results in a call to
kvmppc_handle_loads() in the host.  That function sets the
vcpu->arch.mmio_sign_extend flag and calls kvmppc_handle_load()
to do the rest of the work.  However, kvmppc_handle_load() sets
the mmio_sign_extend flag to 0 unconditionally, so the sign
extension never gets done.

To fix this, we rename kvmppc_handle_load to __kvmppc_handle_load
and add an explicit parameter to indicate whether sign extension
is required.  kvmppc_handle_load() and kvmppc_handle_loads() then
become 1-line functions that just call __kvmppc_handle_load()
with the extra parameter.

Reported-by: Bin Lu <lblulb@linux.vnet.ibm.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Paul Mackerras 2016-05-05 16:17:10 +10:00 committed by Paul Mackerras
parent ade3ac660a
commit eb8b056016

View File

@ -800,9 +800,9 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
} }
} }
int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, static int __kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int rt, unsigned int bytes, unsigned int rt, unsigned int bytes,
int is_default_endian) int is_default_endian, int sign_extend)
{ {
int idx, ret; int idx, ret;
bool host_swabbed; bool host_swabbed;
@ -827,7 +827,7 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
vcpu->arch.mmio_host_swabbed = host_swabbed; vcpu->arch.mmio_host_swabbed = host_swabbed;
vcpu->mmio_needed = 1; vcpu->mmio_needed = 1;
vcpu->mmio_is_write = 0; vcpu->mmio_is_write = 0;
vcpu->arch.mmio_sign_extend = 0; vcpu->arch.mmio_sign_extend = sign_extend;
idx = srcu_read_lock(&vcpu->kvm->srcu); idx = srcu_read_lock(&vcpu->kvm->srcu);
@ -844,6 +844,13 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int rt, unsigned int bytes,
int is_default_endian)
{
return __kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian, 0);
}
EXPORT_SYMBOL_GPL(kvmppc_handle_load); EXPORT_SYMBOL_GPL(kvmppc_handle_load);
/* Same as above, but sign extends */ /* Same as above, but sign extends */
@ -851,12 +858,7 @@ int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int rt, unsigned int bytes, unsigned int rt, unsigned int bytes,
int is_default_endian) int is_default_endian)
{ {
int r; return __kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian, 1);
vcpu->arch.mmio_sign_extend = 1;
r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian);
return r;
} }
int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,