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>
This commit is contained in:
committed by
Avi Kivity
parent
74906345ff
commit
02c03a326a
@@ -485,6 +485,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||||||
int mode = ctxt->mode;
|
int mode = ctxt->mode;
|
||||||
unsigned long modrm_ea;
|
unsigned long modrm_ea;
|
||||||
int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
|
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. */
|
/* Shadow copy of register state. Committed on successful emulation. */
|
||||||
unsigned long _regs[NR_VCPU_REGS];
|
unsigned long _regs[NR_VCPU_REGS];
|
||||||
@@ -1051,7 +1052,7 @@ done_prefixes:
|
|||||||
_regs[VCPU_REGS_RSP]),
|
_regs[VCPU_REGS_RSP]),
|
||||||
&dst.val, dst.bytes, ctxt)) != 0)
|
&dst.val, dst.bytes, ctxt)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
dst.val = dst.orig_val; /* skanky: disable writeback */
|
no_wb = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto cannot_emulate;
|
goto cannot_emulate;
|
||||||
@@ -1060,7 +1061,7 @@ done_prefixes:
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeback:
|
writeback:
|
||||||
if ((d & Mov) || (dst.orig_val != dst.val)) {
|
if (!no_wb) {
|
||||||
switch (dst.type) {
|
switch (dst.type) {
|
||||||
case OP_REG:
|
case OP_REG:
|
||||||
/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
|
/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
|
||||||
@@ -1168,7 +1169,7 @@ pop_instruction:
|
|||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
|
register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
|
||||||
dst.orig_val = dst.val; /* Disable writeback. */
|
no_wb = 1; /* Disable writeback. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
goto writeback;
|
goto writeback;
|
||||||
@@ -1323,7 +1324,7 @@ twobyte_insn:
|
|||||||
|
|
||||||
twobyte_special_insn:
|
twobyte_special_insn:
|
||||||
/* Disable writeback. */
|
/* Disable writeback. */
|
||||||
dst.orig_val = dst.val;
|
no_wb = 1;
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case 0x09: /* wbinvd */
|
case 0x09: /* wbinvd */
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user