diff options
author | Luca Tettamanti <kronos.it@gmail.com> | 2007-06-19 16:41:20 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 05:05:48 -0400 |
commit | 02c03a326a5df825cc01de426f72e160db2b9538 (patch) | |
tree | 6b6e765fbe03832a7fd68c4c28e7f105875d40ed /drivers | |
parent | 74906345ff9f84f2b3b772d368c7e49f4ba27456 (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.c | 9 |
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 | ||
1062 | writeback: | 1063 | writeback: |
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 | ||
1324 | twobyte_special_insn: | 1325 | twobyte_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; |