[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] x86emul: also handle shifts through ->rmw()



commit 04a1a30c50615c1b578301eec7bbcd9ec482e41c
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Mar 22 10:40:24 2018 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Mar 22 10:40:24 2018 +0100

    x86emul: also handle shifts through ->rmw()
    
    These don't allow LOCK, but still are read-modify-write operations, so
    are better handled that way too.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 tools/tests/x86_emulator/test_x86_emulator.c | 31 +++++++++
 xen/arch/x86/x86_emulate/x86_emulate.c       | 94 ++++++++++++++++++----------
 2 files changed, 92 insertions(+), 33 deletions(-)

diff --git a/tools/tests/x86_emulator/test_x86_emulator.c 
b/tools/tests/x86_emulator/test_x86_emulator.c
index 8e99bfcbd0..ad9a5e72b7 100644
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -585,6 +585,37 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
+    printf("%-40s", "Testing rcll $2,(%edi)...");
+    instr[0] = 0xc1; instr[1] = 0x17; instr[2] = 0x02;
+    *res        = 0x2233445F;
+    regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS_CF;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.edi    = (unsigned long)res;
+    rc = x86_emulate(&ctxt, &emulops);
+    if ( (rc != X86EMUL_OKAY) ||
+         (*res != ((0x2233445F << 2) | 2)) ||
+         ((regs.eflags & (EFLAGS_MASK & ~X86_EFLAGS_OF))
+          != EFLAGS_ALWAYS_SET) ||
+         (regs.eip != (unsigned long)&instr[3]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing shrdl $8,%ecx,(%edi)...");
+    instr[0] = 0x0f; instr[1] = 0xac; instr[2] = 0x0f; instr[3] = 0x08;
+    *res        = 0x22334455;
+    regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS_CF;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.ecx    = 0x44332211;
+    regs.edi    = (unsigned long)res;
+    rc = x86_emulate(&ctxt, &emulops);
+    if ( (rc != X86EMUL_OKAY) ||
+         (*res != 0x11223344) ||
+         ((regs.eflags & (EFLAGS_MASK & ~(X86_EFLAGS_OF|X86_EFLAGS_AF)))
+          != (EFLAGS_ALWAYS_SET | X86_EFLAGS_PF)) ||
+         (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
     printf("%-40s", "Testing btrl $0x1,(%edi)...");
     instr[0] = 0x0f; instr[1] = 0xba; instr[2] = 0x37; instr[3] = 0x01;
     *res        = 0x2233445F;
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c 
b/xen/arch/x86/x86_emulate/x86_emulate.c
index 5a07238090..d97e262386 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -682,7 +682,16 @@ struct x86_emulate_state {
         rmw_neg,
         rmw_not,
         rmw_or,
+        rmw_rcl,
+        rmw_rcr,
+        rmw_rol,
+        rmw_ror,
+        rmw_sar,
         rmw_sbb,
+        rmw_shl,
+        rmw_shld,
+        rmw_shr,
+        rmw_shrd,
         rmw_sub,
         rmw_xadd,
         rmw_xchg,
@@ -4112,36 +4121,25 @@ x86_emulate(
     case 0xc0 ... 0xc1: grp2: /* Grp2 */
         generate_exception_if(lock_prefix, EXC_UD);
 
-        if ( ops->rmw && dst.type == OP_MEM &&
-             (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val,
-                              dst.bytes, ctxt, ops)) != X86EMUL_OKAY )
-            goto done;
-        dst.orig_val = dst.val;
-
         switch ( modrm_reg & 7 )
         {
-        case 0: /* rol */
-            emulate_2op_SrcB("rol", src, dst, _regs.eflags);
-            break;
-        case 1: /* ror */
-            emulate_2op_SrcB("ror", src, dst, _regs.eflags);
-            break;
-        case 2: /* rcl */
-            emulate_2op_SrcB("rcl", src, dst, _regs.eflags);
-            break;
-        case 3: /* rcr */
-            emulate_2op_SrcB("rcr", src, dst, _regs.eflags);
-            break;
-        case 4: /* sal/shl */
-        case 6: /* sal/shl */
-            emulate_2op_SrcB("sal", src, dst, _regs.eflags);
-            break;
-        case 5: /* shr */
-            emulate_2op_SrcB("shr", src, dst, _regs.eflags);
-            break;
-        case 7: /* sar */
-            emulate_2op_SrcB("sar", src, dst, _regs.eflags);
-            break;
+#define GRP2(name, ext) \
+        case ext: \
+            if ( ops->rmw && dst.type == OP_MEM ) \
+                state->rmw = rmw_##name; \
+            else \
+                emulate_2op_SrcB(#name, src, dst, _regs.eflags); \
+            break
+
+        GRP2(rol, 0);
+        GRP2(ror, 1);
+        GRP2(rcl, 2);
+        GRP2(rcr, 3);
+        case 6: /* sal/shl alias */
+        GRP2(shl, 4);
+        GRP2(shr, 5);
+        GRP2(sar, 7);
+#undef GRP2
         }
         break;
 
@@ -6571,11 +6569,6 @@ x86_emulate(
 
         generate_exception_if(lock_prefix, EXC_UD);
 
-        if ( ops->rmw && dst.type == OP_MEM &&
-             (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val,
-                              dst.bytes, ctxt, ops)) != X86EMUL_OKAY )
-            goto done;
-
         if ( b & 1 )
             shift = _regs.cl;
         else
@@ -6584,6 +6577,14 @@ x86_emulate(
             src.reg = decode_gpr(&_regs, modrm_reg);
             src.val = truncate_word(*src.reg, dst.bytes);
         }
+
+        if ( ops->rmw && dst.type == OP_MEM )
+        {
+            ea.orig_val = shift;
+            state->rmw = b & 8 ? rmw_shrd : rmw_shld;
+            break;
+        }
+
         if ( (shift &= width - 1) == 0 )
             break;
         dst.orig_val = dst.val;
@@ -8730,6 +8731,11 @@ int x86_emul_rmw(
                                state->ea.val, dst, bytes, *eflags, \
                                "c" ((long)state->lock_prefix) ); \
         break
+#define SHIFT(op) \
+    case rmw_##op: \
+        ASSERT(!state->lock_prefix); \
+        _emulate_2op_SrcB(#op, state->ea.val, dst, bytes, *eflags); \
+        break
 
     BINOP(adc, );
     BINOP(add, );
@@ -8741,12 +8747,20 @@ int x86_emul_rmw(
      UNOP(inc);
      UNOP(neg);
     BINOP(or, );
+    SHIFT(rcl);
+    SHIFT(rcr);
+    SHIFT(rol);
+    SHIFT(ror);
+    SHIFT(sar);
     BINOP(sbb, );
+    SHIFT(shl);
+    SHIFT(shr);
     BINOP(sub, );
     BINOP(xor, );
 
 #undef UNOP
 #undef BINOP
+#undef SHIFT
 
     case rmw_not:
         switch ( state->op_bytes )
@@ -8772,6 +8786,20 @@ int x86_emul_rmw(
         }
         break;
 
+    case rmw_shld:
+        ASSERT(!state->lock_prefix);
+        _emulate_2op_SrcV_nobyte("shld",
+                                 state->ea.val, dst, bytes, *eflags,
+                                 "c" (state->ea.orig_val) );
+        break;
+
+    case rmw_shrd:
+        ASSERT(!state->lock_prefix);
+        _emulate_2op_SrcV_nobyte("shrd",
+                                 state->ea.val, dst, bytes, *eflags,
+                                 "c" (state->ea.orig_val) );
+        break;
+
     case rmw_xadd:
         switch ( state->op_bytes )
         {
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.