# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1168281569 0
# Node ID 8a99ebc5f5a42543d41f97329087d04d4ff301b5
# Parent 1e7bbecdc0a2f286efba0e817415908b2c5744da
[XEN] Tweak x86 emulator interface.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/tests/test_x86_emulator.c | 2 -
xen/arch/x86/hvm/instrlen.c | 32 ++++++-------------
xen/arch/x86/hvm/platform.c | 22 ++++++-------
xen/arch/x86/hvm/svm/svm.c | 10 ++----
xen/arch/x86/hvm/vmx/vmx.c | 10 ++----
xen/arch/x86/mm.c | 6 +--
xen/arch/x86/mm/shadow/common.c | 12 +++----
xen/arch/x86/x86_emulate.c | 62 ++++++++++++++------------------------
xen/include/asm-x86/hvm/hvm.h | 2 -
xen/include/asm-x86/x86_emulate.h | 19 +----------
10 files changed, 67 insertions(+), 110 deletions(-)
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c Mon Jan 08 17:38:47 2007 +0000
+++ b/tools/tests/test_x86_emulator.c Mon Jan 08 18:39:29 2007 +0000
@@ -102,7 +102,7 @@ int main(int argc, char **argv)
int rc;
ctxt.regs = ®s;
- ctxt.mode = X86EMUL_MODE_PROT32;
+ ctxt.address_bytes = 4;
res = mmap((void *)0x100000, 0x1000, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/instrlen.c
--- a/xen/arch/x86/hvm/instrlen.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/hvm/instrlen.c Mon Jan 08 18:39:29 2007 +0000
@@ -201,7 +201,7 @@ static uint8_t twobyte_table[256] = {
if ( inst_copy_from_guest(&_x, pc, 1) != 1 ) { \
gdprintk(XENLOG_WARNING, \
"Cannot read from address %lx (eip %lx, mode %d)\n", \
- pc, org_pc, mode); \
+ pc, org_pc, address_bytes); \
return -1; \
} \
pc += 1; \
@@ -218,30 +218,20 @@ static uint8_t twobyte_table[256] = {
* EXTERNAL this routine calculates the length of the current instruction
* pointed to by org_pc. The guest state is _not_ changed by this routine.
*/
-int hvm_instruction_length(unsigned long org_pc, int mode)
+int hvm_instruction_length(unsigned long org_pc, int address_bytes)
{
uint8_t b, d, twobyte = 0, rex_prefix = 0, modrm_reg = 0;
unsigned int op_default, op_bytes, ad_default, ad_bytes, tmp;
int length = 0;
unsigned long pc = org_pc;
- switch ( mode )
- {
- case X86EMUL_MODE_REAL:
- case X86EMUL_MODE_PROT16:
- op_bytes = op_default = ad_bytes = ad_default = 2;
- break;
- case X86EMUL_MODE_PROT32:
- op_bytes = op_default = ad_bytes = ad_default = 4;
- break;
-#ifdef __x86_64__
- case X86EMUL_MODE_PROT64:
+ op_bytes = op_default = ad_bytes = ad_default = address_bytes;
+ if ( op_bytes == 8 )
+ {
op_bytes = op_default = 4;
- ad_bytes = ad_default = 8;
- break;
+#ifndef __x86_64__
+ return -1;
#endif
- default:
- return -1;
}
/* Legacy prefixes. */
@@ -253,7 +243,7 @@ int hvm_instruction_length(unsigned long
op_bytes = op_default ^ 6; /* switch between 2/4 bytes */
break;
case 0x67: /* address-size override */
- if ( mode == X86EMUL_MODE_PROT64 )
+ if ( ad_default == 8 )
ad_bytes = ad_default ^ 12; /* switch between 4/8 bytes */
else
ad_bytes = ad_default ^ 6; /* switch between 2/4 bytes */
@@ -270,7 +260,7 @@ int hvm_instruction_length(unsigned long
break;
#ifdef __x86_64__
case 0x40 ... 0x4f:
- if ( mode == X86EMUL_MODE_PROT64 )
+ if ( ad_default == 8 )
{
rex_prefix = b;
continue;
@@ -434,7 +424,7 @@ done:
cannot_emulate:
gdprintk(XENLOG_WARNING,
- "Cannot emulate %02x at address %lx (%lx, mode %d)\n",
- b, pc - 1, org_pc, mode);
+ "Cannot emulate %02x at address %lx (%lx, addr_bytes %d)\n",
+ b, pc - 1, org_pc, address_bytes);
return -1;
}
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/platform.c
--- a/xen/arch/x86/hvm/platform.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/hvm/platform.c Mon Jan 08 18:39:29 2007 +0000
@@ -352,7 +352,7 @@ static int reg_mem(unsigned char size, u
return DECODE_success;
}
-static int mmio_decode(int mode, unsigned char *opcode,
+static int mmio_decode(int address_bytes, unsigned char *opcode,
struct hvm_io_op *mmio_op,
unsigned char *ad_size, unsigned char *op_size,
unsigned char *seg_sel)
@@ -368,9 +368,9 @@ static int mmio_decode(int mode, unsigne
opcode = check_prefix(opcode, mmio_op, ad_size, op_size, seg_sel, &rex);
- switch ( mode ) {
- case X86EMUL_MODE_REAL: /* meaning is reversed */
- case X86EMUL_MODE_PROT16:
+ switch ( address_bytes )
+ {
+ case 2:
if ( *op_size == WORD )
*op_size = LONG;
else if ( *op_size == LONG )
@@ -384,14 +384,14 @@ static int mmio_decode(int mode, unsigne
else if ( *ad_size == 0 )
*ad_size = WORD;
break;
- case X86EMUL_MODE_PROT32:
+ case 4:
if ( *op_size == 0 )
*op_size = LONG;
if ( *ad_size == 0 )
*ad_size = LONG;
break;
#ifdef __x86_64__
- case X86EMUL_MODE_PROT64:
+ case 8:
if ( *op_size == 0 )
*op_size = rex & 0x8 ? QUAD : LONG;
if ( *ad_size == 0 )
@@ -907,7 +907,7 @@ void handle_mmio(unsigned long gpa)
struct hvm_io_op *mmio_op;
struct cpu_user_regs *regs;
unsigned char inst[MAX_INST_LEN], ad_size, op_size, seg_sel;
- int i, mode, df, inst_len;
+ int i, address_bytes, df, inst_len;
struct vcpu *v = current;
mmio_op = &v->arch.hvm_vcpu.io_op;
@@ -919,9 +919,9 @@ void handle_mmio(unsigned long gpa)
df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
- mode = hvm_guest_x86_mode(v);
+ address_bytes = hvm_guest_x86_mode(v);
inst_addr = hvm_get_segment_base(v, x86_seg_cs) + regs->eip;
- inst_len = hvm_instruction_length(inst_addr, mode);
+ inst_len = hvm_instruction_length(inst_addr, address_bytes);
if ( inst_len <= 0 )
{
printk("handle_mmio: failed to get instruction length\n");
@@ -934,8 +934,8 @@ void handle_mmio(unsigned long gpa)
domain_crash_synchronous();
}
- if ( mmio_decode(mode, inst, mmio_op, &ad_size, &op_size, &seg_sel)
- == DECODE_failure ) {
+ if ( mmio_decode(address_bytes, inst, mmio_op, &ad_size,
+ &op_size, &seg_sel) == DECODE_failure ) {
printk("handle_mmio: failed to decode instruction\n");
printk("mmio opcode: gpa 0x%lx, len %d:", gpa, inst_len);
for ( i = 0; i < inst_len; i++ )
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c Mon Jan 08 18:39:29 2007 +0000
@@ -483,14 +483,12 @@ static int svm_guest_x86_mode(struct vcp
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
if ( vmcb->efer & EFER_LMA )
- return (vmcb->cs.attr.fields.l ?
- X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+ return (vmcb->cs.attr.fields.l ? 8 : 4);
if ( svm_realmode(v) )
- return X86EMUL_MODE_REAL;
-
- return (vmcb->cs.attr.fields.db ?
- X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
+ return 2;
+
+ return (vmcb->cs.attr.fields.db ? 4 : 2);
}
void svm_update_host_cr3(struct vcpu *v)
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Jan 08 18:39:29 2007 +0000
@@ -695,14 +695,12 @@ static int vmx_guest_x86_mode(struct vcp
cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES);
if ( vmx_long_mode_enabled(v) )
- return ((cs_ar_bytes & (1u<<13)) ?
- X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+ return ((cs_ar_bytes & (1u<<13)) ? 8 : 4);
if ( vmx_realmode(v) )
- return X86EMUL_MODE_REAL;
-
- return ((cs_ar_bytes & (1u<<14)) ?
- X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
+ return 2;
+
+ return ((cs_ar_bytes & (1u<<14)) ? 4 : 2);
}
static int vmx_pae_enabled(struct vcpu *v)
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/mm.c Mon Jan 08 18:39:29 2007 +0000
@@ -3379,9 +3379,9 @@ int ptwr_do_page_fault(struct vcpu *v, u
goto bail;
ptwr_ctxt.ctxt.regs = guest_cpu_user_regs();
- ptwr_ctxt.ctxt.mode = !IS_COMPAT(d) ? X86EMUL_MODE_HOST :
X86EMUL_MODE_PROT32;
- ptwr_ctxt.cr2 = addr;
- ptwr_ctxt.pte = pte;
+ ptwr_ctxt.ctxt.address_bytes = IS_COMPAT(d) ? 4 : sizeof(long);
+ ptwr_ctxt.cr2 = addr;
+ ptwr_ctxt.pte = pte;
if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
goto bail;
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/mm/shadow/common.c Mon Jan 08 18:39:29 2007 +0000
@@ -110,7 +110,7 @@ static int hvm_translate_linear_addr(
unsigned long limit, addr = offset;
uint32_t last_byte;
- if ( sh_ctxt->ctxt.mode != X86EMUL_MODE_PROT64 )
+ if ( sh_ctxt->ctxt.address_bytes != 8 )
{
/*
* COMPATIBILITY MODE: Apply segment checks and add base.
@@ -407,7 +407,7 @@ struct x86_emulate_ops *shadow_init_emul
if ( !is_hvm_vcpu(v) )
{
- sh_ctxt->ctxt.mode = X86EMUL_MODE_HOST;
+ sh_ctxt->ctxt.address_bytes = sizeof(long);
return &pv_shadow_emulator_ops;
}
@@ -417,13 +417,11 @@ struct x86_emulate_ops *shadow_init_emul
/* Work out the emulation mode. */
if ( hvm_long_mode_enabled(v) )
- sh_ctxt->ctxt.mode = creg->attr.fields.l ?
- X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32;
+ sh_ctxt->ctxt.address_bytes = creg->attr.fields.l ? 8 : 4;
else if ( regs->eflags & X86_EFLAGS_VM )
- sh_ctxt->ctxt.mode = X86EMUL_MODE_REAL;
+ sh_ctxt->ctxt.address_bytes = 2;
else
- sh_ctxt->ctxt.mode = creg->attr.fields.db ?
- X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ sh_ctxt->ctxt.address_bytes = creg->attr.fields.db ? 4 : 2;
/* Attempt to prefetch whole instruction. */
sh_ctxt->insn_buf_bytes =
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/arch/x86/x86_emulate.c Mon Jan 08 18:39:29 2007 +0000
@@ -391,10 +391,10 @@ do{ __asm__ __volatile__ (
/* Fetch next part of the instruction being emulated. */
#define insn_fetch_bytes(_size) \
({ unsigned long _x, _eip = _truncate_ea(_regs.eip, def_ad_bytes); \
+ if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt); \
- if ( rc != 0 ) \
- goto done; \
- _register_address_increment(_regs.eip, (_size), def_ad_bytes); \
+ if ( rc ) goto done; \
+ _regs.eip += (_size); /* real hardware doesn't truncate */ \
_x; \
})
#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
@@ -406,13 +406,15 @@ do{ __asm__ __volatile__ (
})
#define truncate_ea(ea) _truncate_ea((ea), ad_bytes)
+#define mode_64bit() (def_ad_bytes == 8)
+
/* Update address held in a register, based on addressing mode. */
#define _register_address_increment(reg, inc, byte_width) \
do { \
int _inc = (inc); /* signed type ensures sign extension to long */ \
if ( (byte_width) == sizeof(unsigned long) ) \
(reg) += _inc; \
- else if ( mode == X86EMUL_MODE_PROT64 ) \
+ else if ( mode_64bit() ) \
(reg) = ((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1); \
else \
(reg) = ((reg) & ~((1UL << ((byte_width) << 3)) - 1)) | \
@@ -424,7 +426,7 @@ do {
#define jmp_rel(rel) \
do { \
_regs.eip += (int)(rel); \
- if ( mode != X86EMUL_MODE_PROT64 ) \
+ if ( !mode_64bit() ) \
_regs.eip = ((op_bytes == 2) \
? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \
} while (0)
@@ -521,7 +523,6 @@ x86_emulate(
unsigned int lock_prefix = 0, rep_prefix = 0, i;
int rc = 0;
struct operand src, dst;
- int mode = ctxt->mode;
/* Data operand effective address (usually computed from ModRM). */
struct operand ea;
@@ -531,26 +532,14 @@ x86_emulate(
ea.mem.seg = x86_seg_ds;
ea.mem.off = 0;
- switch ( mode )
- {
- case X86EMUL_MODE_REAL:
- case X86EMUL_MODE_PROT16:
- op_bytes = def_ad_bytes = 2;
- break;
- case X86EMUL_MODE_PROT32:
- op_bytes = def_ad_bytes = 4;
- break;
-#ifdef __x86_64__
- case X86EMUL_MODE_PROT64:
+ op_bytes = ad_bytes = def_ad_bytes = ctxt->address_bytes;
+ if ( op_bytes == 8 )
+ {
op_bytes = 4;
- def_ad_bytes = 8;
- break;
+#ifndef __x86_64__
+ return -1;
#endif
- default:
- return -1;
- }
-
- ad_bytes = def_ad_bytes;
+ }
/* Prefix bytes. */
for ( i = 0; i < 8; i++ )
@@ -561,7 +550,7 @@ x86_emulate(
op_bytes ^= 6; /* switch between 2/4 bytes */
break;
case 0x67: /* address-size override */
- if ( mode == X86EMUL_MODE_PROT64 )
+ if ( mode_64bit() )
ad_bytes ^= 12; /* switch between 4/8 bytes */
else
ad_bytes ^= 6; /* switch between 2/4 bytes */
@@ -592,7 +581,7 @@ x86_emulate(
rep_prefix = 1;
break;
case 0x40 ... 0x4f: /* REX */
- if ( mode != X86EMUL_MODE_PROT64 )
+ if ( !mode_64bit() )
goto done_prefixes;
rex_prefix = b;
continue;
@@ -685,8 +674,7 @@ x86_emulate(
else if ( (sib_base == 4) && !twobyte && (b == 0x8f) )
/* POP <rm> must have its EA calculated post increment. */
ea.mem.off += _regs.esp +
- (((mode == X86EMUL_MODE_PROT64) && (op_bytes == 4))
- ? 8 : op_bytes);
+ ((mode_64bit() && (op_bytes == 4)) ? 8 : op_bytes);
else
ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);
}
@@ -701,7 +689,7 @@ x86_emulate(
if ( (modrm_rm & 7) != 5 )
break;
ea.mem.off = insn_fetch_type(int32_t);
- if ( mode != X86EMUL_MODE_PROT64 )
+ if ( !mode_64bit() )
break;
/* Relative to RIP of next instruction. Argh! */
ea.mem.off += _regs.eip;
@@ -935,7 +923,7 @@ x86_emulate(
break;
case 0x63: /* movsxd */
- if ( mode != X86EMUL_MODE_PROT64 )
+ if ( !mode_64bit() )
goto cannot_emulate;
dst.val = (int32_t)src.val;
break;
@@ -983,7 +971,7 @@ x86_emulate(
case 0x8f: /* pop (sole member of Grp1a) */
/* 64-bit mode: POP defaults to a 64-bit operand. */
- if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
+ if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
&dst.val, dst.bytes, ctxt)) != 0 )
@@ -1079,7 +1067,7 @@ x86_emulate(
break;
case 6: /* push */
/* 64-bit mode: PUSH defaults to a 64-bit operand. */
- if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
+ if ( mode_64bit() && (dst.bytes == 4) )
{
dst.bytes = 8;
if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
@@ -1168,7 +1156,7 @@ x86_emulate(
case 0x50 ... 0x57: /* push reg */
dst.type = OP_MEM;
dst.bytes = op_bytes;
- if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
+ if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
dst.val = *(unsigned long *)decode_register(
(b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
@@ -1182,7 +1170,7 @@ x86_emulate(
dst.reg = decode_register(
(b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
dst.bytes = op_bytes;
- if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) )
+ if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
&dst.val, dst.bytes, ctxt)) != 0 )
@@ -1278,8 +1266,7 @@ x86_emulate(
break;
case 0xeb: /* jmp (near) */
- jmp_rel(insn_fetch_bytes(
- (mode == X86EMUL_MODE_PROT64) ? 4 : op_bytes));
+ jmp_rel(insn_fetch_bytes(mode_64bit() ? 4 : op_bytes));
break;
case 0xf5: /* cmc */
@@ -1401,8 +1388,7 @@ x86_emulate(
break;
case 0x80 ... 0x8f: /* jcc (near) */ {
- int rel = insn_fetch_bytes(
- (mode == X86EMUL_MODE_PROT64) ? 4 : op_bytes);
+ int rel = insn_fetch_bytes(mode_64bit() ? 4 : op_bytes);
if ( test_cc(b, _regs.eflags) )
jmp_rel(rel);
break;
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h Mon Jan 08 18:39:29 2007 +0000
@@ -185,7 +185,7 @@ hvm_guest_x86_mode(struct vcpu *v)
return hvm_funcs.guest_x86_mode(v);
}
-int hvm_instruction_length(unsigned long pc, int mode);
+int hvm_instruction_length(unsigned long pc, int address_bytes);
static inline void
hvm_update_host_cr3(struct vcpu *v)
diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Mon Jan 08 17:38:47 2007 +0000
+++ b/xen/include/asm-x86/x86_emulate.h Mon Jan 08 18:39:29 2007 +0000
@@ -134,24 +134,11 @@ struct x86_emulate_ctxt
struct x86_emulate_ctxt
{
/* Register state before/after emulation. */
- struct cpu_user_regs *regs;
+ struct cpu_user_regs *regs;
- /* Emulated execution mode, represented by an X86EMUL_MODE value. */
- int mode;
+ /* Default address size in current execution mode (2, 4, or 8). */
+ int address_bytes;
};
-
-/* Execution mode, passed to the emulator. */
-#define X86EMUL_MODE_REAL 0 /* Real mode. */
-#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */
-#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
-#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
-
-/* Host execution mode. */
-#if defined(__i386__)
-#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
-#elif defined(__x86_64__)
-#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
-#endif
/*
* x86_emulate: Emulate an instruction.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|