aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLuca Tettamanti <kronos.it@gmail.com>2007-06-19 16:41:20 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:48 -0400
commit02c03a326a5df825cc01de426f72e160db2b9538 (patch)
tree6b6e765fbe03832a7fd68c4c28e7f105875d40ed /drivers
parent74906345ff9f84f2b3b772d368c7e49f4ba27456 (diff)
KVM: Fix x86 emulator writeback
When the old value and new one are the same the emulator skips the write; this is undesirable when the destination is a MMIO area and the write shall be performed regardless of the previous value. This optimization breaks e.g. a Linux guest APIC compiled without X86_GOOD_APIC. Remove the check and perform the writeback stage in the emulation unless it's explicitly disabled (currently push and some 2 bytes instructions may disable the writeback). Signed-Off-By: Luca Tettamanti <kronos.it@gmail.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/x86_emulate.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 92620e48f06d..f60012d62610 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -485,6 +485,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
485 int mode = ctxt->mode; 485 int mode = ctxt->mode;
486 unsigned long modrm_ea; 486 unsigned long modrm_ea;
487 int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0; 487 int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
488 int no_wb = 0;
488 489
489 /* Shadow copy of register state. Committed on successful emulation. */ 490 /* Shadow copy of register state. Committed on successful emulation. */
490 unsigned long _regs[NR_VCPU_REGS]; 491 unsigned long _regs[NR_VCPU_REGS];
@@ -1051,7 +1052,7 @@ done_prefixes:
1051 _regs[VCPU_REGS_RSP]), 1052 _regs[VCPU_REGS_RSP]),
1052 &dst.val, dst.bytes, ctxt)) != 0) 1053 &dst.val, dst.bytes, ctxt)) != 0)
1053 goto done; 1054 goto done;
1054 dst.val = dst.orig_val; /* skanky: disable writeback */ 1055 no_wb = 1;
1055 break; 1056 break;
1056 default: 1057 default:
1057 goto cannot_emulate; 1058 goto cannot_emulate;
@@ -1060,7 +1061,7 @@ done_prefixes:
1060 } 1061 }
1061 1062
1062writeback: 1063writeback:
1063 if ((d & Mov) || (dst.orig_val != dst.val)) { 1064 if (!no_wb) {
1064 switch (dst.type) { 1065 switch (dst.type) {
1065 case OP_REG: 1066 case OP_REG:
1066 /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ 1067 /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
@@ -1168,7 +1169,7 @@ pop_instruction:
1168 goto done; 1169 goto done;
1169 1170
1170 register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); 1171 register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
1171 dst.orig_val = dst.val; /* Disable writeback. */ 1172 no_wb = 1; /* Disable writeback. */
1172 break; 1173 break;
1173 } 1174 }
1174 goto writeback; 1175 goto writeback;
@@ -1323,7 +1324,7 @@ twobyte_insn:
1323 1324
1324twobyte_special_insn: 1325twobyte_special_insn:
1325 /* Disable writeback. */ 1326 /* Disable writeback. */
1326 dst.orig_val = dst.val; 1327 no_wb = 1;
1327 switch (b) { 1328 switch (b) {
1328 case 0x09: /* wbinvd */ 1329 case 0x09: /* wbinvd */
1329 break; 1330 break;