Commit 83091db9 authored by Christoffer Dall's avatar Christoffer Dall

KVM: arm/arm64: Fix MMIO emulation data handling

When the kernel was handling a guest MMIO read access internally, we
need to copy the emulation result into the run->mmio structure in order
for the kvm_handle_mmio_return() function to pick it up and inject the
	result back into the guest.

Currently the only user of kvm_io_bus for ARM is the VGIC, which did
this copying itself, so this was not causing issues so far.

But with the upcoming new vgic implementation we need this done
properly.

Update the kvm_handle_mmio_return description and cleanup the code to
only perform a single copying when needed.

Code and commit message inspired by Andre Przywara.
Reported-by: default avatarAndre Przywara <andre.przywara@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
Reviewed-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Reviewed-by: default avatarAndre Przywara <andre.przywara@arm.com>
parent 2db4c104
...@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len) ...@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
/** /**
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
* or in-kernel IO emulation
*
* @vcpu: The VCPU pointer * @vcpu: The VCPU pointer
* @run: The VCPU run struct containing the mmio data * @run: The VCPU run struct containing the mmio data
*
* This should only be called after returning from userspace for MMIO load
* emulation.
*/ */
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
...@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, ...@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
run->mmio.is_write = is_write; run->mmio.is_write = is_write;
run->mmio.phys_addr = fault_ipa; run->mmio.phys_addr = fault_ipa;
run->mmio.len = len; run->mmio.len = len;
if (is_write)
memcpy(run->mmio.data, data_buf, len);
if (!ret) { if (!ret) {
/* We handled the access successfully in the kernel. */ /* We handled the access successfully in the kernel. */
if (!is_write)
memcpy(run->mmio.data, data_buf, len);
vcpu->stat.mmio_exit_kernel++; vcpu->stat.mmio_exit_kernel++;
kvm_handle_mmio_return(vcpu, run); kvm_handle_mmio_return(vcpu, run);
return 1; return 1;
} else {
vcpu->stat.mmio_exit_user++;
} }
if (is_write)
memcpy(run->mmio.data, data_buf, len);
vcpu->stat.mmio_exit_user++;
run->exit_reason = KVM_EXIT_MMIO; run->exit_reason = KVM_EXIT_MMIO;
return 0; return 0;
} }
...@@ -819,7 +819,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, ...@@ -819,7 +819,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct vgic_io_device *iodev = container_of(this, struct vgic_io_device *iodev = container_of(this,
struct vgic_io_device, dev); struct vgic_io_device, dev);
struct kvm_run *run = vcpu->run;
const struct vgic_io_range *range; const struct vgic_io_range *range;
struct kvm_exit_mmio mmio; struct kvm_exit_mmio mmio;
bool updated_state; bool updated_state;
...@@ -848,12 +847,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, ...@@ -848,12 +847,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
updated_state = false; updated_state = false;
} }
spin_unlock(&dist->lock); spin_unlock(&dist->lock);
run->mmio.is_write = is_write;
run->mmio.len = len;
run->mmio.phys_addr = addr;
memcpy(run->mmio.data, val, len);
kvm_handle_mmio_return(vcpu, run);
if (updated_state) if (updated_state)
vgic_kick_vcpus(vcpu->kvm); vgic_kick_vcpus(vcpu->kvm);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment