diff options
author | Luca Tettamanti <kronos.it@gmail.com> | 2007-06-19 22:41:20 +0200 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 12:05:48 +0300 |
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 92620e48f06..f60012d6261 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) int mode = ctxt->mode; unsigned long modrm_ea; int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0; + int no_wb = 0; /* Shadow copy of register state. Committed on successful emulation. */ unsigned long _regs[NR_VCPU_REGS]; @@ -1051,7 +1052,7 @@ done_prefixes: _regs[VCPU_REGS_RSP]), &dst.val, dst.bytes, ctxt)) != 0) goto done; - dst.val = dst.orig_val; /* skanky: disable writeback */ + no_wb = 1; break; default: goto cannot_emulate; @@ -1060,7 +1061,7 @@ done_prefixes: } writeback: - if ((d & Mov) || (dst.orig_val != dst.val)) { + if (!no_wb) { switch (dst.type) { case OP_REG: /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ @@ -1168,7 +1169,7 @@ pop_instruction: goto done; register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); - dst.orig_val = dst.val; /* Disable writeback. */ + no_wb = 1; /* Disable writeback. */ break; } goto writeback; @@ -1323,7 +1324,7 @@ twobyte_insn: twobyte_special_insn: /* Disable writeback. */ - dst.orig_val = dst.val; + no_wb = 1; switch (b) { case 0x09: /* wbinvd */ break; |