[XEN] Allow stack-address-size to be specified differently from
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 15 Jan 2007 15:43:20 +0000 (15:43 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 15 Jan 2007 15:43:20 +0000 (15:43 +0000)
regular address-size in the emulator.
Signed-off-by: Keir Fraser <keir@xensource.com>
tools/tests/test_x86_emulator.c
xen/arch/x86/mm.c
xen/arch/x86/mm/shadow/common.c
xen/arch/x86/x86_emulate.c
xen/include/asm-x86/x86_emulate.h

index 1ebe2bb6ddf195569be2dc01299d68c595db6b22..2d8d49e43fb126f4b37ffaf05cecd92b25bc4d85 100644 (file)
@@ -118,7 +118,8 @@ int main(int argc, char **argv)
 #endif
 
     ctxt.regs = &regs;
-    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);
index a4b93f2b70ed53180de197addb803bc14981898c..c095ba41a1cf594cb791e42fabdc121aea9811f0 100644 (file)
@@ -3376,7 +3376,8 @@ int ptwr_do_page_fault(struct vcpu *v, unsigned long addr,
         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) )
index 8cee158842c1bd0bfa20a1656258d39a5c419b66..ac35c7e5cbcd28f4b80050fa1ec487a870d8bce9 100644 (file)
@@ -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 @@ static struct x86_emulate_ops pv_shadow_emulator_ops = {
 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_emulation(
 
     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_emulation(
 
     /* 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 =
index 6690a394f0172394e7f57602a8e82b44f126ad7c..feeccd53de0b4156e101b05e03e2d81f68cc8ec1 100644 (file)
@@ -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,17 +474,28 @@ 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 {                                                                    \
     _regs.eip += (int)(rel);                                            \
@@ -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;
     }
 
index 153bf14aac4632a20935b9ed3997407fd71f8e9d..45246b8044ac7064b3ea12dd284a98d14a6a7f9e 100644 (file)
@@ -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;
 };
 
 /*