diff options
author | Avi Kivity <avi@qumranet.com> | 2007-07-22 11:48:54 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-25 07:29:17 -0400 |
commit | b0fcd903e6f3f47189baddf3fe085bdf78c9644c (patch) | |
tree | c3c0e098b25d158973a7262865e74ae790a66772 | |
parent | 0de085bb474f64e4fdb2f1ff3268590792648c7b (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.c | 28 |
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, | |||
1078 | return 1; | 1078 | return 1; |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | static int emulator_write_emulated(unsigned long addr, | 1081 | static int emulator_write_emulated_onepage(unsigned long addr, |
1082 | const void *val, | 1082 | const void *val, |
1083 | unsigned int bytes, | 1083 | unsigned int bytes, |
1084 | struct x86_emulate_ctxt *ctxt) | 1084 | struct x86_emulate_ctxt *ctxt) |
1085 | { | 1085 | { |
1086 | struct kvm_vcpu *vcpu = ctxt->vcpu; | 1086 | struct kvm_vcpu *vcpu = ctxt->vcpu; |
1087 | struct kvm_io_device *mmio_dev; | 1087 | struct kvm_io_device *mmio_dev; |
@@ -1113,6 +1113,26 @@ static int emulator_write_emulated(unsigned long addr, | |||
1113 | return X86EMUL_CONTINUE; | 1113 | return X86EMUL_CONTINUE; |
1114 | } | 1114 | } |
1115 | 1115 | ||
1116 | static int emulator_write_emulated(unsigned long addr, | ||
1117 | const void *val, | ||
1118 | unsigned int bytes, | ||
1119 | struct x86_emulate_ctxt *ctxt) | ||
1120 | { | ||
1121 | /* Crossing a page boundary? */ | ||
1122 | if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { | ||
1123 | int rc, now; | ||
1124 | |||
1125 | now = -addr & ~PAGE_MASK; | ||
1126 | rc = emulator_write_emulated_onepage(addr, val, now, ctxt); | ||
1127 | if (rc != X86EMUL_CONTINUE) | ||
1128 | return rc; | ||
1129 | addr += now; | ||
1130 | val += now; | ||
1131 | bytes -= now; | ||
1132 | } | ||
1133 | return emulator_write_emulated_onepage(addr, val, bytes, ctxt); | ||
1134 | } | ||
1135 | |||
1116 | static int emulator_cmpxchg_emulated(unsigned long addr, | 1136 | static int emulator_cmpxchg_emulated(unsigned long addr, |
1117 | const void *old, | 1137 | const void *old, |
1118 | const void *new, | 1138 | const void *new, |