summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-11-22 14:16:12 +0200
committerAvi Kivity <avi@qumranet.com>2008-01-30 17:53:14 +0200
commitf21b8bf4cc4091b23669987124fd13f758abf6d6 (patch)
treea15405e027bc520727c9aa86e607a629b98924ac
parent90e0a28f6b7241c7793f2ebd540c349580170446 (diff)
KVM: x86 emulator: address size and operand size overrides are sticky
Current implementation is to toggle, which is incorrect. Patch ported from corresponding Xen code. Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/x86_emulate.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 9f8d59a4931..3be506ac01a 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -758,6 +758,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
struct decode_cache *c = &ctxt->decode;
int rc = 0;
int mode = ctxt->mode;
+ int def_op_bytes, def_ad_bytes;
/* Shadow copy of register state. Committed on successful emulation. */
@@ -768,34 +769,38 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
switch (mode) {
case X86EMUL_MODE_REAL:
case X86EMUL_MODE_PROT16:
- c->op_bytes = c->ad_bytes = 2;
+ def_op_bytes = def_ad_bytes = 2;
break;
case X86EMUL_MODE_PROT32:
- c->op_bytes = c->ad_bytes = 4;
+ def_op_bytes = def_ad_bytes = 4;
break;
#ifdef CONFIG_X86_64
case X86EMUL_MODE_PROT64:
- c->op_bytes = 4;
- c->ad_bytes = 8;
+ def_op_bytes = 4;
+ def_ad_bytes = 8;
break;
#endif
default:
return -1;
}
+ c->op_bytes = def_op_bytes;
+ c->ad_bytes = def_ad_bytes;
+
/* Legacy prefixes. */
for (;;) {
switch (c->b = insn_fetch(u8, 1, c->eip)) {
case 0x66: /* operand-size override */
- c->op_bytes ^= 6; /* switch between 2/4 bytes */
+ /* switch between 2/4 bytes */
+ c->op_bytes = def_op_bytes ^ 6;
break;
case 0x67: /* address-size override */
if (mode == X86EMUL_MODE_PROT64)
/* switch between 4/8 bytes */
- c->ad_bytes ^= 12;
+ c->ad_bytes = def_ad_bytes ^ 12;
else
/* switch between 2/4 bytes */
- c->ad_bytes ^= 6;
+ c->ad_bytes = def_ad_bytes ^ 6;
break;
case 0x2e: /* CS override */
c->override_base = &ctxt->cs_base;