diff mbox

[1/5] x86emul: fix rIP handling

Message ID 56C4AEA502000078000D348C@prv-mh.provo.novell.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Beulich Feb. 17, 2016, 4:32 p.m. UTC
Deal with rIP just like with any other register: Truncate to designated
width upon entry, write back the zero-extended 32-bit value when
emulating 32-bit code, and leave the upper 48 bits unchanged for 16-bit
code.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
x86emul: fix rIP handling

Deal with rIP just like with any other register: Truncate to designated
width upon entry, write back the zero-extended 32-bit value when
emulating 32-bit code, and leave the upper 48 bits unchanged for 16-bit
code.

Signed-off-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -570,7 +570,6 @@ do{ asm volatile (
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch_bytes(_size)                                         \
 ({ unsigned long _x = 0, _eip = _regs.eip;                              \
-   if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
    _regs.eip += (_size); /* real hardware doesn't truncate */           \
    generate_exception_if((uint8_t)(_regs.eip -                          \
                                    ctxt->regs->eip) > MAX_INST_LEN,     \
@@ -1492,6 +1491,10 @@ x86_emulate(
 #endif
     }
 
+    /* Truncate rIP to def_ad_bytes (2 or 4) if necessary. */
+    if ( def_ad_bytes < sizeof(_regs.eip) )
+        _regs.eip &= (1UL << (def_ad_bytes * 8)) - 1;
+
     /* Prefix bytes. */
     for ( ; ; )
     {
@@ -3783,6 +3786,21 @@ x86_emulate(
 
     /* Commit shadow register state. */
     _regs.eflags &= ~EFLG_RF;
+    switch ( __builtin_expect(def_ad_bytes, sizeof(_regs.eip)) )
+    {
+        uint16_t ip;
+
+    case 2:
+        ip = _regs.eip;
+        _regs.eip = ctxt->regs->eip;
+        *(uint16_t *)&_regs.eip = ip;
+        break;
+#ifdef __x86_64__
+    case 4:
+        _regs.rip = _regs._eip;
+        break;
+#endif
+    }
     *ctxt->regs = _regs;
 
  done:

Comments

Andrew Cooper Feb. 17, 2016, 5:51 p.m. UTC | #1
On 17/02/16 16:32, Jan Beulich wrote:
> Deal with rIP just like with any other register: Truncate to designated
> width upon entry, write back the zero-extended 32-bit value when
> emulating 32-bit code, and leave the upper 48 bits unchanged for 16-bit
> code.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
diff mbox

Patch

--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -570,7 +570,6 @@  do{ asm volatile (
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch_bytes(_size)                                         \
 ({ unsigned long _x = 0, _eip = _regs.eip;                              \
-   if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
    _regs.eip += (_size); /* real hardware doesn't truncate */           \
    generate_exception_if((uint8_t)(_regs.eip -                          \
                                    ctxt->regs->eip) > MAX_INST_LEN,     \
@@ -1492,6 +1491,10 @@  x86_emulate(
 #endif
     }
 
+    /* Truncate rIP to def_ad_bytes (2 or 4) if necessary. */
+    if ( def_ad_bytes < sizeof(_regs.eip) )
+        _regs.eip &= (1UL << (def_ad_bytes * 8)) - 1;
+
     /* Prefix bytes. */
     for ( ; ; )
     {
@@ -3783,6 +3786,21 @@  x86_emulate(
 
     /* Commit shadow register state. */
     _regs.eflags &= ~EFLG_RF;
+    switch ( __builtin_expect(def_ad_bytes, sizeof(_regs.eip)) )
+    {
+        uint16_t ip;
+
+    case 2:
+        ip = _regs.eip;
+        _regs.eip = ctxt->regs->eip;
+        *(uint16_t *)&_regs.eip = ip;
+        break;
+#ifdef __x86_64__
+    case 4:
+        _regs.rip = _regs._eip;
+        break;
+#endif
+    }
     *ctxt->regs = _regs;
 
  done: