# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1168875800 0
# Node ID 0ba81aa56455be37c2d5c19920f3633ad267604c
# Parent ba5e80864f9c9cc91879e2fc175370634d3bdd9a
[XEN] Allow stack-address-size to be specified differently from
regular address-size in the emulator.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/tests/test_x86_emulator.c | 3 +-
xen/arch/x86/mm.c | 3 +-
xen/arch/x86/mm/shadow/common.c | 25 +++++++++++++----
xen/arch/x86/x86_emulate.c | 53 ++++++++++++++++++++------------------
xen/include/asm-x86/x86_emulate.h | 7 +++--
5 files changed, 56 insertions(+), 35 deletions(-)
diff -r ba5e80864f9c -r 0ba81aa56455 tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c Mon Jan 15 14:32:25 2007 +0000
+++ b/tools/tests/test_x86_emulator.c Mon Jan 15 15:43:20 2007 +0000
@@ -118,7 +118,8 @@ int main(int argc, char **argv)
#endif
ctxt.regs = ®s;
- ctxt.address_bytes = 4;
+ ctxt.addr_size = 32;
+ ctxt.sp_size = 32;
res = mmap((void *)0x100000, MMAP_SZ, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
diff -r ba5e80864f9c -r 0ba81aa56455 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Jan 15 14:32:25 2007 +0000
+++ b/xen/arch/x86/mm.c Mon Jan 15 15:43:20 2007 +0000
@@ -3376,7 +3376,8 @@ int ptwr_do_page_fault(struct vcpu *v, u
goto bail;
ptwr_ctxt.ctxt.regs = guest_cpu_user_regs();
- ptwr_ctxt.ctxt.address_bytes = IS_COMPAT(d) ? 4 : sizeof(long);
+ ptwr_ctxt.ctxt.addr_size = ptwr_ctxt.ctxt.sp_size =
+ IS_COMPAT(d) ? 32 : BITS_PER_LONG;
ptwr_ctxt.cr2 = addr;
ptwr_ctxt.pte = pte;
if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
diff -r ba5e80864f9c -r 0ba81aa56455 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Mon Jan 15 14:32:25 2007 +0000
+++ b/xen/arch/x86/mm/shadow/common.c Mon Jan 15 15:43:20 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.address_bytes != 8 )
+ if ( sh_ctxt->ctxt.addr_size != 64 )
{
/*
* COMPATIBILITY MODE: Apply segment checks and add base.
@@ -399,7 +399,7 @@ struct x86_emulate_ops *shadow_init_emul
struct x86_emulate_ops *shadow_init_emulation(
struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs)
{
- struct segment_register *creg;
+ struct segment_register *creg, *sreg;
struct vcpu *v = current;
unsigned long addr;
@@ -407,7 +407,7 @@ struct x86_emulate_ops *shadow_init_emul
if ( !is_hvm_vcpu(v) )
{
- sh_ctxt->ctxt.address_bytes = sizeof(long);
+ sh_ctxt->ctxt.addr_size = sh_ctxt->ctxt.sp_size = BITS_PER_LONG;
return &pv_shadow_emulator_ops;
}
@@ -417,11 +417,24 @@ struct x86_emulate_ops *shadow_init_emul
/* Work out the emulation mode. */
if ( hvm_long_mode_enabled(v) )
- sh_ctxt->ctxt.address_bytes = creg->attr.fields.l ? 8 : 4;
+ {
+ sh_ctxt->ctxt.addr_size = creg->attr.fields.l ? 64 : 32;
+ if ( (sh_ctxt->ctxt.sp_size = sh_ctxt->ctxt.addr_size) != 64 )
+ {
+ sreg = hvm_get_seg_reg(x86_seg_ss, sh_ctxt);
+ sh_ctxt->ctxt.sp_size = sreg->attr.fields.db ? 32 : 16;
+ }
+ }
else if ( regs->eflags & X86_EFLAGS_VM )
- sh_ctxt->ctxt.address_bytes = 2;
+ {
+ sh_ctxt->ctxt.addr_size = sh_ctxt->ctxt.sp_size = 16;
+ }
else
- sh_ctxt->ctxt.address_bytes = creg->attr.fields.db ? 4 : 2;
+ {
+ sreg = hvm_get_seg_reg(x86_seg_ss, sh_ctxt);
+ sh_ctxt->ctxt.addr_size = creg->attr.fields.db ? 32 : 16;
+ sh_ctxt->ctxt.sp_size = sreg->attr.fields.db ? 32 : 16;
+ }
/* Attempt to prefetch whole instruction. */
sh_ctxt->insn_buf_bytes =
diff -r ba5e80864f9c -r 0ba81aa56455 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Mon Jan 15 14:32:25 2007 +0000
+++ b/xen/arch/x86/x86_emulate.c Mon Jan 15 15:43:20 2007 +0000
@@ -443,10 +443,11 @@ do{ __asm__ __volatile__ (
})
#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
-#define _truncate_ea(ea, byte_width) \
-({ unsigned long __ea = (ea); \
- (((byte_width) == sizeof(unsigned long)) ? __ea : \
- (__ea & ((1UL << ((byte_width) << 3)) - 1))); \
+#define _truncate_ea(ea, byte_width) \
+({ unsigned long __ea = (ea); \
+ unsigned int _width = (byte_width); \
+ ((_width == sizeof(unsigned long)) ? __ea : \
+ (__ea & ((1UL << (_width << 3)) - 1))); \
})
#define truncate_ea(ea) _truncate_ea((ea), ad_bytes)
@@ -473,16 +474,27 @@ static int even_parity(uint8_t v)
#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) ) \
+ unsigned int _width = (byte_width); \
+ if ( _width == sizeof(unsigned long) ) \
(reg) += _inc; \
else if ( mode_64bit() ) \
- (reg) = ((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1); \
+ (reg) = ((reg) + _inc) & ((1UL << (_width << 3)) - 1); \
else \
- (reg) = ((reg) & ~((1UL << ((byte_width) << 3)) - 1)) | \
- (((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1)); \
+ (reg) = ((reg) & ~((1UL << (_width << 3)) - 1)) | \
+ (((reg) + _inc) & ((1UL << (_width << 3)) - 1)); \
} while (0)
#define register_address_increment(reg, inc) \
_register_address_increment((reg), (inc), ad_bytes)
+
+#define sp_pre_dec(dec) ({ \
+ _register_address_increment(_regs.esp, -(dec), ctxt->sp_size/8); \
+ _truncate_ea(_regs.esp, ctxt->sp_size/8); \
+})
+#define sp_post_inc(inc) ({ \
+ unsigned long __esp = _truncate_ea(_regs.esp, ctxt->sp_size/8); \
+ _register_address_increment(_regs.esp, (inc), ctxt->sp_size/8); \
+ __esp; \
+})
#define jmp_rel(rel) \
do { \
@@ -679,7 +691,7 @@ x86_emulate(
ea.mem.seg = x86_seg_ds;
ea.mem.off = 0;
- op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->address_bytes;
+ op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8;
if ( op_bytes == 8 )
{
op_bytes = def_op_bytes = 4;
@@ -1194,10 +1206,9 @@ x86_emulate(
/* 64-bit mode: POP defaults to a 64-bit operand. */
if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
- if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
+ if ( (rc = ops->read(x86_seg_ss, sp_post_inc(dst.bytes),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
- register_address_increment(_regs.esp, dst.bytes);
break;
case 0xb0 ... 0xb7: /* mov imm8,r8 */
@@ -1488,8 +1499,7 @@ x86_emulate(
&dst.val, 8, ctxt)) != 0 )
goto done;
}
- register_address_increment(_regs.esp, -dst.bytes);
- if ( (rc = ops->write(x86_seg_ss, truncate_ea(_regs.esp),
+ if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(dst.bytes),
dst.val, dst.bytes, ctxt)) != 0 )
goto done;
dst.type = OP_NONE;
@@ -1644,10 +1654,9 @@ x86_emulate(
dst.bytes = op_bytes;
if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
- if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
+ if ( (rc = ops->read(x86_seg_ss, sp_post_inc(dst.bytes),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
- register_address_increment(_regs.esp, dst.bytes);
break;
case 0x60: /* pusha */ {
@@ -1657,11 +1666,9 @@ x86_emulate(
_regs.esp, _regs.ebp, _regs.esi, _regs.edi };
generate_exception_if(mode_64bit(), EXC_UD);
for ( i = 0; i < 8; i++ )
- if ( (rc = ops->write(x86_seg_ss,
- truncate_ea(_regs.esp-(i+1)*op_bytes),
+ if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
regs[i], op_bytes, ctxt)) != 0 )
goto done;
- register_address_increment(_regs.esp, -8*op_bytes);
break;
}
@@ -1674,11 +1681,9 @@ x86_emulate(
(unsigned long *)&_regs.ecx, (unsigned long *)&_regs.eax };
generate_exception_if(mode_64bit(), EXC_UD);
for ( i = 0; i < 8; i++ )
- if ( (rc = ops->read(x86_seg_ss,
- truncate_ea(_regs.esp+i*op_bytes),
+ if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
regs[i], op_bytes, ctxt)) != 0 )
goto done;
- register_address_increment(_regs.esp, 8*op_bytes);
break;
}
@@ -1697,9 +1702,8 @@ x86_emulate(
if ( mode_64bit() && (dst.bytes == 4) )
dst.bytes = 8;
dst.val = src.val;
- register_address_increment(_regs.esp, -dst.bytes);
dst.mem.seg = x86_seg_ss;
- dst.mem.off = truncate_ea(_regs.esp);
+ dst.mem.off = sp_pre_dec(dst.bytes);
break;
case 0x70 ... 0x7f: /* jcc (short) */ {
@@ -1813,11 +1817,10 @@ x86_emulate(
case 0xc3: /* ret (near) */ {
int offset = (b == 0xc2) ? insn_fetch_type(uint16_t) : 0;
op_bytes = mode_64bit() ? 8 : op_bytes;
- if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp),
+ if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes + offset),
&dst.val, op_bytes, ctxt)) != 0 )
goto done;
_regs.eip = dst.val;
- register_address_increment(_regs.esp, op_bytes + offset);
break;
}
diff -r ba5e80864f9c -r 0ba81aa56455 xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Mon Jan 15 14:32:25 2007 +0000
+++ b/xen/include/asm-x86/x86_emulate.h Mon Jan 15 15:43:20 2007 +0000
@@ -150,8 +150,11 @@ struct x86_emulate_ctxt
/* Register state before/after emulation. */
struct cpu_user_regs *regs;
- /* Default address size in current execution mode (2, 4, or 8). */
- int address_bytes;
+ /* Default address size in current execution mode (16, 32, or 64). */
+ unsigned int addr_size;
+
+ /* Stack pointer width in bits (16, 32 or 64). */
+ unsigned int sp_size;
};
/*
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|