All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Beulich <jbeulich@suse.com>
To: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Wei Liu" <wl@xen.org>, "Roger Pau Monné" <roger.pau@citrix.com>
Subject: [PATCH v2 3/8] x86emul: split off opcode 0fc7 handling
Date: Wed, 15 Jun 2022 11:59:35 +0200	[thread overview]
Message-ID: <602c8889-1e75-52dd-135f-be6b6013d880@suse.com> (raw)
In-Reply-To: <7f5287ad-8442-6c53-d513-f9a8345c4857@suse.com>

There's a fair amount of sub-cases (with some yet to be implemented), so
a separate function seems warranted.

Code moved gets slightly adjusted in a few places, e.g. replacing EXC_*
by X86_EXC_* (such that EXC_* don't need to move as well; we want these
to be phased out anyway).

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

--- a/tools/fuzz/x86_instruction_emulator/Makefile
+++ b/tools/fuzz/x86_instruction_emulator/Makefile
@@ -35,7 +35,7 @@ x86.h := $(addprefix $(XEN_ROOT)/tools/i
 x86_emulate.h := x86-emulate.h x86_emulate/x86_emulate.h $(x86.h)
 
 OBJS := fuzz-emul.o x86-emulate.o
-OBJS += x86_emulate/0f01.o x86_emulate/0fae.o
+OBJS += x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o
 
 # x86-emulate.c will be implicit for both
 x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h) x86_emulate/private.h
--- a/tools/tests/x86_emulator/Makefile
+++ b/tools/tests/x86_emulator/Makefile
@@ -251,7 +251,7 @@ xop.h avx512f.h: simd-fma.c
 endif # 32-bit override
 
 OBJS := x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappers.o
