WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Generic x86 emulator now properly supports 16-bit addres

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Generic x86 emulator now properly supports 16-bit addressing
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 29 Dec 2005 17:12:06 +0000
Delivery-date: Thu, 29 Dec 2005 17:16:31 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 5fa0c70663f1d3859656d3fe4b4e214de59cb7d1
# Parent  829517be689f95d3d935ab1af17d0c31ee4950fc
Generic x86 emulator now properly supports 16-bit addressing
by narrowing accesses to SI/DI/SP registers. Also supports
real-mode addressing by shifting and adding the appropriate
segment register for certain stack and string operations
where the effective address is not already known.

todo: Stack operations should have address size specified
by B bit in stack segment descriptor, not by default address
size or address-size override. Probably nothing depends on
the proper behaviour though.

Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>

diff -r 829517be689f -r 5fa0c70663f1 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        Fri Dec 23 15:42:46 2005
+++ b/xen/arch/x86/x86_emulate.c        Fri Dec 23 17:28:33 2005
@@ -371,6 +371,21 @@
    (_type)_x; \
 })
 
+/* Access/update address held in a register, based on addressing mode. */
+#define register_address(sel, reg)                                      \
+    ((ad_bytes == sizeof(unsigned long)) ? (reg) :                      \
+     ((mode == X86EMUL_MODE_REAL) ? /* implies ad_bytes == 2 */         \
+      (((unsigned long)(sel) << 4) + ((reg) & 0xffff)) :                \
+      ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
+#define register_address_increment(reg, inc)                            \
+do {                                                                    \
+    if ( ad_bytes == sizeof(unsigned long) )                            \
+        (reg) += (inc);                                                 \
+    else                                                                \
+        (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) |             \
+                (((reg) + (inc)) & ((1UL << (ad_bytes << 3)) - 1));     \
+} while (0)
+
 void *
 decode_register(
     uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
@@ -420,32 +435,64 @@
 {
     uint8_t b, d, sib, twobyte = 0, rex_prefix = 0;
     uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
-    unsigned int op_bytes = (mode == 8) ? 4 : mode, ad_bytes = mode;
-    unsigned int lock_prefix = 0, rep_prefix = 0, i;
+    uint16_t *seg = NULL; /* override segment */
+    unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
     int rc = 0;
     struct operand src, dst;
 
     /* Shadow copy of register state. Committed on successful emulation. */
     struct cpu_user_regs _regs = *regs;
 
+    switch ( mode )
+    {
+    case X86EMUL_MODE_REAL:
+    case X86EMUL_MODE_PROT16:
+        op_bytes = ad_bytes = 2;
+        break;
+    case X86EMUL_MODE_PROT32:
+        op_bytes = ad_bytes = 4;
+        break;
+#ifdef __x86_64__
+    case X86EMUL_MODE_PROT64:
+        op_bytes = 4;
+        ad_bytes = 8;
+        break;
+#endif
+    default:
+        return -1;
+    }
+
     /* Legacy prefixes. */
     for ( i = 0; i < 8; i++ )
     {
         switch ( b = insn_fetch(uint8_t, 1, _regs.eip) )
         {
         case 0x66: /* operand-size override */
-            op_bytes ^= 6;                    /* switch between 2/4 bytes */
+            op_bytes ^= 6;      /* switch between 2/4 bytes */
             break;
         case 0x67: /* address-size override */
-            ad_bytes ^= (mode == 8) ? 12 : 6; /* switch between 2/4/8 bytes */
+            if ( mode == X86EMUL_MODE_PROT64 )
+                ad_bytes ^= 12; /* switch between 4/8 bytes */
+            else
+                ad_bytes ^= 6;  /* switch between 2/4 bytes */
             break;
         case 0x2e: /* CS override */
+            seg = &_regs.cs;
+            break;
         case 0x3e: /* DS override */
+            seg = &_regs.ds;
+            break;
         case 0x26: /* ES override */
+            seg = &_regs.es;
+            break;
         case 0x64: /* FS override */
+            seg = &_regs.fs;
+            break;
         case 0x65: /* GS override */
+            seg = &_regs.gs;
+            break;
         case 0x36: /* SS override */
-            DPRINTF("Warning: ignoring a segment override.\n");
+            seg = &_regs.ss;
             break;
         case 0xf0: /* LOCK */
             lock_prefix = 1;
@@ -461,8 +508,12 @@
     }
  done_prefixes:
 
+    /* Note quite the same as 80386 real mode, but hopefully good enough. */
+    if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) )
+        goto cannot_emulate;
+
     /* REX prefix. */
-    if ( (mode == 8) && ((b & 0xf0) == 0x40) )
+    if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
     {
         rex_prefix = b;
         if ( b & 8 )
@@ -674,7 +725,7 @@
         emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
         break;
     case 0x63: /* movsxd */
-        if ( mode != 8 ) /* x86/64 long mode only */
+        if ( mode != X86EMUL_MODE_PROT64 )
             goto cannot_emulate;
         dst.val = (int32_t)src.val;
         break;
@@ -721,12 +772,13 @@
         dst.val = src.val;
         break;
     case 0x8f: /* pop (sole member of Grp1a) */
-        /* 64-bit mode: POP defaults to 64-bit operands. */
-        if ( (mode == 8) && (dst.bytes == 4) )
+        /* 64-bit mode: POP always pops a 64-bit operand. */
+        if ( mode == X86EMUL_MODE_PROT64 )
             dst.bytes = 8;
-        if ( (rc = ops->read_std(_regs.esp, &dst.val, dst.bytes)) != 0 )
+        if ( (rc = ops->read_std(register_address(_regs.ss, _regs.esp),
+                                 &dst.val, dst.bytes)) != 0 )
             goto done;
-        _regs.esp += dst.bytes;
+        register_address_increment(_regs.esp, dst.bytes);
         break;
     case 0xc0 ... 0xc1: grp2: /* Grp2 */
         switch ( modrm_reg )
@@ -797,16 +849,17 @@
             emulate_1op("dec", dst, _regs.eflags);
             break;
         case 6: /* push */
-            /* 64-bit mode: PUSH defaults to 64-bit operands. */
-            if ( (mode == 8) && (dst.bytes == 4) )
+            /* 64-bit mode: PUSH always pushes a 64-bit operand. */
+            if ( mode == X86EMUL_MODE_PROT64 )
             {
                 dst.bytes = 8;
                 if ( (rc = ops->read_std((unsigned long)dst.ptr,
                                          &dst.val, 8)) != 0 )
                     goto done;
             }
-            _regs.esp -= dst.bytes;
-            if ( (rc = ops->write_std(_regs.esp, dst.val, dst.bytes)) != 0 )
+            register_address_increment(_regs.esp, -dst.bytes);
+            if ( (rc = ops->write_std(register_address(_regs.ss, _regs.esp),
+                                      dst.val, dst.bytes)) != 0 )
                 goto done;
             dst.val = dst.orig_val; /* skanky: disable writeback */
             break;
@@ -873,19 +926,22 @@
         {
             /* Write fault: destination is special memory. */
             dst.ptr = (unsigned long *)cr2;
-            if ( (rc = ops->read_std(_regs.esi - _regs.edi + cr2, 
+            if ( (rc = ops->read_std(register_address(seg ? *seg : _regs.ds,
+                                                      _regs.esi),
                                      &dst.val, dst.bytes)) != 0 )
                 goto done;
         }
         else
         {
             /* Read fault: source is special memory. */
-            dst.ptr = (unsigned long *)(_regs.edi - _regs.esi + cr2);
+            dst.ptr = (unsigned long *)register_address(_regs.es, _regs.edi);
             if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes)) != 0 )
                 goto done;
         }
-        _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
-        _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        register_address_increment(
+            _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+        register_address_increment(
+            _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         break;
     case 0xa6 ... 0xa7: /* cmps */
         DPRINTF("Urk! I don't handle CMPS.\n");
@@ -895,7 +951,8 @@
         dst.bytes = (d & ByteOp) ? 1 : op_bytes;
         dst.ptr   = (unsigned long *)cr2;
         dst.val   = _regs.eax;
-        _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        register_address_increment(
+            _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         break;
     case 0xac ... 0xad: /* lods */
         dst.type  = OP_REG;
@@ -903,7 +960,8 @@
         dst.ptr   = (unsigned long *)&_regs.eax;
         if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes)) != 0 )
             goto done;
-        _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        register_address_increment(
+            _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         break;
     case 0xae ... 0xaf: /* scas */
         DPRINTF("Urk! I don't handle SCAS.\n");
diff -r 829517be689f -r 5fa0c70663f1 xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Fri Dec 23 15:42:46 2005
+++ b/xen/include/asm-x86/x86_emulate.h Fri Dec 23 17:28:33 2005
@@ -141,6 +141,12 @@
 
 struct cpu_user_regs;
 
+/* Current execution mode, passed to the emulator. */
+#define X86EMUL_MODE_REAL     0
+#define X86EMUL_MODE_PROT16   2
+#define X86EMUL_MODE_PROT32   4
+#define X86EMUL_MODE_PROT64   8
+
 /*
  * x86_emulate_memop: Emulate an instruction that faulted attempting to
  *                    read/write a 'special' memory area.
@@ -149,6 +155,8 @@
  *  @ops:  Interface to access special memory.
  *  @mode: Current execution mode, represented by the default size of memory
  *         addresses, in bytes. Valid values are 2, 4 and 8 (x86/64 only).
+ *         Alternatively use the appropriate X86EMUL_MODE value (which also
+ *         includes a value for emulating real mode).
  */
 extern int
 x86_emulate_memop(

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Generic x86 emulator now properly supports 16-bit addressing, Xen patchbot -unstable <=