KVM: extend in-kernel mmio to handle >8 byte transactions
authorAvi Kivity <avi@redhat.com>
Tue, 19 Jan 2010 10:51:22 +0000 (12:51 +0200)
committerAvi Kivity <avi@redhat.com>
Wed, 11 May 2011 11:56:58 +0000 (07:56 -0400)
Needed for coalesced mmio using sse.

Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/x86.c

index 692c70d6fd02390cbdcfe6ae9f891170603c1f18..3b234c18b63549ca4212afe325ca6665bb681f9a 100644 (file)
@@ -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;