|
@@ -3596,20 +3596,43 @@ static void kvm_init_msr_list(void)
|
|
|
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
|
|
|
const void *v)
|
|
|
{
|
|
|
- if (vcpu->arch.apic &&
|
|
|
- !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
|
|
|
- return 0;
|
|
|
+ int handled = 0;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ do {
|
|
|
+ n = min(len, 8);
|
|
|
+ if (!(vcpu->arch.apic &&
|
|
|
+ !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, n, v))
|
|
|
+ && kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
|
|
|
+ break;
|
|
|
+ handled += n;
|
|
|
+ addr += n;
|
|
|
+ len -= n;
|
|
|
+ v += n;
|
|
|
+ } while (len);
|
|
|
|
|
|
- return kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
|
|
|
+ return handled;
|
|
|
}
|
|
|
|
|
|
static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
|
|
|
{
|
|
|
- if (vcpu->arch.apic &&
|
|
|
- !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
|
|
|
- return 0;
|
|
|
+ int handled = 0;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ do {
|
|
|
+ n = min(len, 8);
|
|
|
+ if (!(vcpu->arch.apic &&
|
|
|
+ !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, n, v))
|
|
|
+ && kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
|
|
|
+ break;
|
|
|
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
|
|
|
+ handled += n;
|
|
|
+ addr += n;
|
|
|
+ len -= n;
|
|
|
+ v += n;
|
|
|
+ } while (len);
|
|
|
|
|
|
- return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
|
|
|
+ return handled;
|
|
|
}
|
|
|
|
|
|
static void kvm_set_segment(struct kvm_vcpu *vcpu,
|
|
@@ -3769,6 +3792,7 @@ static int emulator_read_emulated(unsigned long addr,
|
|
|
struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
gpa_t gpa;
|
|
|
+ int handled;
|
|
|
|
|
|
if (vcpu->mmio_read_completed) {
|
|
|
memcpy(val, vcpu->mmio_data, bytes);
|
|
@@ -3795,10 +3819,14 @@ mmio:
|
|
|
/*
|
|
|
* Is this MMIO handled locally?
|
|
|
*/
|
|
|
- if (!vcpu_mmio_read(vcpu, gpa, bytes, val)) {
|
|
|
- trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, gpa, *(u64 *)val);
|
|
|
+ handled = vcpu_mmio_read(vcpu, gpa, bytes, val);
|
|
|
+
|
|
|
+ if (handled == bytes)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
- }
|
|
|
+
|
|
|
+ gpa += handled;
|
|
|
+ bytes -= handled;
|
|
|
+ val += handled;
|
|
|
|
|
|
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
|
|
|
|
|
@@ -3830,6 +3858,7 @@ static int emulator_write_emulated_onepage(unsigned long addr,
|
|
|
struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
gpa_t gpa;
|
|
|
+ int handled;
|
|
|
|
|
|
gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, exception);
|
|
|
|
|
@@ -3848,9 +3877,14 @@ mmio:
|
|
|
/*
|
|
|
* Is this MMIO handled locally?
|
|
|
*/
|
|
|
- if (!vcpu_mmio_write(vcpu, gpa, bytes, val))
|
|
|
+ handled = vcpu_mmio_write(vcpu, gpa, bytes, val);
|
|
|
+ if (handled == bytes)
|
|
|
return X86EMUL_CONTINUE;
|
|
|
|
|
|
+ gpa += handled;
|
|
|
+ bytes -= handled;
|
|
|
+ val += handled;
|
|
|
+
|
|
|
vcpu->mmio_needed = 1;
|
|
|
vcpu->run->exit_reason = KVM_EXIT_MMIO;
|
|
|
vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
|