Since sse instructions can issue 16-byte mmios, we need to support them.  We
can't increase the kvm_run mmio buffer size to 16 bytes without breaking
compatibility, so instead we break the large mmios into two smaller 8-byte
ones.  Since the bus is 64-bit we aren't breaking any atomicity guarantees.

Signed-off-by: Avi Kivity <[email protected]>
---
 arch/x86/include/asm/kvm_host.h |    1 +
 arch/x86/kvm/x86.c              |   34 +++++++++++++++++++++++++---------
 include/linux/kvm_host.h        |    7 ++++++-
 3 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 35f81b1..e820c63 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -30,6 +30,7 @@
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_MMIO_SIZE 16
 
 #define KVM_PIO_PAGE_OFFSET 1
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2eb1124..01aafc8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3833,8 +3833,10 @@ mmio:
        vcpu->mmio_needed = 1;
        vcpu->run->exit_reason = KVM_EXIT_MMIO;
        vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
-       vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+       vcpu->mmio_size = bytes;
+       vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
        vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
+       vcpu->mmio_index = 0;
 
        return X86EMUL_IO_NEEDED;
 }
@@ -3886,11 +3888,14 @@ mmio:
        val += handled;
 
        vcpu->mmio_needed = 1;
+       memcpy(vcpu->mmio_data, val, bytes);
        vcpu->run->exit_reason = KVM_EXIT_MMIO;
        vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
-       vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+       vcpu->mmio_size = bytes;
+       vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
        vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
-       memcpy(vcpu->run->mmio.data, val, bytes);
+       memcpy(vcpu->run->mmio.data, vcpu->mmio_data, 8);
+       vcpu->mmio_index = 0;
 
        return X86EMUL_CONTINUE;
 }
@@ -4498,11 +4503,9 @@ restart:
                if (!vcpu->arch.pio.in)
                        vcpu->arch.pio.count = 0;
                r = EMULATE_DO_MMIO;
-       } else if (vcpu->mmio_needed) {
-               if (vcpu->mmio_is_write)
-                       vcpu->mmio_needed = 0;
+       } else if (vcpu->mmio_needed)
                r = EMULATE_DO_MMIO;
-       } else if (r == EMULATION_RESTART)
+       else if (r == EMULATION_RESTART)
                goto restart;
        else
                r = EMULATE_DONE;
@@ -5424,9 +5427,22 @@ static int complete_mmio(struct kvm_vcpu *vcpu)
                return 1;
 
        if (vcpu->mmio_needed) {
-               memcpy(vcpu->mmio_data, run->mmio.data, 8);
-               vcpu->mmio_read_completed = 1;
                vcpu->mmio_needed = 0;
+               if (!vcpu->mmio_is_write)
+                       memcpy(vcpu->mmio_data, run->mmio.data, 8);
+               vcpu->mmio_index += 8;
+               if (vcpu->mmio_index < vcpu->mmio_size) {
+                       run->exit_reason = KVM_EXIT_MMIO;
+                       run->mmio.phys_addr = vcpu->mmio_phys_addr + 
vcpu->mmio_index;
+                       memcpy(run->mmio.data, vcpu->mmio_data + 
vcpu->mmio_index, 8);
+                       run->mmio.len = min(vcpu->mmio_size - vcpu->mmio_index, 
8);
+                       run->mmio.is_write = vcpu->mmio_is_write;
+                       vcpu->mmio_needed = 1;
+                       return 0;
+               }
+               if (vcpu->mmio_is_write)
+                       return 1;
+               vcpu->mmio_read_completed = 1;
        }
        vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
        r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 57d7092..1934f48 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -27,6 +27,10 @@
 
 #include <asm/kvm_host.h>
 
+#ifndef KVM_MMIO_SIZE
+#define KVM_MMIO_SIZE 8
+#endif
+
 /*
  * vcpu->requests bit members
  */
@@ -133,7 +137,8 @@ struct kvm_vcpu {
        int mmio_read_completed;
        int mmio_is_write;
        int mmio_size;
-       unsigned char mmio_data[8];
+       int mmio_index;
+       unsigned char mmio_data[KVM_MMIO_SIZE];
        gpa_t mmio_phys_addr;
 #endif
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to