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.
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;
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;
}
/* 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 =
})
#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)
#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 { \
_regs.eip += (int)(rel); \
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;
/* 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 */
&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;
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 */ {
_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;
}
(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;
}
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) */ {
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;
}