aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity2007-07-22 18:48:54 +0300
committerAvi Kivity2007-07-25 14:29:17 +0300
commitb0fcd903e6f3f47189baddf3fe085bdf78c9644c (patch)
treec3c0e098b25d158973a7262865e74ae790a66772
parent0de085bb474f64e4fdb2f1ff3268590792648c7b (diff)
KVM: Correctly handle writes crossing a page boundary
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>
-rw-r--r--drivers/kvm/kvm_main.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index bcbe6835beb4..a0a3fddba815 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -1078,10 +1078,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;
@@ -1113,6 +1113,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,