]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: Correctly handle writes crossing a page boundary
authorAvi Kivity <avi@qumranet.com>
Sun, 22 Jul 2007 15:48:54 +0000 (18:48 +0300)
committerAvi Kivity <avi@qumranet.com>
Mon, 23 Jul 2007 08:03:47 +0000 (11:03 +0300)
Writes that are contiguous in virtual memory may not be contiguous in
physical memory; so split writes that straddle a page boundary.

Thanks to Aurelien for reporting the bug, patient testing, and a fix
to this very patch.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
drivers/kvm/kvm_main.c

index 67654c3680caf4e666b466a89f73dd89e5695027..e7c9ca75eb0a216e6d5c3cacee790116f86c5cd9 100644 (file)
@@ -1092,10 +1092,10 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
        return 1;
 }
 
-static int emulator_write_emulated(unsigned long addr,
-                                  const void *val,
-                                  unsigned int bytes,
-                                  struct x86_emulate_ctxt *ctxt)
+static int emulator_write_emulated_onepage(unsigned long addr,
+                                          const void *val,
+                                          unsigned int bytes,
+                                          struct x86_emulate_ctxt *ctxt)
 {
        struct kvm_vcpu      *vcpu = ctxt->vcpu;
        struct kvm_io_device *mmio_dev;
@@ -1127,6 +1127,26 @@ static int emulator_write_emulated(unsigned long addr,
        return X86EMUL_CONTINUE;
 }
 
+static int emulator_write_emulated(unsigned long addr,
+                                  const void *val,
+                                  unsigned int bytes,
+                                  struct x86_emulate_ctxt *ctxt)
+{
+       /* Crossing a page boundary? */
+       if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
+               int rc, now;
+
+               now = -addr & ~PAGE_MASK;
+               rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+               addr += now;
+               val += now;
+               bytes -= now;
+       }
+       return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+}
+
 static int emulator_cmpxchg_emulated(unsigned long addr,
                                     const void *old,
                                     const void *new,