-OBJS += x86_emulate/0f01.o x86_emulate/0fae.o
+OBJS += x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o
 
 $(TARGET): $(OBJS)
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
--- /dev/null
+++ b/xen/arch/x86/x86_emulate/0fc7.c
@@ -0,0 +1,210 @@
+/******************************************************************************
+ * 0fc7.c - helper for x86_emulate.c
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005-2007 Keir Fraser
+ * Copyright (c) 2005-2007 XenSource Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "private.h"
+
+/* Avoid namespace pollution. */
+#undef cmpxchg
+
+int x86emul_0fc7(struct x86_emulate_state *s,
+                 struct cpu_user_regs *regs,
+                 struct operand *dst,
+                 struct x86_emulate_ctxt *ctxt,
+                 const struct x86_emulate_ops *ops,
+                 mmval_t *mmvalp)
+{
+    int rc;
+
+    if ( s->ea.type == OP_REG )
+    {
+        bool __maybe_unused carry;
+
+        switch ( s->modrm_reg & 7 )
+        {
+        default:
+            return X86EMUL_UNRECOGNIZED;
+
+        case 6: /* rdrand */
+#ifdef HAVE_AS_RDRAND
+            generate_exception_if(s->vex.pfx >= vex_f3, X86_EXC_UD);
+            host_and_vcpu_must_have(rdrand);
+            *dst = s->ea;
+            switch ( s->op_bytes )
+            {
+            case 2:
+                asm ( "rdrand %w0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            default:
+# ifdef __x86_64__
+                asm ( "rdrand %k0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            case 8:
+# endif
+                asm ( "rdrand %0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            }
+            regs->eflags &= ~EFLAGS_MASK;
+            if ( carry )
+                regs->eflags |= X86_EFLAGS_CF;
+            break;
+#else
+            return X86EMUL_UNIMPLEMENTED;
+#endif
+
+        case 7: /* rdseed / rdpid */
+            if ( s->vex.pfx == vex_f3 ) /* rdpid */
+            {
+                uint64_t msr_val;
+
+                generate_exception_if(s->ea.type != OP_REG, X86_EXC_UD);
+                vcpu_must_have(rdpid);
+                fail_if(!ops->read_msr);
+                if ( (rc = ops->read_msr(MSR_TSC_AUX, &msr_val,
+                                         ctxt)) != X86EMUL_OKAY )
+                    goto done;
+                *dst = s->ea;
+                dst->val = msr_val;
+                dst->bytes = 4;
+                break;
+            }
+#ifdef HAVE_AS_RDSEED
+            generate_exception_if(s->vex.pfx >= vex_f3, X86_EXC_UD);
+            host_and_vcpu_must_have(rdseed);
+            *dst = s->ea;
+            switch ( s->op_bytes )
+            {
+            case 2:
+                asm ( "rdseed %w0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            default:
+# ifdef __x86_64__
+                asm ( "rdseed %k0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            case 8:
+# endif
+                asm ( "rdseed %0" ASM_FLAG_OUT(, "; setc %1")
+                      : "=r" (dst->val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
+                break;
+            }
+            regs->eflags &= ~EFLAGS_MASK;
+            if ( carry )
+                regs->eflags |= X86_EFLAGS_CF;
+            break;
+#endif
+        }
+    }
+    else
+    {
+        union {
+            uint32_t u32[2];
+            uint64_t u64[2];
+        } *old, *aux;
+
+        /* cmpxchg8b/cmpxchg16b */
+        generate_exception_if((s->modrm_reg & 7) != 1, X86_EXC_UD);
+        fail_if(!ops->cmpxchg);
+        if ( s->rex_prefix & REX_W )
+        {
+            host_and_vcpu_must_have(cx16);
+            generate_exception_if(!is_aligned(s->ea.mem.seg, s->ea.mem.off, 16,
+                                              ctxt, ops),
+                                  X86_EXC_GP, 0);
+            s->op_bytes = 16;
+        }
+        else
+        {
+            vcpu_must_have(cx8);
+            s->op_bytes = 8;
+        }
+
+        old = container_of(&mmvalp->ymm[0], typeof(*old), u64[0]);
+        aux = container_of(&mmvalp->ymm[2], typeof(*aux), u64[0]);
+
+        /* Get actual old value. */
+        if ( (rc = ops->read(s->ea.mem.seg, s->ea.mem.off, old, s->op_bytes,
+                             ctxt)) != X86EMUL_OKAY )
+            goto done;
+
+        /* Get expected value. */
+        if ( s->op_bytes == 8 )
+        {
+            aux->u32[0] = regs->eax;
+            aux->u32[1] = regs->edx;
+        }
+        else
+        {
+            aux->u64[0] = regs->r(ax);
+            aux->u64[1] = regs->r(dx);
+        }
+
+        if ( memcmp(old, aux, s->op_bytes) )
+        {
+        cmpxchgNb_failed:
+            /* Expected != actual: store actual to rDX:rAX and clear ZF. */
+            regs->r(ax) = s->op_bytes == 8 ? old->u32[0] : old->u64[0];
+            regs->r(dx) = s->op_bytes == 8 ? old->u32[1] : old->u64[1];
+            regs->eflags &= ~X86_EFLAGS_ZF;
+        }
+        else
+        {
+            /*
+             * Expected == actual: Get proposed value, attempt atomic cmpxchg
+             * and set ZF if successful.
+             */
+            if ( s->op_bytes == 8 )
+            {
+                aux->u32[0] = regs->ebx;
+                aux->u32[1] = regs->ecx;
+            }
+            else
+            {
+                aux->u64[0] = regs->r(bx);
+                aux->u64[1] = regs->r(cx);
+            }
+
+            switch ( rc = ops->cmpxchg(s->ea.mem.seg, s->ea.mem.off, old, aux,
+                                       s->op_bytes, s->lock_prefix, ctxt) )
+            {
+            case X86EMUL_OKAY:
+                regs->eflags |= X86_EFLAGS_ZF;
+                break;
+
+            case X86EMUL_CMPXCHG_FAILED:
+                rc = X86EMUL_OKAY;
+                goto cmpxchgNb_failed;
+
+            default:
+                goto done;
+            }
+        }
+    }
+
+    rc = X86EMUL_OKAY;
+
+ done:
+    return rc;
+}
--- a/xen/arch/x86/x86_emulate/Makefile
+++ b/xen/arch/x86/x86_emulate/Makefile
@@ -1,2 +1,3 @@
 obj-y += 0f01.o
 obj-y += 0fae.o
+obj-y += 0fc7.o
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -308,6 +308,14 @@ struct x86_emulate_state {
 #endif
 };
 
+typedef union {
+    uint64_t mmx;
+    uint64_t __attribute__ ((aligned(16))) xmm[2];
+    uint64_t __attribute__ ((aligned(32))) ymm[4];
+    uint64_t __attribute__ ((aligned(64))) zmm[8];
+    uint32_t data32[16];
+} mmval_t;
+
 struct x86_fxsr {
     uint16_t fcw;
     uint16_t fsw;
@@ -558,6 +566,12 @@ int x86emul_0fae(struct x86_emulate_stat
                  struct x86_emulate_ctxt *ctxt,
                  const struct x86_emulate_ops *ops,
                  enum x86_emulate_fpu_type *fpu_type);
+int x86emul_0fc7(struct x86_emulate_state *s,
+                 struct cpu_user_regs *regs,
+                 struct operand *dst,
+                 struct x86_emulate_ctxt *ctxt,
+                 const struct x86_emulate_ops *ops,
+                 mmval_t *mmvalp);
 
 static inline bool is_aligned(enum x86_segment seg, unsigned long offs,
                               unsigned int size, struct x86_emulate_ctxt *ctxt,
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -687,17 +687,9 @@ struct x87_env32 {
 };
 #endif
 
-typedef union {
-    uint64_t mmx;
-    uint64_t __attribute__ ((aligned(16))) xmm[2];
-    uint64_t __attribute__ ((aligned(32))) ymm[4];
-    uint64_t __attribute__ ((aligned(64))) zmm[8];
-    uint32_t data32[16];
-} mmval_t;
-
 /*
- * While proper alignment gets specified above, this doesn't get honored by
- * the compiler for automatic variables. Use this helper to instantiate a
+ * While proper alignment gets specified in mmval_t, this doesn't get honored
+ * by the compiler for automatic variables. Use this helper to instantiate a
  * suitably aligned variable, producing a pointer to access it.
  */
 #define DECLARE_ALIGNED(type, var)                                        \
@@ -7680,174 +7672,8 @@ x86_emulate(
 #endif /* X86EMUL_NO_SIMD */
 
     case X86EMUL_OPC(0x0f, 0xc7): /* Grp9 */
-    {
-        union {
-            uint32_t u32[2];
-            uint64_t u64[2];
-        } *old, *aux;
-
-        if ( ea.type == OP_REG )
-        {
-            bool __maybe_unused carry;
-
-            switch ( modrm_reg & 7 )
-            {
-            default:
-                goto unrecognized_insn;
-
-            case 6: /* rdrand */
-#ifdef HAVE_AS_RDRAND
-                generate_exception_if(rep_prefix(), EXC_UD);
-                host_and_vcpu_must_have(rdrand);
-                dst = ea;
-                switch ( op_bytes )
-                {
-                case 2:
-                    asm ( "rdrand %w0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                default:
-# ifdef __x86_64__
-                    asm ( "rdrand %k0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                case 8:
-# endif
-                    asm ( "rdrand %0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                }
-                _regs.eflags &= ~EFLAGS_MASK;
-                if ( carry )
-                    _regs.eflags |= X86_EFLAGS_CF;
-                break;
-#else
-                goto unimplemented_insn;
-#endif
-
-            case 7: /* rdseed / rdpid */
-                if ( repe_prefix() ) /* rdpid */
-                {
-                    generate_exception_if(ea.type != OP_REG, EXC_UD);
-                    vcpu_must_have(rdpid);
-                    fail_if(!ops->read_msr);
-                    if ( (rc = ops->read_msr(MSR_TSC_AUX, &msr_val,
-                                             ctxt)) != X86EMUL_OKAY )
-                        goto done;
-                    dst = ea;
-                    dst.val = msr_val;
-                    dst.bytes = 4;
-                    break;
-                }
-#ifdef HAVE_AS_RDSEED
-                generate_exception_if(rep_prefix(), EXC_UD);
-                host_and_vcpu_must_have(rdseed);
-                dst = ea;
-                switch ( op_bytes )
-                {
-                case 2:
-                    asm ( "rdseed %w0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                default:
-# ifdef __x86_64__
-                    asm ( "rdseed %k0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                case 8:
-# endif
-                    asm ( "rdseed %0" ASM_FLAG_OUT(, "; setc %1")
-                          : "=r" (dst.val), ASM_FLAG_OUT("=@ccc", "=qm") (carry) );
-                    break;
-                }
-                _regs.eflags &= ~EFLAGS_MASK;
-                if ( carry )
-                    _regs.eflags |= X86_EFLAGS_CF;
-                break;
-#endif
-            }
-            break;
-        }
-
-        /* cmpxchg8b/cmpxchg16b */
-        generate_exception_if((modrm_reg & 7) != 1, EXC_UD);
-        fail_if(!ops->cmpxchg);
-        if ( rex_prefix & REX_W )
-        {
-            host_and_vcpu_must_have(cx16);
-            generate_exception_if(!is_aligned(ea.mem.seg, ea.mem.off, 16,
-                                              ctxt, ops),
-                                  EXC_GP, 0);
-            op_bytes = 16;
-        }
-        else
-        {
-            vcpu_must_have(cx8);
-            op_bytes = 8;
-        }
-
-        old = container_of(&mmvalp->ymm[0], typeof(*old), u64[0]);
-        aux = container_of(&mmvalp->ymm[2], typeof(*aux), u64[0]);
-
-        /* Get actual old value. */
-        if ( (rc = ops->read(ea.mem.seg, ea.mem.off, old, op_bytes,
-                             ctxt)) != X86EMUL_OKAY )
-            goto done;
-
-        /* Get expected value. */
-        if ( !(rex_prefix & REX_W) )
-        {
-            aux->u32[0] = _regs.eax;
-            aux->u32[1] = _regs.edx;
-        }
-        else
-        {
-            aux->u64[0] = _regs.r(ax);
-            aux->u64[1] = _regs.r(dx);
-        }
-
-        if ( memcmp(old, aux, op_bytes) )
-        {
-        cmpxchgNb_failed:
-            /* Expected != actual: store actual to rDX:rAX and clear ZF. */
-            _regs.r(ax) = !(rex_prefix & REX_W) ? old->u32[0] : old->u64[0];
-            _regs.r(dx) = !(rex_prefix & REX_W) ? old->u32[1] : old->u64[1];
-            _regs.eflags &= ~X86_EFLAGS_ZF;
-        }
-        else
-        {
-            /*
-             * Expected == actual: Get proposed value, attempt atomic cmpxchg
-             * and set ZF if successful.
-             */
-            if ( !(rex_prefix & REX_W) )
-            {
-                aux->u32[0] = _regs.ebx;
-                aux->u32[1] = _regs.ecx;
-            }
-            else
-            {
-                aux->u64[0] = _regs.r(bx);
-                aux->u64[1] = _regs.r(cx);
-            }
-
-            switch ( rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old, aux,
-                                       op_bytes, lock_prefix, ctxt) )
-            {
-            case X86EMUL_OKAY:
-                _regs.eflags |= X86_EFLAGS_ZF;
-                break;
-
-            case X86EMUL_CMPXCHG_FAILED:
-                rc = X86EMUL_OKAY;
-                goto cmpxchgNb_failed;
-
-            default:
-                goto done;
-            }
-        }
-        break;
-    }
+        rc =  x86emul_0fc7(state, &_regs, &dst, ctxt, ops, mmvalp);
+        goto dispatch_from_helper;
 
     case X86EMUL_OPC(0x0f, 0xc8) ... X86EMUL_OPC(0x0f, 0xcf): /* bswap */
         dst.type = OP_REG;



  parent reply	other threads:[~2022-06-15  9:59 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-15  9:57 [PATCH v2 0/8] x86emul: a few small steps towards disintegration Jan Beulich
2022-06-15  9:58 ` [PATCH v2 1/8] x86emul: split off opcode 0f01 handling Jan Beulich
2023-03-28 14:57   ` Roger Pau Monné
2023-03-28 16:04     ` Jan Beulich
2022-06-15  9:59 ` [PATCH v2 2/8] x86emul: split off opcode 0fae handling Jan Beulich
2022-06-15  9:59 ` Jan Beulich [this message]
2022-06-15  9:59 ` [PATCH v2 4/8] x86emul: split off FPU opcode handling Jan Beulich
2022-06-15 10:00 ` [PATCH v2 5/8] x86emul: split off insn decoding Jan Beulich
2022-06-15 10:00 ` [PATCH v2 6/8] x86emul: move x86_emul_blk() to separate source file Jan Beulich
2022-06-15 10:01 ` [PATCH v2 7/8] x86emul: move various utility functions to separate source files Jan Beulich
2022-06-15 10:01 ` [PATCH v2 8/8] x86emul: build with -Os Jan Beulich
2022-07-06  7:31 ` [PATCH v2 0/8] x86emul: a few small steps towards disintegration Henry Wang
2022-07-06  9:05   ` Jan Beulich
2022-07-06  9:17     ` Henry Wang
2023-03-28 14:19 ` Roger Pau Monné
2023-03-28 14:48   ` Jan Beulich
2023-03-29 14:17     ` Roger Pau Monné
2023-03-30  7:53       ` Jan Beulich
2023-03-30  9:54         ` Roger Pau Monné
2023-03-30 11:40           ` Jan Beulich
2023-03-30 14:27             ` Roger Pau Monné
2023-03-30 15:14               ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=602c8889-1e75-52dd-135f-be6b6013d880@suse.com \
    --to=jbeulich@suse.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=roger.pau@citrix.com \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.