* [PATCH 1/7] x86emul: split off opcode 0f01 handling
2021-08-11 12:21 [PATCH 0/7] x86emul: a few small steps towards disintegration Jan Beulich
@ 2021-08-11 12:22 ` Jan Beulich
2021-08-11 12:23 ` [PATCH 2/7] x86emul: split off opcode 0fae handling Jan Beulich
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jan Beulich @ 2021-08-11 12:22 UTC (permalink / raw)
To: xen-devel; +Cc: Andrew Cooper, Wei Liu, Roger Pau Monné
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
@@ -11,10 +11,13 @@ endif
# Add libx86 to the build
vpath %.c $(XEN_ROOT)/xen/lib/x86
+.PHONY: x86_emulate
x86_emulate:
- [ -L $@ ] || ln -sf $(XEN_ROOT)/xen/arch/x86/$@
+ mkdir -p $@
+ ln -sf $(XEN_ROOT)/xen/arch/x86/$@/*.[ch] $@/
-x86_emulate/%: x86_emulate ;
+x86_emulate/%.c: x86_emulate ;
+x86_emulate/%.h: x86_emulate ;
x86-emulate.c x86-emulate.h wrappers.c: %:
[ -L $* ] || ln -sf $(XEN_ROOT)/tools/tests/x86_emulator/$*
@@ -31,18 +34,27 @@ x86.h := $(addprefix $(XEN_ROOT)/tools/i
cpuid.h cpuid-autogen.h)
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.c will be implicit for both
-x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h)
+x86-emulate.o x86-emulate-cov.o: x86_emulate/x86_emulate.c $(x86_emulate.h) x86_emulate/private.h
fuzz-emul.o fuzz-emulate-cov.o cpuid.o wrappers.o: $(x86_emulate.h)
-x86-insn-fuzzer.a: fuzz-emul.o x86-emulate.o cpuid.o
+$(filter x86_emulate/%.o,$(OBJS)): x86_emulate/%.o: x86_emulate/%.c x86_emulate/private.h $(x86_emulate.h)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) -c -o $@ $< $(APPEND_CFLAGS)
+
+$(patsubst %.o,%-cov.o,$(filter x86_emulate/%.o,$(OBJS))): x86_emulate/%-cov.o: x86_emulate/%.c x86_emulate/private.h $(x86_emulate.h)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) $(GCOV_FLAGS) -c -o $@ $< $(APPEND_CFLAGS)
+
+x86-insn-fuzzer.a: $(OBJS) cpuid.o
$(AR) rc $@ $^
-afl-harness: afl-harness.o fuzz-emul.o x86-emulate.o cpuid.o wrappers.o
+afl-harness: afl-harness.o $(OBJS) cpuid.o wrappers.o
$(CC) $(CFLAGS) $^ -o $@
-afl-harness-cov: afl-harness-cov.o fuzz-emul-cov.o x86-emulate-cov.o cpuid.o wrappers.o
+afl-harness-cov: afl-harness-cov.o $(patsubst %.o,%-cov.o,$(OBJS)) cpuid.o wrappers.o
$(CC) $(CFLAGS) $(GCOV_FLAGS) $^ -o $@
# Common targets
--- a/tools/tests/x86_emulator/Makefile
+++ b/tools/tests/x86_emulator/Makefile
@@ -29,7 +29,7 @@ OPMASK := avx512f avx512dq avx512bw
ifeq ($(origin XEN_COMPILE_ARCH),override)
-HOSTCFLAGS += -m32
+HOSTCFLAGS += -m32 -I..
else
@@ -250,7 +250,10 @@ xop.h avx512f.h: simd-fma.c
endif # 32-bit override
-$(TARGET): x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappers.o
+OBJS := x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappers.o
+OBJS += x86_emulate/0f01.o
+
+$(TARGET): $(OBJS)
$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
.PHONY: clean
@@ -274,8 +277,10 @@ else
run32 clean32: %32: %
endif
+.PHONY: x86_emulate
x86_emulate:
- [ -L $@ ] || ln -sf $(XEN_ROOT)/xen/arch/x86/$@
+ mkdir -p $@
+ ln -sf $(XEN_ROOT)/xen/arch/x86/$@/*.[ch] $@/
x86_emulate/%: x86_emulate ;
@@ -287,13 +292,13 @@ x86.h := $(addprefix $(XEN_ROOT)/tools/i
x86-vendors.h x86-defns.h msr-index.h) \
$(addprefix $(XEN_ROOT)/tools/include/xen/lib/x86/, \
cpuid.h cpuid-autogen.h)
-x86_emulate.h := x86-emulate.h x86_emulate/x86_emulate.h $(x86.h)
+x86_emulate.h := x86-emulate.h x86_emulate/x86_emulate.h x86_emulate/private.h $(x86.h)
-x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappers.o: %.o: %.c $(x86_emulate.h)
+$(OBJS): %.o: %.c $(x86_emulate.h)
$(HOSTCC) $(HOSTCFLAGS) -c -g -o $@ $<
x86-emulate.o: x86_emulate/x86_emulate.c
-x86-emulate.o: HOSTCFLAGS += -D__XEN_TOOLS__
+x86-emulate.o x86_emulate/%.o: HOSTCFLAGS += -D__XEN_TOOLS__
# In order for our custom .type assembler directives to reliably land after
# gcc's, we need to keep it from re-ordering top-level constructs.
--- a/tools/tests/x86_emulator/x86-emulate.c
+++ b/tools/tests/x86_emulator/x86-emulate.c
@@ -22,11 +22,9 @@
/* For generic assembly code: use macros to define operation/operand sizes. */
#ifdef __i386__
-# define r(name) e ## name
# define __OS "l" /* Operation Suffix */
# define __OP "e" /* Operand Prefix */
#else
-# define r(name) r ## name
# define __OS "q" /* Operation Suffix */
# define __OP "r" /* Operand Prefix */
#endif
@@ -265,12 +263,12 @@ void emul_test_put_fpu(
static uint32_t pkru;
-static unsigned int rdpkru(void)
+unsigned int rdpkru(void)
{
return pkru;
}
-static void wrpkru(unsigned int val)
+void wrpkru(unsigned int val)
{
pkru = val;
}
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -1,3 +1,6 @@
+#ifndef X86_EMULATE_H
+#define X86_EMULATE_H
+
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
@@ -128,6 +131,9 @@ static inline bool xcr0_mask(uint64_t ma
return cpu_has_xsave && ((xgetbv(0) & mask) == mask);
}
+unsigned int rdpkru(void);
+void wrpkru(unsigned int val);
+
#define cache_line_size() (cp.basic.clflush_size * 8)
#define cpu_has_fpu cp.basic.fpu
#define cpu_has_mmx cp.basic.mmx
@@ -205,3 +211,5 @@ void emul_test_put_fpu(
struct x86_emulate_ctxt *ctxt,
enum x86_emulate_fpu_type backout,
const struct x86_emul_fpu_aux *aux);
+
+#endif /* X86_EMULATE_H */
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -7,6 +7,7 @@ obj-y += mm/
obj-$(CONFIG_XENOPROF) += oprofile/
obj-$(CONFIG_PV) += pv/
obj-y += x86_64/
+obj-y += x86_emulate/
alternative-y := alternative.init.o
alternative-$(CONFIG_LIVEPATCH) :=
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -23,8 +23,6 @@
#undef cpuid
#undef wbinvd
-#define r(name) r ## name
-
#define cpu_has_amd_erratum(nr) \
cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr)
@@ -45,12 +43,6 @@
#define FXSAVE_AREA current->arch.fpu_ctxt
-#ifndef CONFIG_HVM
-# define X86EMUL_NO_FPU
-# define X86EMUL_NO_MMX
-# define X86EMUL_NO_SIMD
-#endif
-
#include "x86_emulate/x86_emulate.c"
int x86emul_read_xcr(unsigned int reg, uint64_t *val,
--- /dev/null
+++ b/xen/arch/x86/x86_emulate/0f01.c
@@ -0,0 +1,349 @@
+/******************************************************************************
+ * 0f01.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"
+
+#define ad_bytes (s->ad_bytes) /* for truncate_ea() */
+
+int x86emul_0f01(struct x86_emulate_state *s,
+ struct cpu_user_regs *regs,
+ struct operand *dst,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ enum x86_segment seg = (s->modrm_reg & 1) ? x86_seg_idtr : x86_seg_gdtr;
+ int rc;
+
+ switch ( s->modrm )
+ {
+ unsigned long base, limit, cr0, cr0w, cr4;
+ struct segment_register sreg;
+ uint64_t msr_val;
+
+ case 0xca: /* clac */
+ case 0xcb: /* stac */
+ vcpu_must_have(smap);
+ generate_exception_if(s->vex.pfx || !mode_ring0(), X86_EXC_UD);
+
+ regs->eflags &= ~X86_EFLAGS_AC;
+ if ( s->modrm == 0xcb )
+ regs->eflags |= X86_EFLAGS_AC;
+ break;
+
+ case 0xd0: /* xgetbv */
+ generate_exception_if(s->vex.pfx, X86_EXC_UD);
+ if ( !ops->read_cr || !ops->read_xcr ||
+ ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
+ cr4 = 0;
+ generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD);
+ rc = ops->read_xcr(regs->ecx, &msr_val, ctxt);
+ if ( rc != X86EMUL_OKAY )
+ goto done;
+ regs->r(ax) = (uint32_t)msr_val;
+ regs->r(dx) = msr_val >> 32;
+ break;
+
+ case 0xd1: /* xsetbv */
+ generate_exception_if(s->vex.pfx, X86_EXC_UD);
+ if ( !ops->read_cr || !ops->write_xcr ||
+ ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
+ cr4 = 0;
+ generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), X86_EXC_UD);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ rc = ops->write_xcr(regs->ecx,
+ regs->eax | ((uint64_t)regs->edx << 32), ctxt);
+ if ( rc != X86EMUL_OKAY )
+ goto done;
+ break;
+
+ case 0xd4: /* vmfunc */
+ generate_exception_if(s->vex.pfx, X86_EXC_UD);
+ fail_if(!ops->vmfunc);
+ if ( (rc = ops->vmfunc(ctxt)) != X86EMUL_OKAY )
+ goto done;
+ break;
+
+ case 0xd5: /* xend */
+ generate_exception_if(s->vex.pfx, X86_EXC_UD);
+ generate_exception_if(!vcpu_has_rtm(), X86_EXC_UD);
+ generate_exception_if(vcpu_has_rtm(), X86_EXC_GP, 0);
+ break;
+
+ case 0xd6: /* xtest */
+ generate_exception_if(s->vex.pfx, X86_EXC_UD);
+ generate_exception_if(!vcpu_has_rtm() && !vcpu_has_hle(),
+ X86_EXC_UD);
+ /* Neither HLE nor RTM can be active when we get here. */
+ regs->eflags |= X86_EFLAGS_ZF;
+ break;
+
+ case 0xdf: /* invlpga */
+ fail_if(!ops->read_msr);
+ if ( (rc = ops->read_msr(MSR_EFER,
+ &msr_val, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ /* Finding SVME set implies vcpu_has_svm(). */
+ generate_exception_if(!(msr_val & EFER_SVME) ||
+ !in_protmode(ctxt, ops), X86_EXC_UD);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ fail_if(!ops->tlb_op);
+ if ( (rc = ops->tlb_op(x86emul_invlpga, truncate_ea(regs->r(ax)),
+ regs->ecx, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ break;
+
+ case 0xe8:
+ switch ( s->vex.pfx )
+ {
+ case vex_none: /* serialize */
+ host_and_vcpu_must_have(serialize);
+ asm volatile ( ".byte 0x0f, 0x01, 0xe8" );
+ break;
+ case vex_f2: /* xsusldtrk */
+ vcpu_must_have(tsxldtrk);
+ /*
+ * We're never in a transactional region when coming here
+ * - nothing else to do.
+ */
+ break;
+ default:
+ return X86EMUL_UNIMPLEMENTED;
+ }
+ break;
+
+ case 0xe9:
+ switch ( s->vex.pfx )
+ {
+ case vex_f2: /* xresldtrk */
+ vcpu_must_have(tsxldtrk);
+ /*
+ * We're never in a transactional region when coming here
+ * - nothing else to do.
+ */
+ break;
+ default:
+ return X86EMUL_UNIMPLEMENTED;
+ }
+ break;
+
+ case 0xee:
+ switch ( s->vex.pfx )
+ {
+ case vex_none: /* rdpkru */
+ if ( !ops->read_cr ||
+ ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
+ cr4 = 0;
+ generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD);
+ generate_exception_if(regs->ecx, X86_EXC_GP, 0);
+ regs->r(ax) = rdpkru();
+ regs->r(dx) = 0;
+ break;
+ default:
+ return X86EMUL_UNIMPLEMENTED;
+ }
+ break;
+
+ case 0xef:
+ switch ( s->vex.pfx )
+ {
+ case vex_none: /* wrpkru */
+ if ( !ops->read_cr ||
+ ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
+ cr4 = 0;
+ generate_exception_if(!(cr4 & X86_CR4_PKE), X86_EXC_UD);
+ generate_exception_if(regs->ecx | regs->edx, X86_EXC_GP, 0);
+ wrpkru(regs->eax);
+ break;
+ default:
+ return X86EMUL_UNIMPLEMENTED;
+ }
+ break;
+
+ case 0xf8: /* swapgs */
+ generate_exception_if(!mode_64bit(), X86_EXC_UD);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ fail_if(!ops->read_segment || !ops->read_msr ||
+ !ops->write_segment || !ops->write_msr);
+ if ( (rc = ops->read_segment(x86_seg_gs, &sreg,
+ ctxt)) != X86EMUL_OKAY ||
+ (rc = ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val,
+ ctxt)) != X86EMUL_OKAY ||
+ (rc = ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base,
+ ctxt)) != X86EMUL_OKAY )
+ goto done;
+ sreg.base = msr_val;
+ if ( (rc = ops->write_segment(x86_seg_gs, &sreg,
+ ctxt)) != X86EMUL_OKAY )
+ {
+ /* Best effort unwind (i.e. no error checking). */
+ ops->write_msr(MSR_SHADOW_GS_BASE, msr_val, ctxt);
+ goto done;
+ }
+ break;
+
+ case 0xf9: /* rdtscp */
+ fail_if(ops->read_msr == NULL);
+ if ( (rc = ops->read_msr(MSR_TSC_AUX,
+ &msr_val, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ regs->r(cx) = (uint32_t)msr_val;
+ return X86EMUL_rdtsc;
+
+ case 0xfc: /* clzero */
+ {
+ unsigned long zero = 0;
+
+ vcpu_must_have(clzero);
+
+ base = ad_bytes == 8 ? regs->r(ax) :
+ ad_bytes == 4 ? regs->eax : regs->ax;
+ limit = ctxt->cpuid->basic.clflush_size * 8;
+ generate_exception_if(limit < sizeof(long) ||
+ (limit & (limit - 1)), X86_EXC_UD);
+ base &= ~(limit - 1);
+ if ( ops->rep_stos )
+ {
+ unsigned long nr_reps = limit / sizeof(zero);
+
+ rc = ops->rep_stos(&zero, s->ea.mem.seg, base, sizeof(zero),
+ &nr_reps, ctxt);
+ if ( rc == X86EMUL_OKAY )
+ {
+ base += nr_reps * sizeof(zero);
+ limit -= nr_reps * sizeof(zero);
+ }
+ else if ( rc != X86EMUL_UNHANDLEABLE )
+ goto done;
+ }
+ fail_if(limit && !ops->write);
+ while ( limit )
+ {
+ rc = ops->write(s->ea.mem.seg, base, &zero, sizeof(zero), ctxt);
+ if ( rc != X86EMUL_OKAY )
+ goto done;
+ base += sizeof(zero);
+ limit -= sizeof(zero);
+ }
+ break;
+ }
+
+#define _GRP7(mod, reg) \
+ (((mod) << 6) | ((reg) << 3)) ... (((mod) << 6) | ((reg) << 3) | 7)
+#define GRP7_MEM(reg) _GRP7(0, reg): case _GRP7(1, reg): case _GRP7(2, reg)
+#define GRP7_ALL(reg) GRP7_MEM(reg): case _GRP7(3, reg)
+
+ case GRP7_MEM(0): /* sgdt */
+ case GRP7_MEM(1): /* sidt */
+ ASSERT(s->ea.type == OP_MEM);
+ generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0);
+ fail_if(!ops->read_segment || !ops->write);
+ if ( (rc = ops->read_segment(seg, &sreg, ctxt)) )
+ goto done;
+ if ( mode_64bit() )
+ s->op_bytes = 8;
+ else if ( s->op_bytes == 2 )
+ {
+ sreg.base &= 0xffffff;
+ s->op_bytes = 4;
+ }
+ if ( (rc = ops->write(s->ea.mem.seg, s->ea.mem.off, &sreg.limit,
+ 2, ctxt)) != X86EMUL_OKAY ||
+ (rc = ops->write(s->ea.mem.seg, truncate_ea(s->ea.mem.off + 2),
+ &sreg.base, s->op_bytes, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ break;
+
+ case GRP7_MEM(2): /* lgdt */
+ case GRP7_MEM(3): /* lidt */
+ ASSERT(s->ea.type == OP_MEM);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ fail_if(ops->write_segment == NULL);
+ memset(&sreg, 0, sizeof(sreg));
+ if ( (rc = read_ulong(s->ea.mem.seg, s->ea.mem.off,
+ &limit, 2, ctxt, ops)) ||
+ (rc = read_ulong(s->ea.mem.seg, truncate_ea(s->ea.mem.off + 2),
+ &base, mode_64bit() ? 8 : 4, ctxt, ops)) )
+ goto done;
+ generate_exception_if(!is_canonical_address(base), X86_EXC_GP, 0);
+ sreg.base = base;
+ sreg.limit = limit;
+ if ( !mode_64bit() && s->op_bytes == 2 )
+ sreg.base &= 0xffffff;
+ if ( (rc = ops->write_segment(seg, &sreg, ctxt)) )
+ goto done;
+ break;
+
+ case GRP7_ALL(4): /* smsw */
+ generate_exception_if(umip_active(ctxt, ops), X86_EXC_GP, 0);
+ if ( s->ea.type == OP_MEM )
+ {
+ fail_if(!ops->write);
+ s->desc |= Mov; /* force writeback */
+ s->ea.bytes = 2;
+ }
+ else
+ s->ea.bytes = s->op_bytes;
+ *dst = s->ea;
+ fail_if(ops->read_cr == NULL);
+ if ( (rc = ops->read_cr(0, &dst->val, ctxt)) )
+ goto done;
+ break;
+
+ case GRP7_ALL(6): /* lmsw */
+ fail_if(ops->read_cr == NULL);
+ fail_if(ops->write_cr == NULL);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ if ( (rc = ops->read_cr(0, &cr0, ctxt)) )
+ goto done;
+ if ( s->ea.type == OP_REG )
+ cr0w = *s->ea.reg;
+ else if ( (rc = read_ulong(s->ea.mem.seg, s->ea.mem.off,
+ &cr0w, 2, ctxt, ops)) )
+ goto done;
+ /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */
+ cr0 = (cr0 & ~0xe) | (cr0w & 0xf);
+ if ( (rc = ops->write_cr(0, cr0, ctxt)) )
+ goto done;
+ break;
+
+ case GRP7_MEM(7): /* invlpg */
+ ASSERT(s->ea.type == OP_MEM);
+ generate_exception_if(!mode_ring0(), X86_EXC_GP, 0);
+ fail_if(!ops->tlb_op);
+ if ( (rc = ops->tlb_op(x86emul_invlpg, s->ea.mem.off, s->ea.mem.seg,
+ ctxt)) != X86EMUL_OKAY )
+ goto done;
+ break;
+
+#undef GRP7_ALL
+#undef GRP7_MEM
+#undef _GRP7
+
+ default:
+ return X86EMUL_UNIMPLEMENTED;
+ }
+
+ rc = X86EMUL_OKAY;
+
+ done:
+ return rc;
+}
--- /dev/null
+++ b/xen/arch/x86/x86_emulate/Makefile
@@ -0,0 +1 @@
+obj-y += 0f01.o
--- /dev/null
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -0,0 +1,531 @@
+/******************************************************************************
+ * private.h - interface between x86_emulate.c and its helpers
+ *
+ * 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/>.
+ */
+
+#ifdef __XEN__
+
+# include <xen/kernel.h>
+# include <asm/msr-index.h>
+# include <asm/x86_emulate.h>
+
+# ifndef CONFIG_HVM
+# define X86EMUL_NO_FPU
+# define X86EMUL_NO_MMX
+# define X86EMUL_NO_SIMD
+# endif
+
+#else /* !__XEN__ */
+# include "x86-emulate.h"
+#endif
+
+#ifdef __i386__
+# define mode_64bit() false
+# define r(name) e ## name
+#else
+# define mode_64bit() (ctxt->addr_size == 64)
+# define r(name) r ## name
+#endif
+
+/* Operand sizes: 8-bit operands or specified/overridden size. */
+#define ByteOp (1<<0) /* 8-bit operands. */
+/* Destination operand type. */
+#define DstNone (0<<1) /* No destination operand. */
+#define DstImplicit (0<<1) /* Destination operand is implicit in the opcode. */
+#define DstBitBase (1<<1) /* Memory operand, bit string. */
+#define DstReg (2<<1) /* Register operand. */
+#define DstEax DstReg /* Register EAX (aka DstReg with no ModRM) */
+#define DstMem (3<<1) /* Memory operand. */
+#define DstMask (3<<1)
+/* Source operand type. */
+#define SrcNone (0<<3) /* No source operand. */
+#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
+#define SrcReg (1<<3) /* Register operand. */
+#define SrcEax SrcReg /* Register EAX (aka SrcReg with no ModRM) */
+#define SrcMem (2<<3) /* Memory operand. */
+#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
+#define SrcImm (4<<3) /* Immediate operand. */
+#define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */
+#define SrcImm16 (6<<3) /* 16-bit zero-extended immediate operand. */
+#define SrcMask (7<<3)
+/* Generic ModRM decode. */
+#define ModRM (1<<6)
+/* vSIB addressing mode (0f38 extension opcodes only), aliasing ModRM. */
+#define vSIB (1<<6)
+/* Destination is only written; never read. */
+#define Mov (1<<7)
+/* VEX/EVEX (SIMD only): 2nd source operand unused (must be all ones) */
+#define TwoOp Mov
+/* All operands are implicit in the opcode. */
+#define ImplicitOps (DstImplicit|SrcImplicit)
+
+typedef uint8_t opcode_desc_t;
+
+/* Type, address-of, and value of an instruction's operand. */
+struct operand {
+ enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
+ unsigned int bytes;
+
+ /* Operand value. */
+ unsigned long val;
+
+ /* Original operand value. */
+ unsigned long orig_val;
+
+ /* OP_REG: Pointer to register field. */
+ unsigned long *reg;
+
+ /* OP_MEM: Segment and offset. */
+ struct {
+ enum x86_segment seg;
+ unsigned long off;
+ } mem;
+};
+
+#define REX_PREFIX 0x40
+#define REX_B 0x01
+#define REX_X 0x02
+#define REX_R 0x04
+#define REX_W 0x08
+
+enum simd_opsize {
+ simd_none,
+
+ /*
+ * Ordinary packed integers:
+ * - 64 bits without prefix 66 (MMX)
+ * - 128 bits with prefix 66 (SSEn)
+ * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
+ */
+ simd_packed_int,
+
+ /*
+ * Ordinary packed/scalar floating point:
+ * - 128 bits without prefix or with prefix 66 (SSEn)
+ * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
+ * - 32 bits with prefix F3 (scalar single)
+ * - 64 bits with prefix F2 (scalar doubgle)
+ */
+ simd_any_fp,
+
+ /*
+ * Packed floating point:
+ * - 128 bits without prefix or with prefix 66 (SSEn)
+ * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
+ */
+ simd_packed_fp,
+
+ /*
+ * Single precision packed/scalar floating point:
+ * - 128 bits without prefix (SSEn)
+ * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
+ * - 32 bits with prefix F3 (scalar)
+ */
+ simd_single_fp,
+
+ /*
+ * Scalar floating point:
+ * - 32 bits with low opcode bit clear (scalar single)
+ * - 64 bits with low opcode bit set (scalar double)
+ */
+ simd_scalar_opc,
+
+ /*
+ * Scalar floating point:
+ * - 32/64 bits depending on VEX.W/EVEX.W
+ */
+ simd_scalar_vexw,
+
+ /*
+ * 128 bits of integer or floating point data, with no further
+ * formatting information, or with it encoded by EVEX.W.
+ */
+ simd_128,
+
+ /*
+ * 256 bits of integer or floating point data, with formatting
+ * encoded by EVEX.W.
+ */
+ simd_256,
+
+ /* Operand size encoded in non-standard way. */
+ simd_other
+};
+typedef uint8_t simd_opsize_t;
+
+#define vex_none 0
+
+enum vex_opcx {
+ vex_0f = vex_none + 1,
+ vex_0f38,
+ vex_0f3a,
+};
+
+enum vex_pfx {
+ vex_66 = vex_none + 1,
+ vex_f3,
+ vex_f2
+};
+
+union vex {
+ uint8_t raw[2];
+ struct { /* SDM names */
+ uint8_t opcx:5; /* mmmmm */
+ uint8_t b:1; /* B */
+ uint8_t x:1; /* X */
+ uint8_t r:1; /* R */
+ uint8_t pfx:2; /* pp */
+ uint8_t l:1; /* L */
+ uint8_t reg:4; /* vvvv */
+ uint8_t w:1; /* W */
+ };
+};
+
+union evex {
+ uint8_t raw[3];
+ struct { /* SDM names */
+ uint8_t opcx:2; /* mm */
+ uint8_t mbz:2;
+ uint8_t R:1; /* R' */
+ uint8_t b:1; /* B */
+ uint8_t x:1; /* X */
+ uint8_t r:1; /* R */
+ uint8_t pfx:2; /* pp */
+ uint8_t mbs:1;
+ uint8_t reg:4; /* vvvv */
+ uint8_t w:1; /* W */
+ uint8_t opmsk:3; /* aaa */
+ uint8_t RX:1; /* V' */
+ uint8_t brs:1; /* b */
+ uint8_t lr:2; /* L'L */
+ uint8_t z:1; /* z */
+ };
+};
+
+struct x86_emulate_state {
+ unsigned int op_bytes, ad_bytes;
+
+ enum {
+ ext_none = vex_none,
+ ext_0f = vex_0f,
+ ext_0f38 = vex_0f38,
+ ext_0f3a = vex_0f3a,
+ /*
+ * For XOP use values such that the respective instruction field
+ * can be used without adjustment.
+ */
+ ext_8f08 = 8,
+ ext_8f09,
+ ext_8f0a,
+ } ext;
+ enum {
+ rmw_NONE,
+ rmw_adc,
+ rmw_add,
+ rmw_and,
+ rmw_btc,
+ rmw_btr,
+ rmw_bts,
+ rmw_dec,
+ rmw_inc,
+ 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,
+ rmw_xor,
+ } rmw;
+ enum {
+ blk_NONE,
+ blk_enqcmd,
+#ifndef X86EMUL_NO_FPU
+ blk_fld, /* FLDENV, FRSTOR */
+ blk_fst, /* FNSTENV, FNSAVE */
+#endif
+#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \
+ !defined(X86EMUL_NO_SIMD)
+ blk_fxrstor,
+ blk_fxsave,
+#endif
+ blk_movdir,
+ } blk;
+ uint8_t modrm, modrm_mod, modrm_reg, modrm_rm;
+ uint8_t sib_index, sib_scale;
+ uint8_t rex_prefix;
+ bool lock_prefix;
+ bool not_64bit; /* Instruction not available in 64bit. */
+ bool fpu_ctrl; /* Instruction is an FPU control one. */
+ opcode_desc_t desc;
+ union vex vex;
+ union evex evex;
+ enum simd_opsize simd_size;
+
+ /*
+ * Data operand effective address (usually computed from ModRM).
+ * Default is a memory operand relative to segment DS.
+ */
+ struct operand ea;
+
+ /* Immediate operand values, if any. Use otherwise unused fields. */
+#define imm1 ea.val
+#define imm2 ea.orig_val
+
+ unsigned long ip;
+ struct cpu_user_regs *regs;
+
+#ifndef NDEBUG
+ /*
+ * Track caller of x86_decode_insn() to spot missing as well as
+ * premature calls to x86_emulate_free_state().
+ */
+ void *caller;
+#endif
+};
+
+/*
+ * Externally visible return codes from x86_emulate() are non-negative.
+ * Use negative values for internal state change indicators from helpers
+ * to the main function.
+ */
+#define X86EMUL_rdtsc (-1)
+
+/*
+ * These EFLAGS bits are restored from saved value during emulation, and
+ * any changes are written back to the saved value after emulation.
+ */
+#define EFLAGS_MASK (X86_EFLAGS_OF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \
+ X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF)
+
+/*
+ * These EFLAGS bits are modifiable (by POPF and IRET), possibly subject
+ * to further CPL and IOPL constraints.
+ */
+#define EFLAGS_MODIFIABLE (X86_EFLAGS_ID | X86_EFLAGS_AC | X86_EFLAGS_RF | \
+ X86_EFLAGS_NT | X86_EFLAGS_IOPL | X86_EFLAGS_DF | \
+ X86_EFLAGS_IF | X86_EFLAGS_TF | EFLAGS_MASK)
+
+#define truncate_word(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_word((ea), ad_bytes)
+
+#define fail_if(p) \
+do { \
+ rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \
+ if ( rc ) goto done; \
+} while (0)
+
+#define EXPECT(p) \
+do { \
+ if ( unlikely(!(p)) ) \
+ { \
+ ASSERT_UNREACHABLE(); \
+ goto unhandleable; \
+ } \
+} while (0)
+
+static inline int mkec(uint8_t e, int32_t ec, ...)
+{
+ return (e < 32 && ((1u << e) & X86_EXC_HAVE_EC)) ? ec : X86_EVENT_NO_EC;
+}
+
+#define generate_exception_if(p, e, ec...) \
+({ if ( (p) ) { \
+ x86_emul_hw_exception(e, mkec(e, ##ec, 0), ctxt); \
+ rc = X86EMUL_EXCEPTION; \
+ goto done; \
+ } \
+})
+
+#define generate_exception(e, ec...) generate_exception_if(true, e, ##ec)
+
+static inline bool
+in_realmode(
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ unsigned long cr0;
+ int rc;
+
+ if ( ops->read_cr == NULL )
+ return 0;
+
+ rc = ops->read_cr(0, &cr0, ctxt);
+ return (!rc && !(cr0 & X86_CR0_PE));
+}
+
+static inline bool
+in_protmode(
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & X86_EFLAGS_VM));
+}
+
+#define mode_ring0() ({ \
+ int _cpl = x86emul_get_cpl(ctxt, ops); \
+ fail_if(_cpl < 0); \
+ (_cpl == 0); \
+})
+
+#define vcpu_has_fpu() (ctxt->cpuid->basic.fpu)
+#define vcpu_has_sep() (ctxt->cpuid->basic.sep)
+#define vcpu_has_cx8() (ctxt->cpuid->basic.cx8)
+#define vcpu_has_cmov() (ctxt->cpuid->basic.cmov)
+#define vcpu_has_clflush() (ctxt->cpuid->basic.clflush)
+#define vcpu_has_mmx() (ctxt->cpuid->basic.mmx)
+#define vcpu_has_fxsr() (ctxt->cpuid->basic.fxsr)
+#define vcpu_has_sse() (ctxt->cpuid->basic.sse)
+#define vcpu_has_sse2() (ctxt->cpuid->basic.sse2)
+#define vcpu_has_sse3() (ctxt->cpuid->basic.sse3)
+#define vcpu_has_pclmulqdq() (ctxt->cpuid->basic.pclmulqdq)
+#define vcpu_has_ssse3() (ctxt->cpuid->basic.ssse3)
+#define vcpu_has_fma() (ctxt->cpuid->basic.fma)
+#define vcpu_has_cx16() (ctxt->cpuid->basic.cx16)
+#define vcpu_has_sse4_1() (ctxt->cpuid->basic.sse4_1)
+#define vcpu_has_sse4_2() (ctxt->cpuid->basic.sse4_2)
+#define vcpu_has_movbe() (ctxt->cpuid->basic.movbe)
+#define vcpu_has_popcnt() (ctxt->cpuid->basic.popcnt)
+#define vcpu_has_aesni() (ctxt->cpuid->basic.aesni)
+#define vcpu_has_avx() (ctxt->cpuid->basic.avx)
+#define vcpu_has_f16c() (ctxt->cpuid->basic.f16c)
+#define vcpu_has_rdrand() (ctxt->cpuid->basic.rdrand)
+
+#define vcpu_has_mmxext() (ctxt->cpuid->extd.mmxext || vcpu_has_sse())
+#define vcpu_has_3dnow_ext() (ctxt->cpuid->extd._3dnowext)
+#define vcpu_has_3dnow() (ctxt->cpuid->extd._3dnow)
+#define vcpu_has_lahf_lm() (ctxt->cpuid->extd.lahf_lm)
+#define vcpu_has_cr8_legacy() (ctxt->cpuid->extd.cr8_legacy)
+#define vcpu_has_lzcnt() (ctxt->cpuid->extd.abm)
+#define vcpu_has_sse4a() (ctxt->cpuid->extd.sse4a)
+#define vcpu_has_misalignsse() (ctxt->cpuid->extd.misalignsse)
+#define vcpu_has_xop() (ctxt->cpuid->extd.xop)
+#define vcpu_has_fma4() (ctxt->cpuid->extd.fma4)
+#define vcpu_has_tbm() (ctxt->cpuid->extd.tbm)
+#define vcpu_has_clzero() (ctxt->cpuid->extd.clzero)
+#define vcpu_has_wbnoinvd() (ctxt->cpuid->extd.wbnoinvd)
+
+#define vcpu_has_bmi1() (ctxt->cpuid->feat.bmi1)
+#define vcpu_has_hle() (ctxt->cpuid->feat.hle)
+#define vcpu_has_avx2() (ctxt->cpuid->feat.avx2)
+#define vcpu_has_bmi2() (ctxt->cpuid->feat.bmi2)
+#define vcpu_has_invpcid() (ctxt->cpuid->feat.invpcid)
+#define vcpu_has_rtm() (ctxt->cpuid->feat.rtm)
+#define vcpu_has_mpx() (ctxt->cpuid->feat.mpx)
+#define vcpu_has_avx512f() (ctxt->cpuid->feat.avx512f)
+#define vcpu_has_avx512dq() (ctxt->cpuid->feat.avx512dq)
+#define vcpu_has_rdseed() (ctxt->cpuid->feat.rdseed)
+#define vcpu_has_adx() (ctxt->cpuid->feat.adx)
+#define vcpu_has_smap() (ctxt->cpuid->feat.smap)
+#define vcpu_has_avx512_ifma() (ctxt->cpuid->feat.avx512_ifma)
+#define vcpu_has_clflushopt() (ctxt->cpuid->feat.clflushopt)
+#define vcpu_has_clwb() (ctxt->cpuid->feat.clwb)
+#define vcpu_has_avx512pf() (ctxt->cpuid->feat.avx512pf)
+#define vcpu_has_avx512er() (ctxt->cpuid->feat.avx512er)
+#define vcpu_has_avx512cd() (ctxt->cpuid->feat.avx512cd)
+#define vcpu_has_sha() (ctxt->cpuid->feat.sha)
+#define vcpu_has_avx512bw() (ctxt->cpuid->feat.avx512bw)
+#define vcpu_has_avx512vl() (ctxt->cpuid->feat.avx512vl)
+#define vcpu_has_avx512_vbmi() (ctxt->cpuid->feat.avx512_vbmi)
+#define vcpu_has_avx512_vbmi2() (ctxt->cpuid->feat.avx512_vbmi2)
+#define vcpu_has_gfni() (ctxt->cpuid->feat.gfni)
+#define vcpu_has_vaes() (ctxt->cpuid->feat.vaes)
+#define vcpu_has_vpclmulqdq() (ctxt->cpuid->feat.vpclmulqdq)
+#define vcpu_has_avx512_vnni() (ctxt->cpuid->feat.avx512_vnni)
+#define vcpu_has_avx512_bitalg() (ctxt->cpuid->feat.avx512_bitalg)
+#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq)
+#define vcpu_has_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk)
+#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid)
+#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri)
+#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b)
+#define vcpu_has_enqcmd() (ctxt->cpuid->feat.enqcmd)
+#define vcpu_has_avx512_4vnniw() (ctxt->cpuid->feat.avx512_4vnniw)
+#define vcpu_has_avx512_4fmaps() (ctxt->cpuid->feat.avx512_4fmaps)
+#define vcpu_has_avx512_vp2intersect() (ctxt->cpuid->feat.avx512_vp2intersect)
+#define vcpu_has_serialize() (ctxt->cpuid->feat.serialize)
+#define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni)
+#define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16)
+
+#define vcpu_must_have(feat) \
+ generate_exception_if(!vcpu_has_##feat(), X86_EXC_UD)
+
+#ifdef __XEN__
+/*
+ * Note the difference between vcpu_must_have(<feature>) and
+ * host_and_vcpu_must_have(<feature>): The latter needs to be used when
+ * emulation code is using the same instruction class for carrying out
+ * the actual operation.
+ */
+# define host_and_vcpu_must_have(feat) ({ \
+ generate_exception_if(!cpu_has_##feat, X86_EXC_UD); \
+ vcpu_must_have(feat); \
+})
+#else
+/*
+ * For the test harness both are fine to be used interchangeably, i.e.
+ * features known to always be available (e.g. SSE/SSE2) to (64-bit) Xen
+ * may be checked for by just vcpu_must_have().
+ */
+# define host_and_vcpu_must_have(feat) vcpu_must_have(feat)
+#endif
+
+int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops);
+
+int x86emul_0f01(struct x86_emulate_state *s,
+ struct cpu_user_regs *regs,
+ struct operand *dst,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops);
+
+static inline bool umip_active(struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ unsigned long cr4;
+
+ /* Intentionally not using mode_ring0() here to avoid its fail_if(). */
+ return x86emul_get_cpl(ctxt, ops) > 0 &&
+ ops->read_cr && ops->read_cr(4, &cr4, ctxt) == X86EMUL_OKAY &&
+ (cr4 & X86_CR4_UMIP);
+}
+
+/* Compatibility function: read guest memory, zero-extend result to a ulong. */
+static inline int read_ulong(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ *val = 0;
+ return ops->read(seg, offset, val, bytes, ctxt);
+}
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -20,39 +20,7 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
-/* Operand sizes: 8-bit operands or specified/overridden size. */
-#define ByteOp (1<<0) /* 8-bit operands. */
-/* Destination operand type. */
-#define DstNone (0<<1) /* No destination operand. */
-#define DstImplicit (0<<1) /* Destination operand is implicit in the opcode. */
-#define DstBitBase (1<<1) /* Memory operand, bit string. */
-#define DstReg (2<<1) /* Register operand. */
-#define DstEax DstReg /* Register EAX (aka DstReg with no ModRM) */
-#define DstMem (3<<1) /* Memory operand. */
-#define DstMask (3<<1)
-/* Source operand type. */
-#define SrcNone (0<<3) /* No source operand. */
-#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
-#define SrcReg (1<<3) /* Register operand. */
-#define SrcEax SrcReg /* Register EAX (aka SrcReg with no ModRM) */
-#define SrcMem (2<<3) /* Memory operand. */
-#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
-#define SrcImm (4<<3) /* Immediate operand. */
-#define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */
-#define SrcImm16 (6<<3) /* 16-bit zero-extended immediate operand. */
-#define SrcMask (7<<3)
-/* Generic ModRM decode. */
-#define ModRM (1<<6)
-/* vSIB addressing mode (0f38 extension opcodes only), aliasing ModRM. */
-#define vSIB (1<<6)
-/* Destination is only written; never read. */
-#define Mov (1<<7)
-/* VEX/EVEX (SIMD only): 2nd source operand unused (must be all ones) */
-#define TwoOp Mov
-/* All operands are implicit in the opcode. */
-#define ImplicitOps (DstImplicit|SrcImplicit)
-
-typedef uint8_t opcode_desc_t;
+#include "private.h"
static const opcode_desc_t opcode_table[256] = {
/* 0x00 - 0x07 */
@@ -184,71 +152,6 @@ static const opcode_desc_t opcode_table[
ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
};
-enum simd_opsize {
- simd_none,
-
- /*
- * Ordinary packed integers:
- * - 64 bits without prefix 66 (MMX)
- * - 128 bits with prefix 66 (SSEn)
- * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
- */
- simd_packed_int,
-
- /*
- * Ordinary packed/scalar floating point:
- * - 128 bits without prefix or with prefix 66 (SSEn)
- * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
- * - 32 bits with prefix F3 (scalar single)
- * - 64 bits with prefix F2 (scalar doubgle)
- */
- simd_any_fp,
-
- /*
- * Packed floating point:
- * - 128 bits without prefix or with prefix 66 (SSEn)
- * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
- */
- simd_packed_fp,
-
- /*
- * Single precision packed/scalar floating point:
- * - 128 bits without prefix (SSEn)
- * - 128/256/512 bits depending on VEX.L/EVEX.LR (AVX+)
- * - 32 bits with prefix F3 (scalar)
- */
- simd_single_fp,
-
- /*
- * Scalar floating point:
- * - 32 bits with low opcode bit clear (scalar single)
- * - 64 bits with low opcode bit set (scalar double)
- */
- simd_scalar_opc,
-
- /*
- * Scalar floating point:
- * - 32/64 bits depending on VEX.W/EVEX.W
- */
- simd_scalar_vexw,
-
- /*
- * 128 bits of integer or floating point data, with no further
- * formatting information, or with it encoded by EVEX.W.
- */
- simd_128,
-
- /*
- * 256 bits of integer or floating point data, with formatting
- * encoded by EVEX.W.
- */
- simd_256,
-
- /* Operand size encoded in non-standard way. */
- simd_other
-};
-typedef uint8_t simd_opsize_t;
-
enum disp8scale {
/* Values 0 ... 4 are explicit sizes. */
d8s_bw = 5,
@@ -670,45 +573,11 @@ static const struct ext8f09_table {
[0xe1 ... 0xe3] = { .simd_size = simd_packed_int, .two_op = 1 },
};
-#define REX_PREFIX 0x40
-#define REX_B 0x01
-#define REX_X 0x02
-#define REX_R 0x04
-#define REX_W 0x08
-
-#define vex_none 0
-
-enum vex_opcx {
- vex_0f = vex_none + 1,
- vex_0f38,
- vex_0f3a,
-};
-
-enum vex_pfx {
- vex_66 = vex_none + 1,
- vex_f3,
- vex_f2
-};
-
#define VEX_PREFIX_DOUBLE_MASK 0x1
#define VEX_PREFIX_SCALAR_MASK 0x2
static const uint8_t sse_prefix[] = { 0x66, 0xf3, 0xf2 };
-union vex {
- uint8_t raw[2];
- struct { /* SDM names */
- uint8_t opcx:5; /* mmmmm */
- uint8_t b:1; /* B */
- uint8_t x:1; /* X */
- uint8_t r:1; /* R */
- uint8_t pfx:2; /* pp */
- uint8_t l:1; /* L */
- uint8_t reg:4; /* vvvv */
- uint8_t w:1; /* W */
- };
-};
-
#ifdef __x86_64__
# define PFX2 REX_PREFIX
#else
@@ -748,27 +617,6 @@ union vex {
} \
} while (0)
-union evex {
- uint8_t raw[3];
- struct { /* SDM names */
- uint8_t opcx:2; /* mm */
- uint8_t mbz:2;
- uint8_t R:1; /* R' */
- uint8_t b:1; /* B */
- uint8_t x:1; /* X */
- uint8_t r:1; /* R */
- uint8_t pfx:2; /* pp */
- uint8_t mbs:1;
- uint8_t reg:4; /* vvvv */
- uint8_t w:1; /* W */
- uint8_t opmsk:3; /* aaa */
- uint8_t RX:1; /* V' */
- uint8_t brs:1; /* b */
- uint8_t lr:2; /* L'L */
- uint8_t z:1; /* z */
- };
-};
-
#define EVEX_PFX_BYTES 4
#define init_evex(stub) ({ \
uint8_t *buf_ = get_stub(stub); \
@@ -789,118 +637,6 @@ union evex {
#define repe_prefix() (vex.pfx == vex_f3)
#define repne_prefix() (vex.pfx == vex_f2)
-/* Type, address-of, and value of an instruction's operand. */
-struct operand {
- enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
- unsigned int bytes;
-
- /* Operand value. */
- unsigned long val;
-
- /* Original operand value. */
- unsigned long orig_val;
-
- /* OP_REG: Pointer to register field. */
- unsigned long *reg;
-
- /* OP_MEM: Segment and offset. */
- struct {
- enum x86_segment seg;
- unsigned long off;
- } mem;
-};
-
-struct x86_emulate_state {
- unsigned int op_bytes, ad_bytes;
-
- enum {
- ext_none = vex_none,
- ext_0f = vex_0f,
- ext_0f38 = vex_0f38,
- ext_0f3a = vex_0f3a,
- /*
- * For XOP use values such that the respective instruction field
- * can be used without adjustment.
- */
- ext_8f08 = 8,
- ext_8f09,
- ext_8f0a,
- } ext;
- enum {
- rmw_NONE,
- rmw_adc,
- rmw_add,
- rmw_and,
- rmw_btc,
- rmw_btr,
- rmw_bts,
- rmw_dec,
- rmw_inc,
- 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,
- rmw_xor,
- } rmw;
- enum {
- blk_NONE,
- blk_enqcmd,
-#ifndef X86EMUL_NO_FPU
- blk_fld, /* FLDENV, FRSTOR */
- blk_fst, /* FNSTENV, FNSAVE */
-#endif
-#if !defined(X86EMUL_NO_FPU) || !defined(X86EMUL_NO_MMX) || \
- !defined(X86EMUL_NO_SIMD)
- blk_fxrstor,
- blk_fxsave,
-#endif
- blk_movdir,
- } blk;
- uint8_t modrm, modrm_mod, modrm_reg, modrm_rm;
- uint8_t sib_index, sib_scale;
- uint8_t rex_prefix;
- bool lock_prefix;
- bool not_64bit; /* Instruction not available in 64bit. */
- bool fpu_ctrl; /* Instruction is an FPU control one. */
- opcode_desc_t desc;
- union vex vex;
- union evex evex;
- enum simd_opsize simd_size;
-
- /*
- * Data operand effective address (usually computed from ModRM).
- * Default is a memory operand relative to segment DS.
- */
- struct operand ea;
-
- /* Immediate operand values, if any. Use otherwise unused fields. */
-#define imm1 ea.val
-#define imm2 ea.orig_val
-
- unsigned long ip;
- struct cpu_user_regs *regs;
-
-#ifndef NDEBUG
- /*
- * Track caller of x86_decode_insn() to spot missing as well as
- * premature calls to x86_emulate_free_state().
- */
- void *caller;
-#endif
-};
-
#ifdef __x86_64__
#define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */
#else
@@ -1049,21 +785,6 @@ struct x86_fxsr {
#define _BYTES_PER_LONG "4"
#endif
-/*
- * These EFLAGS bits are restored from saved value during emulation, and
- * any changes are written back to the saved value after emulation.
- */
-#define EFLAGS_MASK (X86_EFLAGS_OF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \
- X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF)
-
-/*
- * These EFLAGS bits are modifiable (by POPF and IRET), possibly subject
- * to further CPL and IOPL constraints.
- */
-#define EFLAGS_MODIFIABLE (X86_EFLAGS_ID | X86_EFLAGS_AC | X86_EFLAGS_RF | \
- X86_EFLAGS_NT | X86_EFLAGS_IOPL | X86_EFLAGS_DF | \
- X86_EFLAGS_IF | X86_EFLAGS_TF | EFLAGS_MASK)
-
/* Before executing instruction: restore necessary bits in EFLAGS. */
#define _PRE_EFLAGS(_sav, _msk, _tmp) \
/* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~_msk; */ \
@@ -1223,36 +944,6 @@ do{ asm volatile (
#define __emulate_1op_8byte(op, dst, eflags, extra...)
#endif /* __i386__ */
-#define fail_if(p) \
-do { \
- rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \
- if ( rc ) goto done; \
-} while (0)
-
-#define EXPECT(p) \
-do { \
- if ( unlikely(!(p)) ) \
- { \
- ASSERT_UNREACHABLE(); \
- goto unhandleable; \
- } \
-} while (0)
-
-static inline int mkec(uint8_t e, int32_t ec, ...)
-{
- return (e < 32 && ((1u << e) & EXC_HAS_EC)) ? ec : X86_EVENT_NO_EC;
-}
-
-#define generate_exception_if(p, e, ec...) \
-({ if ( (p) ) { \
- x86_emul_hw_exception(e, mkec(e, ##ec, 0), ctxt); \
- rc = X86EMUL_EXCEPTION; \
- goto done; \
- } \
-})
-
-#define generate_exception(e, ec...) generate_exception_if(true, e, ##ec)
-
#ifdef __XEN__
# define invoke_stub(pre, post, constraints...) do { \
stub_exn.info = (union stub_exception_token) { .raw = ~0 }; \
@@ -1301,20 +992,6 @@ static inline int mkec(uint8_t e, int32_
})
#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
-#define truncate_word(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_word((ea), ad_bytes)
-
-#ifdef __x86_64__
-# define mode_64bit() (ctxt->addr_size == 64)
-#else
-# define mode_64bit() false
-#endif
-
/*
* Given byte has even parity (even number of 1s)? SDM Vol. 1 Sec. 3.4.3.1,
* "Status Flags": EFLAGS.PF reflects parity of least-sig. byte of result only.
@@ -1655,19 +1332,6 @@ static void __put_rep_prefix(
ea__; \
})
-/* Compatibility function: read guest memory, zero-extend result to a ulong. */
-static int read_ulong(
- enum x86_segment seg,
- unsigned long offset,
- unsigned long *val,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- *val = 0;
- return ops->read(seg, offset, val, bytes, ctxt);
-}
-
/*
* Unsigned multiplication with double-word result.
* IN: Multiplicand=m[0], Multiplier=m[1]
@@ -1792,10 +1456,8 @@ test_cc(
return (!!rc ^ (condition & 1));
}
-static int
-get_cpl(
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
+int x86emul_get_cpl(struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
{
struct segment_register reg;
@@ -1814,17 +1476,12 @@ _mode_iopl(
struct x86_emulate_ctxt *ctxt,
const struct x86_emulate_ops *ops)
{
- int cpl = get_cpl(ctxt, ops);
+ int cpl = x86emul_get_cpl(ctxt, ops);
if ( cpl == -1 )
return -1;
return cpl <= MASK_EXTR(ctxt->regs->eflags, X86_EFLAGS_IOPL);
}
-#define mode_ring0() ({ \
- int _cpl = get_cpl(ctxt, ops); \
- fail_if(_cpl < 0); \
- (_cpl == 0); \
-})
#define mode_iopl() ({ \
int _iopl = _mode_iopl(ctxt, ops); \
fail_if(_iopl < 0); \
@@ -1832,7 +1489,7 @@ _mode_iopl(
})
#define mode_vif() ({ \
cr4 = 0; \
- if ( ops->read_cr && get_cpl(ctxt, ops) == 3 ) \
+ if ( ops->read_cr && x86emul_get_cpl(ctxt, ops) == 3 ) \
{ \
rc = ops->read_cr(4, &cr4, ctxt); \
if ( rc != X86EMUL_OKAY ) goto done; \
@@ -1900,29 +1557,6 @@ static int ioport_access_check(
}
static bool
-in_realmode(
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- unsigned long cr0;
- int rc;
-
- if ( ops->read_cr == NULL )
- return 0;
-
- rc = ops->read_cr(0, &cr0, ctxt);
- return (!rc && !(cr0 & X86_CR0_PE));
-}
-
-static bool
-in_protmode(
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & X86_EFLAGS_VM));
-}
-
-static bool
_amd_like(const struct cpuid_policy *cp)
{
return cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON);
@@ -1934,107 +1568,6 @@ amd_like(const struct x86_emulate_ctxt *
return _amd_like(ctxt->cpuid);
}
-#define vcpu_has_fpu() (ctxt->cpuid->basic.fpu)
-#define vcpu_has_sep() (ctxt->cpuid->basic.sep)
-#define vcpu_has_cx8() (ctxt->cpuid->basic.cx8)
-#define vcpu_has_cmov() (ctxt->cpuid->basic.cmov)
-#define vcpu_has_clflush() (ctxt->cpuid->basic.clflush)
-#define vcpu_has_mmx() (ctxt->cpuid->basic.mmx)
-#define vcpu_has_fxsr() (ctxt->cpuid->basic.fxsr)
-#define vcpu_has_sse() (ctxt->cpuid->basic.sse)
-#define vcpu_has_sse2() (ctxt->cpuid->basic.sse2)
-#define vcpu_has_sse3() (ctxt->cpuid->basic.sse3)
-#define vcpu_has_pclmulqdq() (ctxt->cpuid->basic.pclmulqdq)
-#define vcpu_has_ssse3() (ctxt->cpuid->basic.ssse3)
-#define vcpu_has_fma() (ctxt->cpuid->basic.fma)
-#define vcpu_has_cx16() (ctxt->cpuid->basic.cx16)
-#define vcpu_has_sse4_1() (ctxt->cpuid->basic.sse4_1)
-#define vcpu_has_sse4_2() (ctxt->cpuid->basic.sse4_2)
-#define vcpu_has_movbe() (ctxt->cpuid->basic.movbe)
-#define vcpu_has_popcnt() (ctxt->cpuid->basic.popcnt)
-#define vcpu_has_aesni() (ctxt->cpuid->basic.aesni)
-#define vcpu_has_avx() (ctxt->cpuid->basic.avx)
-#define vcpu_has_f16c() (ctxt->cpuid->basic.f16c)
-#define vcpu_has_rdrand() (ctxt->cpuid->basic.rdrand)
-
-#define vcpu_has_mmxext() (ctxt->cpuid->extd.mmxext || vcpu_has_sse())
-#define vcpu_has_3dnow_ext() (ctxt->cpuid->extd._3dnowext)
-#define vcpu_has_3dnow() (ctxt->cpuid->extd._3dnow)
-#define vcpu_has_lahf_lm() (ctxt->cpuid->extd.lahf_lm)
-#define vcpu_has_cr8_legacy() (ctxt->cpuid->extd.cr8_legacy)
-#define vcpu_has_lzcnt() (ctxt->cpuid->extd.abm)
-#define vcpu_has_sse4a() (ctxt->cpuid->extd.sse4a)
-#define vcpu_has_misalignsse() (ctxt->cpuid->extd.misalignsse)
-#define vcpu_has_xop() (ctxt->cpuid->extd.xop)
-#define vcpu_has_fma4() (ctxt->cpuid->extd.fma4)
-#define vcpu_has_tbm() (ctxt->cpuid->extd.tbm)
-#define vcpu_has_clzero() (ctxt->cpuid->extd.clzero)
-#define vcpu_has_wbnoinvd() (ctxt->cpuid->extd.wbnoinvd)
-
-#define vcpu_has_bmi1() (ctxt->cpuid->feat.bmi1)
-#define vcpu_has_hle() (ctxt->cpuid->feat.hle)
-#define vcpu_has_avx2() (ctxt->cpuid->feat.avx2)
-#define vcpu_has_bmi2() (ctxt->cpuid->feat.bmi2)
-#define vcpu_has_invpcid() (ctxt->cpuid->feat.invpcid)
-#define vcpu_has_rtm() (ctxt->cpuid->feat.rtm)
-#define vcpu_has_mpx() (ctxt->cpuid->feat.mpx)
-#define vcpu_has_avx512f() (ctxt->cpuid->feat.avx512f)
-#define vcpu_has_avx512dq() (ctxt->cpuid->feat.avx512dq)
-#define vcpu_has_rdseed() (ctxt->cpuid->feat.rdseed)
-#define vcpu_has_adx() (ctxt->cpuid->feat.adx)
-#define vcpu_has_smap() (ctxt->cpuid->feat.smap)
-#define vcpu_has_avx512_ifma() (ctxt->cpuid->feat.avx512_ifma)
-#define vcpu_has_clflushopt() (ctxt->cpuid->feat.clflushopt)
-#define vcpu_has_clwb() (ctxt->cpuid->feat.clwb)
-#define vcpu_has_avx512pf() (ctxt->cpuid->feat.avx512pf)
-#define vcpu_has_avx512er() (ctxt->cpuid->feat.avx512er)
-#define vcpu_has_avx512cd() (ctxt->cpuid->feat.avx512cd)
-#define vcpu_has_sha() (ctxt->cpuid->feat.sha)
-#define vcpu_has_avx512bw() (ctxt->cpuid->feat.avx512bw)
-#define vcpu_has_avx512vl() (ctxt->cpuid->feat.avx512vl)
-#define vcpu_has_avx512_vbmi() (ctxt->cpuid->feat.avx512_vbmi)
-#define vcpu_has_avx512_vbmi2() (ctxt->cpuid->feat.avx512_vbmi2)
-#define vcpu_has_gfni() (ctxt->cpuid->feat.gfni)
-#define vcpu_has_vaes() (ctxt->cpuid->feat.vaes)
-#define vcpu_has_vpclmulqdq() (ctxt->cpuid->feat.vpclmulqdq)
-#define vcpu_has_avx512_vnni() (ctxt->cpuid->feat.avx512_vnni)
-#define vcpu_has_avx512_bitalg() (ctxt->cpuid->feat.avx512_bitalg)
-#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq)
-#define vcpu_has_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk)
-#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid)
-#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri)
-#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b)
-#define vcpu_has_enqcmd() (ctxt->cpuid->feat.enqcmd)
-#define vcpu_has_avx512_4vnniw() (ctxt->cpuid->feat.avx512_4vnniw)
-#define vcpu_has_avx512_4fmaps() (ctxt->cpuid->feat.avx512_4fmaps)
-#define vcpu_has_avx512_vp2intersect() (ctxt->cpuid->feat.avx512_vp2intersect)
-#define vcpu_has_serialize() (ctxt->cpuid->feat.serialize)
-#define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni)
-#define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16)
-
-#define vcpu_must_have(feat) \
- generate_exception_if(!vcpu_has_##feat(), EXC_UD)
-
-#ifdef __XEN__
-/*
- * Note the difference between vcpu_must_have(<feature>) and
- * host_and_vcpu_must_have(<feature>): The latter needs to be used when
- * emulation code is using the same instruction class for carrying out
- * the actual operation.
- */
-#define host_and_vcpu_must_have(feat) ({ \
- generate_exception_if(!cpu_has_##feat, EXC_UD); \
- vcpu_must_have(feat); \
-})
-#else
-/*
- * For the test harness both are fine to be used interchangeably, i.e.
- * features known to always be available (e.g. SSE/SSE2) to (64-bit) Xen
- * may be checked for by just vcpu_must_have().
- */
-#define host_and_vcpu_must_have(feat) vcpu_must_have(feat)
-#endif
-
/* Initialise output state in x86_emulate_ctxt */
static void init_context(struct x86_emulate_ctxt *ctxt)
{
@@ -2081,7 +1614,7 @@ protmode_load_seg(
enum x86_segment sel_seg = (sel & 4) ? x86_seg_ldtr : x86_seg_gdtr;
struct { uint32_t a, b; } desc, desc_hi = {};
uint8_t dpl, rpl;
- int cpl = get_cpl(ctxt, ops);
+ int cpl = x86emul_get_cpl(ctxt, ops);
uint32_t a_flag = 0x100;
int rc, fault_type = EXC_GP;
@@ -2481,17 +2014,6 @@ static bool is_branch_step(struct x86_em
(debugctl & IA32_DEBUGCTLMSR_BTF);
}
-static bool umip_active(struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- unsigned long cr4;
-
- /* Intentionally not using mode_ring0() here to avoid its fail_if(). */
- return get_cpl(ctxt, ops) > 0 &&
- ops->read_cr && ops->read_cr(4, &cr4, ctxt) == X86EMUL_OKAY &&
- (cr4 & X86_CR4_UMIP);
-}
-
static void adjust_bnd(struct x86_emulate_ctxt *ctxt,
const struct x86_emulate_ops *ops, enum vex_pfx pfx)
{
@@ -5703,317 +5225,8 @@ x86_emulate(
break;
case X86EMUL_OPC(0x0f, 0x01): /* Grp7 */
- {
- unsigned long base, limit, cr0, cr0w;
-
- seg = (modrm_reg & 1) ? x86_seg_idtr : x86_seg_gdtr;
-
- switch( modrm )
- {
- case 0xca: /* clac */
- case 0xcb: /* stac */
- vcpu_must_have(smap);
- generate_exception_if(vex.pfx || !mode_ring0(), EXC_UD);
-
- _regs.eflags &= ~X86_EFLAGS_AC;
- if ( modrm == 0xcb )
- _regs.eflags |= X86_EFLAGS_AC;
- break;
-
- case 0xd0: /* xgetbv */
- generate_exception_if(vex.pfx, EXC_UD);
- if ( !ops->read_cr || !ops->read_xcr ||
- ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
- cr4 = 0;
- generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), EXC_UD);
- rc = ops->read_xcr(_regs.ecx, &msr_val, ctxt);
- if ( rc != X86EMUL_OKAY )
- goto done;
- _regs.r(ax) = (uint32_t)msr_val;
- _regs.r(dx) = msr_val >> 32;
- break;
-
- case 0xd1: /* xsetbv */
- generate_exception_if(vex.pfx, EXC_UD);
- if ( !ops->read_cr || !ops->write_xcr ||
- ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
- cr4 = 0;
- generate_exception_if(!(cr4 & X86_CR4_OSXSAVE), EXC_UD);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- rc = ops->write_xcr(_regs.ecx,
- _regs.eax | ((uint64_t)_regs.edx << 32), ctxt);
- if ( rc != X86EMUL_OKAY )
- goto done;
- break;
-
- case 0xd4: /* vmfunc */
- generate_exception_if(vex.pfx, EXC_UD);
- fail_if(!ops->vmfunc);
- if ( (rc = ops->vmfunc(ctxt)) != X86EMUL_OKAY )
- goto done;
- break;
-
- case 0xd5: /* xend */
- generate_exception_if(vex.pfx, EXC_UD);
- generate_exception_if(!vcpu_has_rtm(), EXC_UD);
- generate_exception_if(vcpu_has_rtm(), EXC_GP, 0);
- break;
-
- case 0xd6: /* xtest */
- generate_exception_if(vex.pfx, EXC_UD);
- generate_exception_if(!vcpu_has_rtm() && !vcpu_has_hle(),
- EXC_UD);
- /* Neither HLE nor RTM can be active when we get here. */
- _regs.eflags |= X86_EFLAGS_ZF;
- break;
-
- case 0xdf: /* invlpga */
- fail_if(!ops->read_msr);
- if ( (rc = ops->read_msr(MSR_EFER,
- &msr_val, ctxt)) != X86EMUL_OKAY )
- goto done;
- /* Finding SVME set implies vcpu_has_svm(). */
- generate_exception_if(!(msr_val & EFER_SVME) ||
- !in_protmode(ctxt, ops), EXC_UD);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- fail_if(!ops->tlb_op);
- if ( (rc = ops->tlb_op(x86emul_invlpga, truncate_ea(_regs.r(ax)),
- _regs.ecx, ctxt)) != X86EMUL_OKAY )
- goto done;
- break;
-
- case 0xe8:
- switch ( vex.pfx )
- {
- case vex_none: /* serialize */
- host_and_vcpu_must_have(serialize);
- asm volatile ( ".byte 0x0f, 0x01, 0xe8" );
- break;
- case vex_f2: /* xsusldtrk */
- vcpu_must_have(tsxldtrk);
- /*
- * We're never in a transactional region when coming here
- * - nothing else to do.
- */
- break;
- default:
- goto unimplemented_insn;
- }
- break;
-
- case 0xe9:
- switch ( vex.pfx )
- {
- case vex_f2: /* xresldtrk */
- vcpu_must_have(tsxldtrk);
- /*
- * We're never in a transactional region when coming here
- * - nothing else to do.
- */
- break;
- default:
- goto unimplemented_insn;
- }
- break;
-
- case 0xee:
- switch ( vex.pfx )
- {
- case vex_none: /* rdpkru */
- if ( !ops->read_cr ||
- ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
- cr4 = 0;
- generate_exception_if(!(cr4 & X86_CR4_PKE), EXC_UD);
- generate_exception_if(_regs.ecx, EXC_GP, 0);
- _regs.r(ax) = rdpkru();
- _regs.r(dx) = 0;
- break;
- default:
- goto unimplemented_insn;
- }
- break;
-
- case 0xef:
- switch ( vex.pfx )
- {
- case vex_none: /* wrpkru */
- if ( !ops->read_cr ||
- ops->read_cr(4, &cr4, ctxt) != X86EMUL_OKAY )
- cr4 = 0;
- generate_exception_if(!(cr4 & X86_CR4_PKE), EXC_UD);
- generate_exception_if(_regs.ecx | _regs.edx, EXC_GP, 0);
- wrpkru(_regs.eax);
- break;
- default:
- goto unimplemented_insn;
- }
- break;
-
- case 0xf8: /* swapgs */
- generate_exception_if(!mode_64bit(), EXC_UD);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- fail_if(!ops->read_segment || !ops->read_msr ||
- !ops->write_segment || !ops->write_msr);
- if ( (rc = ops->read_segment(x86_seg_gs, &sreg,
- ctxt)) != X86EMUL_OKAY ||
- (rc = ops->read_msr(MSR_SHADOW_GS_BASE, &msr_val,
- ctxt)) != X86EMUL_OKAY ||
- (rc = ops->write_msr(MSR_SHADOW_GS_BASE, sreg.base,
- ctxt)) != X86EMUL_OKAY )
- goto done;
- sreg.base = msr_val;
- if ( (rc = ops->write_segment(x86_seg_gs, &sreg,
- ctxt)) != X86EMUL_OKAY )
- {
- /* Best effort unwind (i.e. no error checking). */
- ops->write_msr(MSR_SHADOW_GS_BASE, msr_val, ctxt);
- goto done;
- }
- break;
-
- case 0xf9: /* rdtscp */
- fail_if(ops->read_msr == NULL);
- if ( (rc = ops->read_msr(MSR_TSC_AUX,
- &msr_val, ctxt)) != X86EMUL_OKAY )
- goto done;
- _regs.r(cx) = (uint32_t)msr_val;
- goto rdtsc;
-
- case 0xfc: /* clzero */
- {
- unsigned long zero = 0;
-
- vcpu_must_have(clzero);
-
- base = ad_bytes == 8 ? _regs.r(ax) :
- ad_bytes == 4 ? _regs.eax : _regs.ax;
- limit = ctxt->cpuid->basic.clflush_size * 8;
- generate_exception_if(limit < sizeof(long) ||
- (limit & (limit - 1)), EXC_UD);
- base &= ~(limit - 1);
- if ( ops->rep_stos )
- {
- unsigned long nr_reps = limit / sizeof(zero);
-
- rc = ops->rep_stos(&zero, ea.mem.seg, base, sizeof(zero),
- &nr_reps, ctxt);
- if ( rc == X86EMUL_OKAY )
- {
- base += nr_reps * sizeof(zero);
- limit -= nr_reps * sizeof(zero);
- }
- else if ( rc != X86EMUL_UNHANDLEABLE )
- goto done;
- }
- fail_if(limit && !ops->write);
- while ( limit )
- {
- rc = ops->write(ea.mem.seg, base, &zero, sizeof(zero), ctxt);
- if ( rc != X86EMUL_OKAY )
- goto done;
- base += sizeof(zero);
- limit -= sizeof(zero);
- }
- break;
- }
-
-#define _GRP7(mod, reg) \
- (((mod) << 6) | ((reg) << 3)) ... (((mod) << 6) | ((reg) << 3) | 7)
-#define GRP7_MEM(reg) _GRP7(0, reg): case _GRP7(1, reg): case _GRP7(2, reg)
-#define GRP7_ALL(reg) GRP7_MEM(reg): case _GRP7(3, reg)
-
- case GRP7_MEM(0): /* sgdt */
- case GRP7_MEM(1): /* sidt */
- ASSERT(ea.type == OP_MEM);
- generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0);
- fail_if(!ops->read_segment || !ops->write);
- if ( (rc = ops->read_segment(seg, &sreg, ctxt)) )
- goto done;
- if ( mode_64bit() )
- op_bytes = 8;
- else if ( op_bytes == 2 )
- {
- sreg.base &= 0xffffff;
- op_bytes = 4;
- }
- if ( (rc = ops->write(ea.mem.seg, ea.mem.off, &sreg.limit,
- 2, ctxt)) != X86EMUL_OKAY ||
- (rc = ops->write(ea.mem.seg, truncate_ea(ea.mem.off + 2),
- &sreg.base, op_bytes, ctxt)) != X86EMUL_OKAY )
- goto done;
- break;
-
- case GRP7_MEM(2): /* lgdt */
- case GRP7_MEM(3): /* lidt */
- ASSERT(ea.type == OP_MEM);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- fail_if(ops->write_segment == NULL);
- memset(&sreg, 0, sizeof(sreg));
- if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
- &limit, 2, ctxt, ops)) ||
- (rc = read_ulong(ea.mem.seg, truncate_ea(ea.mem.off + 2),
- &base, mode_64bit() ? 8 : 4, ctxt, ops)) )
- goto done;
- generate_exception_if(!is_canonical_address(base), EXC_GP, 0);
- sreg.base = base;
- sreg.limit = limit;
- if ( !mode_64bit() && op_bytes == 2 )
- sreg.base &= 0xffffff;
- if ( (rc = ops->write_segment(seg, &sreg, ctxt)) )
- goto done;
- break;
-
- case GRP7_ALL(4): /* smsw */
- generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0);
- if ( ea.type == OP_MEM )
- {
- fail_if(!ops->write);
- d |= Mov; /* force writeback */
- ea.bytes = 2;
- }
- else
- ea.bytes = op_bytes;
- dst = ea;
- fail_if(ops->read_cr == NULL);
- if ( (rc = ops->read_cr(0, &dst.val, ctxt)) )
- goto done;
- break;
-
- case GRP7_ALL(6): /* lmsw */
- fail_if(ops->read_cr == NULL);
- fail_if(ops->write_cr == NULL);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- if ( (rc = ops->read_cr(0, &cr0, ctxt)) )
- goto done;
- if ( ea.type == OP_REG )
- cr0w = *ea.reg;
- else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
- &cr0w, 2, ctxt, ops)) )
- goto done;
- /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */
- cr0 = (cr0 & ~0xe) | (cr0w & 0xf);
- if ( (rc = ops->write_cr(0, cr0, ctxt)) )
- goto done;
- break;
-
- case GRP7_MEM(7): /* invlpg */
- ASSERT(ea.type == OP_MEM);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- fail_if(!ops->tlb_op);
- if ( (rc = ops->tlb_op(x86emul_invlpg, ea.mem.off, ea.mem.seg,
- ctxt)) != X86EMUL_OKAY )
- goto done;
- break;
-
-#undef GRP7_ALL
-#undef GRP7_MEM
-#undef _GRP7
-
- default:
- goto unimplemented_insn;
- }
- break;
- }
+ rc = x86emul_0f01(state, &_regs, &dst, ctxt, ops);
+ goto dispatch_from_helper;
case X86EMUL_OPC(0x0f, 0x02): /* lar */
generate_exception_if(!in_protmode(ctxt, ops), EXC_UD);
@@ -11309,6 +10522,24 @@ x86_emulate(
unrecognized_insn:
rc = X86EMUL_UNRECOGNIZED;
goto done;
+
+ dispatch_from_helper:
+ if ( rc == X86EMUL_OKAY )
+ break;
+
+ switch ( rc )
+ {
+ case X86EMUL_rdtsc:
+ goto rdtsc;
+ }
+
+ /* Internally used state change indicators may not make it here. */
+ if ( rc < 0 )
+ {
+ ASSERT_UNREACHABLE();
+ rc = X86EMUL_UNHANDLEABLE;
+ }
+ goto done;
}
if ( state->rmw )
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 5/7] x86emul: split off insn decoding
2021-08-11 12:21 [PATCH 0/7] x86emul: a few small steps towards disintegration Jan Beulich
` (3 preceding siblings ...)
2021-08-11 12:24 ` [PATCH 4/7] x86emul: split off FPU opcode handling Jan Beulich
@ 2021-08-11 12:24 ` Jan Beulich
2021-08-11 12:25 ` [PATCH 6/7] x86emul: move x86_emul_blk() to separate source file Jan Beulich
2021-08-11 12:25 ` [PATCH 7/7] x86emul: move various utility functions to separate source files Jan Beulich
6 siblings, 0 replies; 8+ messages in thread
From: Jan Beulich @ 2021-08-11 12:24 UTC (permalink / raw)
To: xen-devel; +Cc: Andrew Cooper, Wei Liu, Roger Pau Monné
This is a fair chunk of code and data and can easily live separate from
the main emulation function.
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
@@ -36,7 +36,7 @@ x86_emulate.h := x86-emulate.h x86_emula
OBJS := fuzz-emul.o x86-emulate.o
OBJS += x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o
-OBJS += x86_emulate/fpu.o
+OBJS += x86_emulate/decode.o x86_emulate/fpu.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
@@ -252,7 +252,7 @@ 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 x86_emulate/0fc7.o
-OBJS += x86_emulate/fpu.o
+OBJS += x86_emulate/decode.o x86_emulate/fpu.o
$(TARGET): $(OBJS)
$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
--- a/tools/tests/x86_emulator/x86-emulate.c
+++ b/tools/tests/x86_emulator/x86-emulate.c
@@ -3,11 +3,6 @@
#include <errno.h>
#include <sys/mman.h>
-#define DEFINE_PER_CPU(type, var) type per_cpu_##var
-#define this_cpu(var) per_cpu_##var
-
-#define ERR_PTR(val) NULL
-
/* See gcc bug 100680, but here don't bother making this version dependent. */
#define gcc11_wrap(x) ({ \
unsigned long x_; \
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -48,6 +48,9 @@
#define ASSERT assert
#define ASSERT_UNREACHABLE() assert(!__LINE__)
+#define DEFINE_PER_CPU(type, var) type per_cpu_##var
+#define this_cpu(var) per_cpu_##var
+
#define MASK_EXTR(v, m) (((v) & (m)) / ((m) & -(m)))
#define MASK_INSR(v, m) (((v) * ((m) & -(m))) & (m))
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -9,7 +9,6 @@
* Keir Fraser <keir@xen.org>
*/
-#include <xen/err.h>
#include <xen/event.h>
#include <asm/x86_emulate.h>
#include <asm/processor.h> /* current_cpu_info */
--- a/xen/arch/x86/x86_emulate/Makefile
+++ b/xen/arch/x86/x86_emulate/Makefile
@@ -1,4 +1,5 @@
obj-y += 0f01.o
obj-y += 0fae.o
obj-y += 0fc7.o
+obj-y += decode.o
obj-$(CONFIG_HVM) += fpu.o
--- /dev/null
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -0,0 +1,1750 @@
+/******************************************************************************
+ * decode.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"
+
+#ifdef __XEN__
+# include <xen/err.h>
+#else
+# define ERR_PTR(val) NULL
+#endif
+
+#define evex_encoded() (s->evex.mbs)
+
+struct x86_emulate_state *
+x86_decode_insn(
+ struct x86_emulate_ctxt *ctxt,
+ int (*insn_fetch)(
+ enum x86_segment seg, unsigned long offset,
+ void *p_data, unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt))
+{
+ static DEFINE_PER_CPU(struct x86_emulate_state, state);
+ struct x86_emulate_state *s = &this_cpu(state);
+ const struct x86_emulate_ops ops = {
+ .insn_fetch = insn_fetch,
+ .read = x86emul_unhandleable_rw,
+ };
+ int rc;
+
+ init_context(ctxt);
+
+ rc = x86emul_decode(s, ctxt, &ops);
+ if ( unlikely(rc != X86EMUL_OKAY) )
+ return ERR_PTR(-rc);
+
+#if defined(__XEN__) && !defined(NDEBUG)
+ /*
+ * While we avoid memory allocation (by use of per-CPU data) above,
+ * nevertheless make sure callers properly release the state structure
+ * for forward compatibility.
+ */
+ if ( s->caller )
+ {
+ printk(XENLOG_ERR "Unreleased emulation state acquired by %ps\n",
+ s->caller);
+ dump_execution_state();
+ }
+ s->caller = __builtin_return_address(0);
+#endif
+
+ return s;
+}
+
+static const opcode_desc_t opcode_table[256] = {
+ /* 0x00 - 0x07 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
+ /* 0x08 - 0x0F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, 0,
+ /* 0x10 - 0x17 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
+ /* 0x18 - 0x1F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
+ /* 0x20 - 0x27 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
+ /* 0x28 - 0x2F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
+ /* 0x30 - 0x37 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
+ /* 0x38 - 0x3F */
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
+ /* 0x40 - 0x4F */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ /* 0x50 - 0x5F */
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
+ /* 0x60 - 0x67 */
+ ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcNone|ModRM|Mov,
+ 0, 0, 0, 0,
+ /* 0x68 - 0x6F */
+ DstImplicit|SrcImm|Mov, DstReg|SrcImm|ModRM|Mov,
+ DstImplicit|SrcImmByte|Mov, DstReg|SrcImmByte|ModRM|Mov,
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
+ /* 0x70 - 0x77 */
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ /* 0x78 - 0x7F */
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ /* 0x80 - 0x87 */
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ /* 0x88 - 0x8F */
+ ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
+ ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM,
+ DstReg|SrcMem16|ModRM|Mov, DstMem|SrcNone|ModRM|Mov,
+ /* 0x90 - 0x97 */
+ DstImplicit|SrcEax, DstImplicit|SrcEax,
+ DstImplicit|SrcEax, DstImplicit|SrcEax,
+ DstImplicit|SrcEax, DstImplicit|SrcEax,
+ DstImplicit|SrcEax, DstImplicit|SrcEax,
+ /* 0x98 - 0x9F */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps, ImplicitOps,
+ /* 0xA0 - 0xA7 */
+ ByteOp|DstEax|SrcMem|Mov, DstEax|SrcMem|Mov,
+ ByteOp|DstMem|SrcEax|Mov, DstMem|SrcEax|Mov,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps, ImplicitOps,
+ /* 0xA8 - 0xAF */
+ ByteOp|DstEax|SrcImm, DstEax|SrcImm,
+ ByteOp|DstImplicit|SrcEax|Mov, DstImplicit|SrcEax|Mov,
+ ByteOp|DstEax|SrcImplicit|Mov, DstEax|SrcImplicit|Mov,
+ ByteOp|DstImplicit|SrcEax, DstImplicit|SrcEax,
+ /* 0xB0 - 0xB7 */
+ ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
+ ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
+ ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
+ ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
+ /* 0xB8 - 0xBF */
+ DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
+ DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
+ /* 0xC0 - 0xC7 */
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
+ DstImplicit|SrcImm16, ImplicitOps,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
+ /* 0xC8 - 0xCF */
+ DstImplicit|SrcImm16, ImplicitOps, DstImplicit|SrcImm16, ImplicitOps,
+ ImplicitOps, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps,
+ /* 0xD0 - 0xD7 */
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps,
+ /* 0xD8 - 0xDF */
+ ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
+ ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
+ ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
+ DstImplicit|SrcMem16|ModRM, ImplicitOps|ModRM|Mov,
+ /* 0xE0 - 0xE7 */
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ DstEax|SrcImmByte, DstEax|SrcImmByte,
+ DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
+ /* 0xE8 - 0xEF */
+ DstImplicit|SrcImm|Mov, DstImplicit|SrcImm,
+ ImplicitOps, DstImplicit|SrcImmByte,
+ DstEax|SrcImplicit, DstEax|SrcImplicit, ImplicitOps, ImplicitOps,
+ /* 0xF0 - 0xF7 */
+ 0, ImplicitOps, 0, 0,
+ ImplicitOps, ImplicitOps, ByteOp|ModRM, ModRM,
+ /* 0xF8 - 0xFF */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
+};
+
+static const struct twobyte_table {
+ opcode_desc_t desc;
+ simd_opsize_t size:4;
+ disp8scale_t d8s:4;
+} twobyte_table[256] = {
+ [0x00] = { ModRM },
+ [0x01] = { ImplicitOps|ModRM },
+ [0x02] = { DstReg|SrcMem16|ModRM },
+ [0x03] = { DstReg|SrcMem16|ModRM },
+ [0x05] = { ImplicitOps },
+ [0x06] = { ImplicitOps },
+ [0x07] = { ImplicitOps },
+ [0x08] = { ImplicitOps },
+ [0x09] = { ImplicitOps },
+ [0x0b] = { ImplicitOps },
+ [0x0d] = { ImplicitOps|ModRM },
+ [0x0e] = { ImplicitOps },
+ [0x0f] = { ModRM|SrcImmByte },
+ [0x10] = { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl },
+ [0x11] = { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl },
+ [0x12] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 },
+ [0x13] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
+ [0x14 ... 0x15] = { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl },
+ [0x16] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 },
+ [0x17] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
+ [0x18 ... 0x1f] = { ImplicitOps|ModRM },
+ [0x20 ... 0x21] = { DstMem|SrcImplicit|ModRM },
+ [0x22 ... 0x23] = { DstImplicit|SrcMem|ModRM },
+ [0x28] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
+ [0x29] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_fp, d8s_vl },
+ [0x2a] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 },
+ [0x2b] = { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl },
+ [0x2c ... 0x2d] = { DstImplicit|SrcMem|ModRM|Mov, simd_other },
+ [0x2e ... 0x2f] = { ImplicitOps|ModRM|TwoOp, simd_none, d8s_dq },
+ [0x30 ... 0x35] = { ImplicitOps },
+ [0x37] = { ImplicitOps },
+ [0x38] = { DstReg|SrcMem|ModRM },
+ [0x3a] = { DstReg|SrcImmByte|ModRM },
+ [0x40 ... 0x4f] = { DstReg|SrcMem|ModRM|Mov },
+ [0x50] = { DstReg|SrcImplicit|ModRM|Mov },
+ [0x51] = { DstImplicit|SrcMem|ModRM|TwoOp, simd_any_fp, d8s_vl },
+ [0x52 ... 0x53] = { DstImplicit|SrcMem|ModRM|TwoOp, simd_single_fp },
+ [0x54 ... 0x57] = { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl },
+ [0x58 ... 0x59] = { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl },
+ [0x5a] = { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl },
+ [0x5b] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
+ [0x5c ... 0x5f] = { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl },
+ [0x60 ... 0x62] = { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl },
+ [0x63 ... 0x67] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0x68 ... 0x6a] = { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl },
+ [0x6b ... 0x6d] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0x6e] = { DstImplicit|SrcMem|ModRM|Mov, simd_none, d8s_dq64 },
+ [0x6f] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_int, d8s_vl },
+ [0x70] = { SrcImmByte|ModRM|TwoOp, simd_other, d8s_vl },
+ [0x71 ... 0x73] = { DstImplicit|SrcImmByte|ModRM, simd_none, d8s_vl },
+ [0x74 ... 0x76] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0x77] = { DstImplicit|SrcNone },
+ [0x78 ... 0x79] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_vl },
+ [0x7a] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
+ [0x7b] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 },
+ [0x7c ... 0x7d] = { DstImplicit|SrcMem|ModRM, simd_other },
+ [0x7e] = { DstMem|SrcImplicit|ModRM|Mov, simd_none, d8s_dq64 },
+ [0x7f] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl },
+ [0x80 ... 0x8f] = { DstImplicit|SrcImm },
+ [0x90 ... 0x9f] = { ByteOp|DstMem|SrcNone|ModRM|Mov },
+ [0xa0 ... 0xa1] = { ImplicitOps|Mov },
+ [0xa2] = { ImplicitOps },
+ [0xa3] = { DstBitBase|SrcReg|ModRM },
+ [0xa4] = { DstMem|SrcImmByte|ModRM },
+ [0xa5] = { DstMem|SrcReg|ModRM },
+ [0xa6 ... 0xa7] = { ModRM },
+ [0xa8 ... 0xa9] = { ImplicitOps|Mov },
+ [0xaa] = { ImplicitOps },
+ [0xab] = { DstBitBase|SrcReg|ModRM },
+ [0xac] = { DstMem|SrcImmByte|ModRM },
+ [0xad] = { DstMem|SrcReg|ModRM },
+ [0xae] = { ImplicitOps|ModRM },
+ [0xaf] = { DstReg|SrcMem|ModRM },
+ [0xb0] = { ByteOp|DstMem|SrcReg|ModRM },
+ [0xb1] = { DstMem|SrcReg|ModRM },
+ [0xb2] = { DstReg|SrcMem|ModRM|Mov },
+ [0xb3] = { DstBitBase|SrcReg|ModRM },
+ [0xb4 ... 0xb5] = { DstReg|SrcMem|ModRM|Mov },
+ [0xb6] = { ByteOp|DstReg|SrcMem|ModRM|Mov },
+ [0xb7] = { DstReg|SrcMem16|ModRM|Mov },
+ [0xb8] = { DstReg|SrcMem|ModRM },
+ [0xb9] = { ModRM },
+ [0xba] = { DstBitBase|SrcImmByte|ModRM },
+ [0xbb] = { DstBitBase|SrcReg|ModRM },
+ [0xbc ... 0xbd] = { DstReg|SrcMem|ModRM },
+ [0xbe] = { ByteOp|DstReg|SrcMem|ModRM|Mov },
+ [0xbf] = { DstReg|SrcMem16|ModRM|Mov },
+ [0xc0] = { ByteOp|DstMem|SrcReg|ModRM },
+ [0xc1] = { DstMem|SrcReg|ModRM },
+ [0xc2] = { DstImplicit|SrcImmByte|ModRM, simd_any_fp, d8s_vl },
+ [0xc3] = { DstMem|SrcReg|ModRM|Mov },
+ [0xc4] = { DstImplicit|SrcImmByte|ModRM, simd_none, 1 },
+ [0xc5] = { DstReg|SrcImmByte|ModRM|Mov },
+ [0xc6] = { DstImplicit|SrcImmByte|ModRM, simd_packed_fp, d8s_vl },
+ [0xc7] = { ImplicitOps|ModRM },
+ [0xc8 ... 0xcf] = { ImplicitOps },
+ [0xd0] = { DstImplicit|SrcMem|ModRM, simd_other },
+ [0xd1 ... 0xd3] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
+ [0xd4 ... 0xd5] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xd6] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
+ [0xd7] = { DstReg|SrcImplicit|ModRM|Mov },
+ [0xd8 ... 0xdf] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xe0] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xe1 ... 0xe2] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
+ [0xe3 ... 0xe5] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xe6] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
+ [0xe7] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl },
+ [0xe8 ... 0xef] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xf0] = { DstImplicit|SrcMem|ModRM|Mov, simd_other },
+ [0xf1 ... 0xf3] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
+ [0xf4 ... 0xf6] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xf7] = { DstMem|SrcMem|ModRM|Mov, simd_packed_int },
+ [0xf8 ... 0xfe] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
+ [0xff] = { ModRM }
+};
+
+/*
+ * "two_op" and "four_op" below refer to the number of register operands
+ * (one of which possibly also allowing to be a memory one). The named
+ * operand counts do not include any immediate operands.
+ */
+static const struct ext0f38_table {
+ uint8_t simd_size:5;
+ uint8_t to_mem:1;
+ uint8_t two_op:1;
+ uint8_t vsib:1;
+ disp8scale_t d8s:4;
+} ext0f38_table[256] = {
+ [0x00] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x01 ... 0x03] = { .simd_size = simd_packed_int },
+ [0x04] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x05 ... 0x0a] = { .simd_size = simd_packed_int },
+ [0x0b] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x0c ... 0x0d] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x0e ... 0x0f] = { .simd_size = simd_packed_fp },
+ [0x10 ... 0x12] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x13] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x14 ... 0x16] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x17] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0x18] = { .simd_size = simd_scalar_opc, .two_op = 1, .d8s = 2 },
+ [0x19] = { .simd_size = simd_scalar_opc, .two_op = 1, .d8s = 3 },
+ [0x1a] = { .simd_size = simd_128, .two_op = 1, .d8s = 4 },
+ [0x1b] = { .simd_size = simd_256, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x1c ... 0x1f] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0x20] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x21] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
+ [0x22] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_8 },
+ [0x23] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x24] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
+ [0x25] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x26 ... 0x29] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x2a] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0x2b] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x2c] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x2d] = { .simd_size = simd_packed_fp, .d8s = d8s_dq },
+ [0x2e ... 0x2f] = { .simd_size = simd_packed_fp, .to_mem = 1 },
+ [0x30] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x31] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
+ [0x32] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_8 },
+ [0x33] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x34] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
+ [0x35] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x36 ... 0x3f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x40] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x41] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0x42] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x43] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x44] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0x45 ... 0x47] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x4c] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x4d] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x4e] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x4f] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x50 ... 0x53] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x54 ... 0x55] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0x58] = { .simd_size = simd_other, .two_op = 1, .d8s = 2 },
+ [0x59] = { .simd_size = simd_other, .two_op = 1, .d8s = 3 },
+ [0x5a] = { .simd_size = simd_128, .two_op = 1, .d8s = 4 },
+ [0x5b] = { .simd_size = simd_256, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x62] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_bw },
+ [0x63] = { .simd_size = simd_packed_int, .to_mem = 1, .two_op = 1, .d8s = d8s_bw },
+ [0x64 ... 0x66] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x68] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x70 ... 0x73] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x75 ... 0x76] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x77] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x78] = { .simd_size = simd_other, .two_op = 1 },
+ [0x79] = { .simd_size = simd_other, .two_op = 1, .d8s = 1 },
+ [0x7a ... 0x7c] = { .simd_size = simd_none, .two_op = 1 },
+ [0x7d ... 0x7e] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x7f] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x82] = { .simd_size = simd_other },
+ [0x83] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x88] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_dq },
+ [0x89] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_dq },
+ [0x8a] = { .simd_size = simd_packed_fp, .to_mem = 1, .two_op = 1, .d8s = d8s_dq },
+ [0x8b] = { .simd_size = simd_packed_int, .to_mem = 1, .two_op = 1, .d8s = d8s_dq },
+ [0x8c] = { .simd_size = simd_packed_int },
+ [0x8d] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x8e] = { .simd_size = simd_packed_int, .to_mem = 1 },
+ [0x8f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x90 ... 0x93] = { .simd_size = simd_other, .vsib = 1, .d8s = d8s_dq },
+ [0x96 ... 0x98] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x99] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x9a] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x9b] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x9c] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x9d] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x9e] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x9f] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xa0 ... 0xa3] = { .simd_size = simd_other, .to_mem = 1, .vsib = 1, .d8s = d8s_dq },
+ [0xa6 ... 0xa8] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xa9] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xaa] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xab] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xac] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xad] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xae] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xaf] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xb4 ... 0xb5] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0xb6 ... 0xb8] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xb9] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xba] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xbb] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xbc] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xbd] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xbe] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0xbf] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xc4] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0xc6 ... 0xc7] = { .simd_size = simd_other, .vsib = 1, .d8s = d8s_dq },
+ [0xc8] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0xc9] = { .simd_size = simd_other },
+ [0xca] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0xcb] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xcc] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0xcd] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0xcf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0xdb] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xdc ... 0xdf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0xf0] = { .two_op = 1 },
+ [0xf1] = { .to_mem = 1, .two_op = 1 },
+ [0xf2 ... 0xf3] = {},
+ [0xf5 ... 0xf7] = {},
+ [0xf8] = { .simd_size = simd_other },
+ [0xf9] = { .to_mem = 1, .two_op = 1 /* Mov */ },
+};
+
+static const struct ext0f3a_table {
+ uint8_t simd_size:5;
+ uint8_t to_mem:1;
+ uint8_t two_op:1;
+ uint8_t four_op:1;
+ disp8scale_t d8s:4;
+} ext0f3a_table[256] = {
+ [0x00] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
+ [0x01] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x02] = { .simd_size = simd_packed_int },
+ [0x03] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x04 ... 0x05] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x06] = { .simd_size = simd_packed_fp },
+ [0x08 ... 0x09] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x0a ... 0x0b] = { .simd_size = simd_scalar_opc, .d8s = d8s_dq },
+ [0x0c ... 0x0d] = { .simd_size = simd_packed_fp },
+ [0x0e] = { .simd_size = simd_packed_int },
+ [0x0f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x14] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 0 },
+ [0x15] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 1 },
+ [0x16] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = d8s_dq64 },
+ [0x17] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 2 },
+ [0x18] = { .simd_size = simd_128, .d8s = 4 },
+ [0x19] = { .simd_size = simd_128, .to_mem = 1, .two_op = 1, .d8s = 4 },
+ [0x1a] = { .simd_size = simd_256, .d8s = d8s_vl_by_2 },
+ [0x1b] = { .simd_size = simd_256, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x1d] = { .simd_size = simd_other, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x1e ... 0x1f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x20] = { .simd_size = simd_none, .d8s = 0 },
+ [0x21] = { .simd_size = simd_other, .d8s = 2 },
+ [0x22] = { .simd_size = simd_none, .d8s = d8s_dq64 },
+ [0x23] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x25] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x26] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x27] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x30 ... 0x33] = { .simd_size = simd_other, .two_op = 1 },
+ [0x38] = { .simd_size = simd_128, .d8s = 4 },
+ [0x3a] = { .simd_size = simd_256, .d8s = d8s_vl_by_2 },
+ [0x39] = { .simd_size = simd_128, .to_mem = 1, .two_op = 1, .d8s = 4 },
+ [0x3b] = { .simd_size = simd_256, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x3e ... 0x3f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x40 ... 0x41] = { .simd_size = simd_packed_fp },
+ [0x42 ... 0x43] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x44] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x46] = { .simd_size = simd_packed_int },
+ [0x48 ... 0x49] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x4a ... 0x4b] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x4c] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0x50] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x51] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x54] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x55] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x56] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x57] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x5c ... 0x5f] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x60 ... 0x63] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0x66] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
+ [0x67] = { .simd_size = simd_scalar_vexw, .two_op = 1, .d8s = d8s_dq },
+ [0x68 ... 0x69] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x6a ... 0x6b] = { .simd_size = simd_scalar_opc, .four_op = 1 },
+ [0x6c ... 0x6d] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x6e ... 0x6f] = { .simd_size = simd_scalar_opc, .four_op = 1 },
+ [0x70 ... 0x73] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x78 ... 0x79] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x7a ... 0x7b] = { .simd_size = simd_scalar_opc, .four_op = 1 },
+ [0x7c ... 0x7d] = { .simd_size = simd_packed_fp, .four_op = 1 },
+ [0x7e ... 0x7f] = { .simd_size = simd_scalar_opc, .four_op = 1 },
+ [0xcc] = { .simd_size = simd_other },
+ [0xce ... 0xcf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0xdf] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xf0] = {},
+};
+
+static const opcode_desc_t xop_table[] = {
+ DstReg|SrcImmByte|ModRM,
+ DstReg|SrcMem|ModRM,
+ DstReg|SrcImm|ModRM,
+};
+
+static const struct ext8f08_table {
+ uint8_t simd_size:5;
+ uint8_t two_op:1;
+ uint8_t four_op:1;
+} ext8f08_table[256] = {
+ [0xa2] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0x85 ... 0x87] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0x8e ... 0x8f] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0x95 ... 0x97] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0x9e ... 0x9f] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0xa3] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0xa6] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0xb6] = { .simd_size = simd_packed_int, .four_op = 1 },
+ [0xc0 ... 0xc3] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xcc ... 0xcf] = { .simd_size = simd_packed_int },
+ [0xec ... 0xef] = { .simd_size = simd_packed_int },
+};
+
+static const struct ext8f09_table {
+ uint8_t simd_size:5;
+ uint8_t two_op:1;
+} ext8f09_table[256] = {
+ [0x01 ... 0x02] = { .two_op = 1 },
+ [0x80 ... 0x81] = { .simd_size = simd_packed_fp, .two_op = 1 },
+ [0x82 ... 0x83] = { .simd_size = simd_scalar_opc, .two_op = 1 },
+ [0x90 ... 0x9b] = { .simd_size = simd_packed_int },
+ [0xc1 ... 0xc3] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xc6 ... 0xc7] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xcb] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xd1 ... 0xd3] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xd6 ... 0xd7] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xdb] = { .simd_size = simd_packed_int, .two_op = 1 },
+ [0xe1 ... 0xe3] = { .simd_size = simd_packed_int, .two_op = 1 },
+};
+
+static unsigned int decode_disp8scale(enum disp8scale scale,
+ const struct x86_emulate_state *s)
+{
+ switch ( scale )
+ {
+ case d8s_bw:
+ return s->evex.w;
+
+ default:
+ if ( scale < d8s_vl )
+ return scale;
+ if ( s->evex.brs )
+ {
+ case d8s_dq:
+ return 2 + s->evex.w;
+ }
+ break;
+
+ case d8s_dq64:
+ return 2 + (s->op_bytes == 8);
+ }
+
+ switch ( s->simd_size )
+ {
+ case simd_any_fp:
+ case simd_single_fp:
+ if ( !(s->evex.pfx & VEX_PREFIX_SCALAR_MASK) )
+ break;
+ /* fall through */
+ case simd_scalar_opc:
+ case simd_scalar_vexw:
+ return 2 + s->evex.w;
+
+ case simd_128:
+ /* These should have an explicit size specified. */
+ ASSERT_UNREACHABLE();
+ return 4;
+
+ default:
+ break;
+ }
+
+ return 4 + s->evex.lr - (scale - d8s_vl);
+}
+
+/* Fetch next part of the instruction being emulated. */
+#define insn_fetch_bytes(_size) ({ \
+ unsigned long _x = 0, _ip = s->ip; \
+ s->ip += (_size); /* real hardware doesn't truncate */ \
+ generate_exception_if((uint8_t)(s->ip - \
+ ctxt->regs->r(ip)) > MAX_INST_LEN, \
+ X86_EXC_GP, 0); \
+ rc = ops->insn_fetch(x86_seg_cs, _ip, &_x, _size, ctxt); \
+ if ( rc ) goto done; \
+ _x; \
+})
+#define insn_fetch_type(type) ((type)insn_fetch_bytes(sizeof(type)))
+
+static int
+decode_onebyte(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ int rc = X86EMUL_OKAY;
+
+ switch ( ctxt->opcode )
+ {
+ case 0x06: /* push %%es */
+ case 0x07: /* pop %%es */
+ case 0x0e: /* push %%cs */
+ case 0x16: /* push %%ss */
+ case 0x17: /* pop %%ss */
+ case 0x1e: /* push %%ds */
+ case 0x1f: /* pop %%ds */
+ case 0x27: /* daa */
+ case 0x2f: /* das */
+ case 0x37: /* aaa */
+ case 0x3f: /* aas */
+ case 0x60: /* pusha */
+ case 0x61: /* popa */
+ case 0x62: /* bound */
+ case 0xc4: /* les */
+ case 0xc5: /* lds */
+ case 0xce: /* into */
+ case 0xd4: /* aam */
+ case 0xd5: /* aad */
+ case 0xd6: /* salc */
+ s->not_64bit = true;
+ break;
+
+ case 0x82: /* Grp1 (x86/32 only) */
+ s->not_64bit = true;
+ /* fall through */
+ case 0x80: case 0x81: case 0x83: /* Grp1 */
+ if ( (s->modrm_reg & 7) == 7 ) /* cmp */
+ s->desc = (s->desc & ByteOp) | DstNone | SrcMem;
+ break;
+
+ case 0x90: /* nop / pause */
+ if ( s->vex.pfx == vex_f3 )
+ ctxt->opcode |= X86EMUL_OPC_F3(0, 0);
+ break;
+
+ case 0x9a: /* call (far, absolute) */
+ case 0xea: /* jmp (far, absolute) */
+ generate_exception_if(mode_64bit(), X86_EXC_UD);
+
+ s->imm1 = insn_fetch_bytes(s->op_bytes);
+ s->imm2 = insn_fetch_type(uint16_t);
+ break;
+
+ case 0xa0: case 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
+ case 0xa2: case 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
+ /* Source EA is not encoded via ModRM. */
+ s->ea.type = OP_MEM;
+ s->ea.mem.off = insn_fetch_bytes(s->ad_bytes);
+ break;
+
+ case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */
+ if ( s->op_bytes == 8 ) /* Fetch more bytes to obtain imm64. */
+ s->imm1 = ((uint32_t)s->imm1 |
+ ((uint64_t)insn_fetch_type(uint32_t) << 32));
+ break;
+
+ case 0xc8: /* enter imm16,imm8 */
+ s->imm2 = insn_fetch_type(uint8_t);
+ break;
+
+ case 0xf6: case 0xf7: /* Grp3 */
+ if ( !(s->modrm_reg & 6) ) /* test */
+ s->desc = (s->desc & ByteOp) | DstNone | SrcMem;
+ break;
+
+ case 0xff: /* Grp5 */
+ switch ( s->modrm_reg & 7 )
+ {
+ case 2: /* call (near) */
+ case 4: /* jmp (near) */
+ if ( mode_64bit() && (s->op_bytes == 4 || !amd_like(ctxt)) )
+ s->op_bytes = 8;
+ s->desc = DstNone | SrcMem | Mov;
+ break;
+
+ case 3: /* call (far, absolute indirect) */
+ case 5: /* jmp (far, absolute indirect) */
+ /* REX.W ignored on a vendor-dependent basis. */
+ if ( s->op_bytes == 8 && amd_like(ctxt) )
+ s->op_bytes = 4;
+ s->desc = DstNone | SrcMem | Mov;
+ break;
+
+ case 6: /* push */
+ if ( mode_64bit() && s->op_bytes == 4 )
+ s->op_bytes = 8;
+ s->desc = DstNone | SrcMem | Mov;
+ break;
+ }
+ break;
+ }
+
+ done:
+ return rc;
+}
+
+static int
+decode_twobyte(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ int rc = X86EMUL_OKAY;
+
+ switch ( ctxt->opcode & X86EMUL_OPC_MASK )
+ {
+ case 0x00: /* Grp6 */
+ switch ( s->modrm_reg & 6 )
+ {
+ case 0:
+ s->desc |= DstMem | SrcImplicit | Mov;
+ break;
+ case 2: case 4:
+ s->desc |= SrcMem16;
+ break;
+ }
+ break;
+
+ case 0x78:
+ s->desc = ImplicitOps;
+ s->simd_size = simd_none;
+ switch ( s->vex.pfx )
+ {
+ case vex_66: /* extrq $imm8, $imm8, xmm */
+ case vex_f2: /* insertq $imm8, $imm8, xmm, xmm */
+ s->imm1 = insn_fetch_type(uint8_t);
+ s->imm2 = insn_fetch_type(uint8_t);
+ break;
+ }
+ /* fall through */
+ case 0x10 ... 0x18:
+ case 0x28 ... 0x2f:
+ case 0x50 ... 0x77:
+ case 0x7a ... 0x7d:
+ case 0x7f:
+ case 0xc2 ... 0xc3:
+ case 0xc5 ... 0xc6:
+ case 0xd0 ... 0xef:
+ case 0xf1 ... 0xfe:
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ case 0x20: case 0x22: /* mov to/from cr */
+ if ( s->lock_prefix && vcpu_has_cr8_legacy() )
+ {
+ s->modrm_reg += 8;
+ s->lock_prefix = false;
+ }
+ /* fall through */
+ case 0x21: case 0x23: /* mov to/from dr */
+ ASSERT(s->ea.type == OP_REG); /* Early operand adjustment ensures this. */
+ generate_exception_if(s->lock_prefix, X86_EXC_UD);
+ s->op_bytes = mode_64bit() ? 8 : 4;
+ break;
+
+ case 0x79:
+ s->desc = DstReg | SrcMem;
+ s->simd_size = simd_packed_int;
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ case 0x7e:
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ if ( s->vex.pfx == vex_f3 ) /* movq xmm/m64,xmm */
+ {
+ case X86EMUL_OPC_VEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
+ case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
+ s->desc = DstImplicit | SrcMem | TwoOp;
+ s->simd_size = simd_other;
+ /* Avoid the s->desc clobbering of TwoOp below. */
+ return X86EMUL_OKAY;
+ }
+ break;
+
+ case X86EMUL_OPC_VEX(0, 0x90): /* kmov{w,q} */
+ case X86EMUL_OPC_VEX_66(0, 0x90): /* kmov{b,d} */
+ s->desc = DstReg | SrcMem | Mov;
+ s->simd_size = simd_other;
+ break;
+
+ case X86EMUL_OPC_VEX(0, 0x91): /* kmov{w,q} */
+ case X86EMUL_OPC_VEX_66(0, 0x91): /* kmov{b,d} */
+ s->desc = DstMem | SrcReg | Mov;
+ s->simd_size = simd_other;
+ break;
+
+ case 0xae:
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ /* fall through */
+ case X86EMUL_OPC_VEX(0, 0xae):
+ switch ( s->modrm_reg & 7 )
+ {
+ case 2: /* {,v}ldmxcsr */
+ s->desc = DstImplicit | SrcMem | Mov;
+ s->op_bytes = 4;
+ break;
+
+ case 3: /* {,v}stmxcsr */
+ s->desc = DstMem | SrcImplicit | Mov;
+ s->op_bytes = 4;
+ break;
+ }
+ break;
+
+ case 0xb2: /* lss */
+ case 0xb4: /* lfs */
+ case 0xb5: /* lgs */
+ /* REX.W ignored on a vendor-dependent basis. */
+ if ( s->op_bytes == 8 && amd_like(ctxt) )
+ s->op_bytes = 4;
+ break;
+
+ case 0xb8: /* jmpe / popcnt */
+ if ( s->vex.pfx >= vex_f3 )
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ /* Intentionally not handling here despite being modified by F3:
+ case 0xbc: bsf / tzcnt
+ case 0xbd: bsr / lzcnt
+ * They're being dealt with in the execution phase (if at all).
+ */
+
+ case 0xc4: /* pinsrw */
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ /* fall through */
+ case X86EMUL_OPC_VEX_66(0, 0xc4): /* vpinsrw */
+ case X86EMUL_OPC_EVEX_66(0, 0xc4): /* vpinsrw */
+ s->desc = DstImplicit | SrcMem16;
+ break;
+
+ case 0xf0:
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ if ( s->vex.pfx == vex_f2 ) /* lddqu mem,xmm */
+ {
+ /* fall through */
+ case X86EMUL_OPC_VEX_F2(0, 0xf0): /* vlddqu mem,{x,y}mm */
+ s->desc = DstImplicit | SrcMem | TwoOp;
+ s->simd_size = simd_other;
+ /* Avoid the s->desc clobbering of TwoOp below. */
+ return X86EMUL_OKAY;
+ }
+ break;
+ }
+
+ /*
+ * Scalar forms of most VEX-/EVEX-encoded TwoOp instructions have
+ * three operands. Those which do really have two operands
+ * should have exited earlier.
+ */
+ if ( s->simd_size && s->vex.opcx &&
+ (s->vex.pfx & VEX_PREFIX_SCALAR_MASK) )
+ s->desc &= ~TwoOp;
+
+ done:
+ return rc;
+}
+
+static int
+decode_0f38(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ switch ( ctxt->opcode & X86EMUL_OPC_MASK )
+ {
+ case 0x00 ... 0xef:
+ case 0xf2 ... 0xf5:
+ case 0xf7 ... 0xf8:
+ case 0xfa ... 0xff:
+ s->op_bytes = 0;
+ /* fall through */
+ case 0xf6: /* adcx / adox */
+ case 0xf9: /* movdiri */
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ case X86EMUL_OPC_EVEX_66(0, 0x2d): /* vscalefs{s,d} */
+ s->simd_size = simd_scalar_vexw;
+ break;
+
+ case X86EMUL_OPC_EVEX_66(0, 0x7a): /* vpbroadcastb */
+ case X86EMUL_OPC_EVEX_66(0, 0x7b): /* vpbroadcastw */
+ case X86EMUL_OPC_EVEX_66(0, 0x7c): /* vpbroadcast{d,q} */
+ break;
+
+ case 0xf0: /* movbe / crc32 */
+ s->desc |= s->vex.pfx == vex_f2 ? ByteOp : Mov;
+ if ( s->vex.pfx >= vex_f3 )
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ case 0xf1: /* movbe / crc32 */
+ if ( s->vex.pfx == vex_f2 )
+ s->desc = DstReg | SrcMem;
+ if ( s->vex.pfx >= vex_f3 )
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+ break;
+
+ case X86EMUL_OPC_VEX(0, 0xf2): /* andn */
+ case X86EMUL_OPC_VEX(0, 0xf3): /* Grp 17 */
+ case X86EMUL_OPC_VEX(0, 0xf5): /* bzhi */
+ case X86EMUL_OPC_VEX_F3(0, 0xf5): /* pext */
+ case X86EMUL_OPC_VEX_F2(0, 0xf5): /* pdep */
+ case X86EMUL_OPC_VEX_F2(0, 0xf6): /* mulx */
+ case X86EMUL_OPC_VEX(0, 0xf7): /* bextr */
+ case X86EMUL_OPC_VEX_66(0, 0xf7): /* shlx */
+ case X86EMUL_OPC_VEX_F3(0, 0xf7): /* sarx */
+ case X86EMUL_OPC_VEX_F2(0, 0xf7): /* shrx */
+ break;
+
+ default:
+ s->op_bytes = 0;
+ break;
+ }
+
+ return X86EMUL_OKAY;
+}
+
+static int
+decode_0f3a(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ if ( !s->vex.opcx )
+ ctxt->opcode |= MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+
+ switch ( ctxt->opcode & X86EMUL_OPC_MASK )
+ {
+ case X86EMUL_OPC_66(0, 0x14)
+ ... X86EMUL_OPC_66(0, 0x17): /* pextr*, extractps */
+ case X86EMUL_OPC_VEX_66(0, 0x14)
+ ... X86EMUL_OPC_VEX_66(0, 0x17): /* vpextr*, vextractps */
+ case X86EMUL_OPC_EVEX_66(0, 0x14)
+ ... X86EMUL_OPC_EVEX_66(0, 0x17): /* vpextr*, vextractps */
+ case X86EMUL_OPC_VEX_F2(0, 0xf0): /* rorx */
+ break;
+
+ case X86EMUL_OPC_66(0, 0x20): /* pinsrb */
+ case X86EMUL_OPC_VEX_66(0, 0x20): /* vpinsrb */
+ case X86EMUL_OPC_EVEX_66(0, 0x20): /* vpinsrb */
+ s->desc = DstImplicit | SrcMem;
+ if ( s->modrm_mod != 3 )
+ s->desc |= ByteOp;
+ break;
+
+ case X86EMUL_OPC_66(0, 0x22): /* pinsr{d,q} */
+ case X86EMUL_OPC_VEX_66(0, 0x22): /* vpinsr{d,q} */
+ case X86EMUL_OPC_EVEX_66(0, 0x22): /* vpinsr{d,q} */
+ s->desc = DstImplicit | SrcMem;
+ break;
+
+ default:
+ s->op_bytes = 0;
+ break;
+ }
+
+ return X86EMUL_OKAY;
+}
+
+#define ad_bytes (s->ad_bytes) /* for truncate_ea() */
+
+int x86emul_decode(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ uint8_t b, d;
+ unsigned int def_op_bytes, def_ad_bytes, opcode;
+ enum x86_segment override_seg = x86_seg_none;
+ bool pc_rel = false;
+ int rc = X86EMUL_OKAY;
+
+ ASSERT(ops->insn_fetch);
+
+ memset(s, 0, sizeof(*s));
+ s->ea.type = OP_NONE;
+ s->ea.mem.seg = x86_seg_ds;
+ s->ea.reg = PTR_POISON;
+ s->regs = ctxt->regs;
+ s->ip = ctxt->regs->r(ip);
+
+ s->op_bytes = def_op_bytes = ad_bytes = def_ad_bytes =
+ ctxt->addr_size / 8;
+ if ( s->op_bytes == 8 )
+ {
+ s->op_bytes = def_op_bytes = 4;
+#ifndef __x86_64__
+ return X86EMUL_UNHANDLEABLE;
+#endif
+ }
+
+ /* Prefix bytes. */
+ for ( ; ; )
+ {
+ switch ( b = insn_fetch_type(uint8_t) )
+ {
+ case 0x66: /* operand-size override */
+ s->op_bytes = def_op_bytes ^ 6;
+ if ( !s->vex.pfx )
+ s->vex.pfx = vex_66;
+ break;
+ case 0x67: /* address-size override */
+ ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6);
+ break;
+ case 0x2e: /* CS override / ignored in 64-bit mode */
+ if ( !mode_64bit() )
+ override_seg = x86_seg_cs;
+ break;
+ case 0x3e: /* DS override / ignored in 64-bit mode */
+ if ( !mode_64bit() )
+ override_seg = x86_seg_ds;
+ break;
+ case 0x26: /* ES override / ignored in 64-bit mode */
+ if ( !mode_64bit() )
+ override_seg = x86_seg_es;
+ break;
+ case 0x64: /* FS override */
+ override_seg = x86_seg_fs;
+ break;
+ case 0x65: /* GS override */
+ override_seg = x86_seg_gs;
+ break;
+ case 0x36: /* SS override / ignored in 64-bit mode */
+ if ( !mode_64bit() )
+ override_seg = x86_seg_ss;
+ break;
+ case 0xf0: /* LOCK */
+ s->lock_prefix = true;
+ break;
+ case 0xf2: /* REPNE/REPNZ */
+ s->vex.pfx = vex_f2;
+ break;
+ case 0xf3: /* REP/REPE/REPZ */
+ s->vex.pfx = vex_f3;
+ break;
+ case 0x40 ... 0x4f: /* REX */
+ if ( !mode_64bit() )
+ goto done_prefixes;
+ s->rex_prefix = b;
+ continue;
+ default:
+ goto done_prefixes;
+ }
+
+ /* Any legacy prefix after a REX prefix nullifies its effect. */
+ s->rex_prefix = 0;
+ }
+ done_prefixes:
+
+ if ( s->rex_prefix & REX_W )
+ s->op_bytes = 8;
+
+ /* Opcode byte(s). */
+ d = opcode_table[b];
+ if ( d == 0 && b == 0x0f )
+ {
+ /* Two-byte opcode. */
+ b = insn_fetch_type(uint8_t);
+ d = twobyte_table[b].desc;
+ switch ( b )
+ {
+ default:
+ opcode = b | MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK);
+ s->ext = ext_0f;
+ s->simd_size = twobyte_table[b].size;
+ break;
+ case 0x38:
+ b = insn_fetch_type(uint8_t);
+ opcode = b | MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK);
+ s->ext = ext_0f38;
+ break;
+ case 0x3a:
+ b = insn_fetch_type(uint8_t);
+ opcode = b | MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK);
+ s->ext = ext_0f3a;
+ break;
+ }
+ }
+ else
+ opcode = b;
+
+ /* ModRM and SIB bytes. */
+ if ( d & ModRM )
+ {
+ s->modrm = insn_fetch_type(uint8_t);
+ s->modrm_mod = (s->modrm & 0xc0) >> 6;
+
+ if ( !s->ext && ((b & ~1) == 0xc4 || (b == 0x8f && (s->modrm & 0x18)) ||
+ b == 0x62) )
+ switch ( def_ad_bytes )
+ {
+ default:
+ BUG(); /* Shouldn't be possible. */
+ case 2:
+ if ( s->regs->eflags & X86_EFLAGS_VM )
+ break;
+ /* fall through */
+ case 4:
+ if ( s->modrm_mod != 3 || in_realmode(ctxt, ops) )
+ break;
+ /* fall through */
+ case 8:
+ /* VEX / XOP / EVEX */
+ generate_exception_if(s->rex_prefix || s->vex.pfx, X86_EXC_UD);
+ /*
+ * With operand size override disallowed (see above), op_bytes
+ * should not have changed from its default.
+ */
+ ASSERT(s->op_bytes == def_op_bytes);
+
+ s->vex.raw[0] = s->modrm;
+ if ( b == 0xc5 )
+ {
+ opcode = X86EMUL_OPC_VEX_;
+ s->vex.raw[1] = s->modrm;
+ s->vex.opcx = vex_0f;
+ s->vex.x = 1;
+ s->vex.b = 1;
+ s->vex.w = 0;
+ }
+ else
+ {
+ s->vex.raw[1] = insn_fetch_type(uint8_t);
+ if ( mode_64bit() )
+ {
+ if ( !s->vex.b )
+ s->rex_prefix |= REX_B;
+ if ( !s->vex.x )
+ s->rex_prefix |= REX_X;
+ if ( s->vex.w )
+ {
+ s->rex_prefix |= REX_W;
+ s->op_bytes = 8;
+ }
+ }
+ else
+ {
+ /* Operand size fixed at 4 (no override via W bit). */
+ s->op_bytes = 4;
+ s->vex.b = 1;
+ }
+ switch ( b )
+ {
+ case 0x62:
+ opcode = X86EMUL_OPC_EVEX_;
+ s->evex.raw[0] = s->vex.raw[0];
+ s->evex.raw[1] = s->vex.raw[1];
+ s->evex.raw[2] = insn_fetch_type(uint8_t);
+
+ generate_exception_if(!s->evex.mbs || s->evex.mbz, X86_EXC_UD);
+ generate_exception_if(!s->evex.opmsk && s->evex.z, X86_EXC_UD);
+
+ if ( !mode_64bit() )
+ s->evex.R = 1;
+
+ s->vex.opcx = s->evex.opcx;
+ break;
+ case 0xc4:
+ opcode = X86EMUL_OPC_VEX_;
+ break;
+ default:
+ opcode = 0;
+ break;
+ }
+ }
+ if ( !s->vex.r )
+ s->rex_prefix |= REX_R;
+
+ s->ext = s->vex.opcx;
+ if ( b != 0x8f )
+ {
+ b = insn_fetch_type(uint8_t);
+ switch ( s->ext )
+ {
+ case vex_0f:
+ opcode |= MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK);
+ d = twobyte_table[b].desc;
+ s->simd_size = twobyte_table[b].size;
+ break;
+ case vex_0f38:
+ opcode |= MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK);
+ d = twobyte_table[0x38].desc;
+ break;
+ case vex_0f3a:
+ opcode |= MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK);
+ d = twobyte_table[0x3a].desc;
+ break;
+ default:
+ rc = X86EMUL_UNRECOGNIZED;
+ goto done;
+ }
+ }
+ else if ( s->ext < ext_8f08 + ARRAY_SIZE(xop_table) )
+ {
+ b = insn_fetch_type(uint8_t);
+ opcode |= MASK_INSR(0x8f08 + s->ext - ext_8f08,
+ X86EMUL_OPC_EXT_MASK);
+ d = array_access_nospec(xop_table, s->ext - ext_8f08);
+ }
+ else
+ {
+ rc = X86EMUL_UNRECOGNIZED;
+ goto done;
+ }
+
+ opcode |= b | MASK_INSR(s->vex.pfx, X86EMUL_OPC_PFX_MASK);
+
+ if ( !evex_encoded() )
+ s->evex.lr = s->vex.l;
+
+ if ( !(d & ModRM) )
+ break;
+
+ s->modrm = insn_fetch_type(uint8_t);
+ s->modrm_mod = (s->modrm & 0xc0) >> 6;
+
+ break;
+ }
+ }
+
+ if ( d & ModRM )
+ {
+ unsigned int disp8scale = 0;
+
+ d &= ~ModRM;
+#undef ModRM /* Only its aliases are valid to use from here on. */
+ s->modrm_reg = ((s->rex_prefix & 4) << 1) | ((s->modrm & 0x38) >> 3) |
+ ((evex_encoded() && !s->evex.R) << 4);
+ s->modrm_rm = s->modrm & 0x07;
+
+ /*
+ * Early operand adjustments. Only ones affecting further processing
+ * prior to the x86_decode_*() calls really belong here. That would
+ * normally be only addition/removal of SrcImm/SrcImm16, so their
+ * fetching can be taken care of by the common code below.
+ */
+ switch ( s->ext )
+ {
+ case ext_none:
+ switch ( b )
+ {
+ case 0xf6 ... 0xf7: /* Grp3 */
+ switch ( s->modrm_reg & 7 )
+ {
+ case 0 ... 1: /* test */
+ d |= DstMem | SrcImm;
+ break;
+ case 2: /* not */
+ case 3: /* neg */
+ d |= DstMem;
+ break;
+ case 4: /* mul */
+ case 5: /* imul */
+ case 6: /* div */
+ case 7: /* idiv */
+ /*
+ * DstEax isn't really precise for all cases; updates to
+ * rDX get handled in an open coded manner.
+ */
+ d |= DstEax | SrcMem;
+ break;
+ }
+ break;
+ }
+ break;
+
+ case ext_0f:
+ if ( evex_encoded() )
+ disp8scale = decode_disp8scale(twobyte_table[b].d8s, s);
+
+ switch ( b )
+ {
+ case 0x12: /* vmovsldup / vmovddup */
+ if ( s->evex.pfx == vex_f2 )
+ disp8scale = s->evex.lr ? 4 + s->evex.lr : 3;
+ /* fall through */
+ case 0x16: /* vmovshdup */
+ if ( s->evex.pfx == vex_f3 )
+ disp8scale = 4 + s->evex.lr;
+ break;
+
+ case 0x20: /* mov cr,reg */
+ case 0x21: /* mov dr,reg */
+ case 0x22: /* mov reg,cr */
+ case 0x23: /* mov reg,dr */
+ /*
+ * Mov to/from cr/dr ignore the encoding of Mod, and behave as
+ * if they were encoded as reg/reg instructions. No further
+ * disp/SIB bytes are fetched.
+ */
+ s->modrm_mod = 3;
+ break;
+
+ case 0x78:
+ case 0x79:
+ if ( !s->evex.pfx )
+ break;
+ /* vcvt{,t}ps2uqq need special casing */
+ if ( s->evex.pfx == vex_66 )
+ {
+ if ( !s->evex.w && !s->evex.brs )
+ --disp8scale;
+ break;
+ }
+ /* vcvt{,t}s{s,d}2usi need special casing: fall through */
+ case 0x2c: /* vcvtts{s,d}2si need special casing */
+ case 0x2d: /* vcvts{s,d}2si need special casing */
+ if ( evex_encoded() )
+ disp8scale = 2 + (s->evex.pfx & VEX_PREFIX_DOUBLE_MASK);
+ break;
+
+ case 0x5a: /* vcvtps2pd needs special casing */
+ if ( disp8scale && !s->evex.pfx && !s->evex.brs )
+ --disp8scale;
+ break;
+
+ case 0x7a: /* vcvttps2qq and vcvtudq2pd need special casing */
+ if ( disp8scale && s->evex.pfx != vex_f2 && !s->evex.w && !s->evex.brs )
+ --disp8scale;
+ break;
+
+ case 0x7b: /* vcvtp{s,d}2qq need special casing */
+ if ( disp8scale && s->evex.pfx == vex_66 )
+ disp8scale = (s->evex.brs ? 2 : 3 + s->evex.lr) + s->evex.w;
+ break;
+
+ case 0x7e: /* vmovq xmm/m64,xmm needs special casing */
+ if ( disp8scale == 2 && s->evex.pfx == vex_f3 )
+ disp8scale = 3;
+ break;
+
+ case 0xe6: /* vcvtdq2pd needs special casing */
+ if ( disp8scale && s->evex.pfx == vex_f3 && !s->evex.w && !s->evex.brs )
+ --disp8scale;
+ break;
+ }
+ break;
+
+ case ext_0f38:
+ d = ext0f38_table[b].to_mem ? DstMem | SrcReg
+ : DstReg | SrcMem;
+ if ( ext0f38_table[b].two_op )
+ d |= TwoOp;
+ if ( ext0f38_table[b].vsib )
+ d |= vSIB;
+ s->simd_size = ext0f38_table[b].simd_size;
+ if ( evex_encoded() )
+ {
+ /*
+ * VPMOVUS* are identical to VPMOVS* Disp8-scaling-wise, but
+ * their attributes don't match those of the vex_66 encoded
+ * insns with the same base opcodes. Rather than adding new
+ * columns to the table, handle this here for now.
+ */
+ if ( s->evex.pfx != vex_f3 || (b & 0xf8) != 0x10 )
+ disp8scale = decode_disp8scale(ext0f38_table[b].d8s, s);
+ else
+ {
+ disp8scale = decode_disp8scale(ext0f38_table[b ^ 0x30].d8s,
+ s);
+ s->simd_size = simd_other;
+ }
+
+ switch ( b )
+ {
+ /* vp4dpwssd{,s} need special casing */
+ case 0x52: case 0x53:
+ /* v4f{,n}madd{p,s}s need special casing */
+ case 0x9a: case 0x9b: case 0xaa: case 0xab:
+ if ( s->evex.pfx == vex_f2 )
+ {
+ disp8scale = 4;
+ s->simd_size = simd_128;
+ }
+ break;
+ }
+ }
+ break;
+
+ case ext_0f3a:
+ /*
+ * Cannot update d here yet, as the immediate operand still
+ * needs fetching.
+ */
+ s->simd_size = ext0f3a_table[b].simd_size;
+ if ( evex_encoded() )
+ disp8scale = decode_disp8scale(ext0f3a_table[b].d8s, s);
+ break;
+
+ case ext_8f09:
+ if ( ext8f09_table[b].two_op )
+ d |= TwoOp;
+ s->simd_size = ext8f09_table[b].simd_size;
+ break;
+
+ case ext_8f08:
+ case ext_8f0a:
+ /*
+ * Cannot update d here yet, as the immediate operand still
+ * needs fetching.
+ */
+ break;
+
+ default:
+ ASSERT_UNREACHABLE();
+ return X86EMUL_UNIMPLEMENTED;
+ }
+
+ if ( s->modrm_mod == 3 )
+ {
+ generate_exception_if(d & vSIB, X86_EXC_UD);
+ s->modrm_rm |= ((s->rex_prefix & 1) << 3) |
+ ((evex_encoded() && !s->evex.x) << 4);
+ s->ea.type = OP_REG;
+ }
+ else if ( ad_bytes == 2 )
+ {
+ /* 16-bit ModR/M decode. */
+ generate_exception_if(d & vSIB, X86_EXC_UD);
+ s->ea.type = OP_MEM;
+ switch ( s->modrm_rm )
+ {
+ case 0:
+ s->ea.mem.off = s->regs->bx + s->regs->si;
+ break;
+ case 1:
+ s->ea.mem.off = s->regs->bx + s->regs->di;
+ break;
+ case 2:
+ s->ea.mem.seg = x86_seg_ss;
+ s->ea.mem.off = s->regs->bp + s->regs->si;
+ break;
+ case 3:
+ s->ea.mem.seg = x86_seg_ss;
+ s->ea.mem.off = s->regs->bp + s->regs->di;
+ break;
+ case 4:
+ s->ea.mem.off = s->regs->si;
+ break;
+ case 5:
+ s->ea.mem.off = s->regs->di;
+ break;
+ case 6:
+ if ( s->modrm_mod == 0 )
+ break;
+ s->ea.mem.seg = x86_seg_ss;
+ s->ea.mem.off = s->regs->bp;
+ break;
+ case 7:
+ s->ea.mem.off = s->regs->bx;
+ break;
+ }
+ switch ( s->modrm_mod )
+ {
+ case 0:
+ if ( s->modrm_rm == 6 )
+ s->ea.mem.off = insn_fetch_type(int16_t);
+ break;
+ case 1:
+ s->ea.mem.off += insn_fetch_type(int8_t) * (1 << disp8scale);
+ break;
+ case 2:
+ s->ea.mem.off += insn_fetch_type(int16_t);
+ break;
+ }
+ }
+ else
+ {
+ /* 32/64-bit ModR/M decode. */
+ s->ea.type = OP_MEM;
+ if ( s->modrm_rm == 4 )
+ {
+ uint8_t sib = insn_fetch_type(uint8_t);
+ uint8_t sib_base = (sib & 7) | ((s->rex_prefix << 3) & 8);
+
+ s->sib_index = ((sib >> 3) & 7) | ((s->rex_prefix << 2) & 8);
+ s->sib_scale = (sib >> 6) & 3;
+ if ( unlikely(d & vSIB) )
+ s->sib_index |= (mode_64bit() && evex_encoded() &&
+ !s->evex.RX) << 4;
+ else if ( s->sib_index != 4 )
+ {
+ s->ea.mem.off = *decode_gpr(s->regs, s->sib_index);
+ s->ea.mem.off <<= s->sib_scale;
+ }
+ if ( (s->modrm_mod == 0) && ((sib_base & 7) == 5) )
+ s->ea.mem.off += insn_fetch_type(int32_t);
+ else if ( sib_base == 4 )
+ {
+ s->ea.mem.seg = x86_seg_ss;
+ s->ea.mem.off += s->regs->r(sp);
+ if ( !s->ext && (b == 0x8f) )
+ /* POP <rm> computes its EA post increment. */
+ s->ea.mem.off += ((mode_64bit() && (s->op_bytes == 4))
+ ? 8 : s->op_bytes);
+ }
+ else if ( sib_base == 5 )
+ {
+ s->ea.mem.seg = x86_seg_ss;
+ s->ea.mem.off += s->regs->r(bp);
+ }
+ else
+ s->ea.mem.off += *decode_gpr(s->regs, sib_base);
+ }
+ else
+ {
+ generate_exception_if(d & vSIB, X86_EXC_UD);
+ s->modrm_rm |= (s->rex_prefix & 1) << 3;
+ s->ea.mem.off = *decode_gpr(s->regs, s->modrm_rm);
+ if ( (s->modrm_rm == 5) && (s->modrm_mod != 0) )
+ s->ea.mem.seg = x86_seg_ss;
+ }
+ switch ( s->modrm_mod )
+ {
+ case 0:
+ if ( (s->modrm_rm & 7) != 5 )
+ break;
+ s->ea.mem.off = insn_fetch_type(int32_t);
+ pc_rel = mode_64bit();
+ break;
+ case 1:
+ s->ea.mem.off += insn_fetch_type(int8_t) * (1 << disp8scale);
+ break;
+ case 2:
+ s->ea.mem.off += insn_fetch_type(int32_t);
+ break;
+ }
+ }
+ }
+ else
+ {
+ s->modrm_mod = 0xff;
+ s->modrm_reg = s->modrm_rm = s->modrm = 0;
+ }
+
+ if ( override_seg != x86_seg_none )
+ s->ea.mem.seg = override_seg;
+
+ /* Fetch the immediate operand, if present. */
+ switch ( d & SrcMask )
+ {
+ unsigned int bytes;
+
+ case SrcImm:
+ if ( !(d & ByteOp) )
+ {
+ if ( mode_64bit() && !amd_like(ctxt) &&
+ ((s->ext == ext_none && (b | 1) == 0xe9) /* call / jmp */ ||
+ (s->ext == ext_0f && (b | 0xf) == 0x8f) /* jcc */ ) )
+ s->op_bytes = 4;
+ bytes = s->op_bytes != 8 ? s->op_bytes : 4;
+ }
+ else
+ {
+ case SrcImmByte:
+ bytes = 1;
+ }
+ /* NB. Immediates are sign-extended as necessary. */
+ switch ( bytes )
+ {
+ case 1: s->imm1 = insn_fetch_type(int8_t); break;
+ case 2: s->imm1 = insn_fetch_type(int16_t); break;
+ case 4: s->imm1 = insn_fetch_type(int32_t); break;
+ }
+ break;
+ case SrcImm16:
+ s->imm1 = insn_fetch_type(uint16_t);
+ break;
+ }
+
+ ctxt->opcode = opcode;
+ s->desc = d;
+
+ switch ( s->ext )
+ {
+ case ext_none:
+ rc = decode_onebyte(s, ctxt, ops);
+ break;
+
+ case ext_0f:
+ rc = decode_twobyte(s, ctxt, ops);
+ break;
+
+ case ext_0f38:
+ rc = decode_0f38(s, ctxt, ops);
+ break;
+
+ case ext_0f3a:
+ d = ext0f3a_table[b].to_mem ? DstMem | SrcReg : DstReg | SrcMem;
+ if ( ext0f3a_table[b].two_op )
+ d |= TwoOp;
+ else if ( ext0f3a_table[b].four_op && !mode_64bit() && s->vex.opcx )
+ s->imm1 &= 0x7f;
+ s->desc = d;
+ rc = decode_0f3a(s, ctxt, ops);
+ break;
+
+ case ext_8f08:
+ d = DstReg | SrcMem;
+ if ( ext8f08_table[b].two_op )
+ d |= TwoOp;
+ else if ( ext8f08_table[b].four_op && !mode_64bit() )
+ s->imm1 &= 0x7f;
+ s->desc = d;
+ s->simd_size = ext8f08_table[b].simd_size;
+ break;
+
+ case ext_8f09:
+ case ext_8f0a:
+ break;
+
+ default:
+ ASSERT_UNREACHABLE();
+ return X86EMUL_UNIMPLEMENTED;
+ }
+
+ if ( s->ea.type == OP_MEM )
+ {
+ if ( pc_rel )
+ s->ea.mem.off += s->ip;
+
+ s->ea.mem.off = truncate_ea(s->ea.mem.off);
+ }
+
+ /*
+ * Simple op_bytes calculations. More complicated cases produce 0
+ * and are further handled during execute.
+ */
+ switch ( s->simd_size )
+ {
+ case simd_none:
+ /*
+ * When prefix 66 has a meaning different from operand-size override,
+ * operand size defaults to 4 and can't be overridden to 2.
+ */
+ if ( s->op_bytes == 2 &&
+ (ctxt->opcode & X86EMUL_OPC_PFX_MASK) == X86EMUL_OPC_66(0, 0) )
+ s->op_bytes = 4;
+ break;
+
+#ifndef X86EMUL_NO_SIMD
+ case simd_packed_int:
+ switch ( s->vex.pfx )
+ {
+ case vex_none:
+ if ( !s->vex.opcx )
+ {
+ s->op_bytes = 8;
+ break;
+ }
+ /* fall through */
+ case vex_66:
+ s->op_bytes = 16 << s->evex.lr;
+ break;
+ default:
+ s->op_bytes = 0;
+ break;
+ }
+ break;
+
+ case simd_single_fp:
+ if ( s->vex.pfx & VEX_PREFIX_DOUBLE_MASK )
+ {
+ s->op_bytes = 0;
+ break;
+ case simd_packed_fp:
+ if ( s->vex.pfx & VEX_PREFIX_SCALAR_MASK )
+ {
+ s->op_bytes = 0;
+ break;
+ }
+ }
+ /* fall through */
+ case simd_any_fp:
+ switch ( s->vex.pfx )
+ {
+ default:
+ s->op_bytes = 16 << s->evex.lr;
+ break;
+ case vex_f3:
+ generate_exception_if(evex_encoded() && s->evex.w, X86_EXC_UD);
+ s->op_bytes = 4;
+ break;
+ case vex_f2:
+ generate_exception_if(evex_encoded() && !s->evex.w, X86_EXC_UD);
+ s->op_bytes = 8;
+ break;
+ }
+ break;
+
+ case simd_scalar_opc:
+ s->op_bytes = 4 << (ctxt->opcode & 1);
+ break;
+
+ case simd_scalar_vexw:
+ s->op_bytes = 4 << s->vex.w;
+ break;
+
+ case simd_128:
+ /* The special cases here are MMX shift insns. */
+ s->op_bytes = s->vex.opcx || s->vex.pfx ? 16 : 8;
+ break;
+
+ case simd_256:
+ s->op_bytes = 32;
+ break;
+#endif /* !X86EMUL_NO_SIMD */
+
+ default:
+ s->op_bytes = 0;
+ break;
+ }
+
+ done:
+ return rc;
+}
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -37,9 +37,11 @@
#ifdef __i386__
# define mode_64bit() false
# define r(name) e ## name
+# define PTR_POISON NULL /* 32-bit builds are for user-space, so NULL is OK. */
#else
# define mode_64bit() (ctxt->addr_size == 64)
# define r(name) r ## name
+# define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */
#endif
/* Operand sizes: 8-bit operands or specified/overridden size. */
@@ -76,6 +78,23 @@
typedef uint8_t opcode_desc_t;
+enum disp8scale {
+ /* Values 0 ... 4 are explicit sizes. */
+ d8s_bw = 5,
+ d8s_dq,
+ /* EVEX.W ignored outside of 64-bit mode */
+ d8s_dq64,
+ /*
+ * All further values must strictly be last and in the order
+ * given so that arithmetic on the values works.
+ */
+ d8s_vl,
+ d8s_vl_by_2,
+ d8s_vl_by_4,
+ d8s_vl_by_8,
+};
+typedef uint8_t disp8scale_t;
+
/* Type, address-of, and value of an instruction's operand. */
struct operand {
enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
@@ -182,6 +201,9 @@ enum vex_pfx {
vex_f2
};
+#define VEX_PREFIX_DOUBLE_MASK 0x1
+#define VEX_PREFIX_SCALAR_MASK 0x2
+
union vex {
uint8_t raw[2];
struct { /* SDM names */
@@ -706,6 +728,10 @@ do {
if ( rc ) goto done; \
} while (0)
+int x86emul_decode(struct x86_emulate_state *s,
+ struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops);
+
int x86emul_fpu(struct x86_emulate_state *s,
struct cpu_user_regs *regs,
struct operand *dst,
@@ -735,6 +761,13 @@ int x86emul_0fc7(struct x86_emulate_stat
const struct x86_emulate_ops *ops,
mmval_t *mmvalp);
+/* Initialise output state in x86_emulate_ctxt */
+static inline void init_context(struct x86_emulate_ctxt *ctxt)
+{
+ ctxt->retire.raw = 0;
+ x86_emul_reset_event(ctxt);
+}
+
static inline bool is_aligned(enum x86_segment seg, unsigned long offs,
unsigned int size, struct x86_emulate_ctxt *ctxt,
const struct x86_emulate_ops *ops)
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -22,274 +22,6 @@
#include "private.h"
-static const opcode_desc_t opcode_table[256] = {
- /* 0x00 - 0x07 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
- /* 0x08 - 0x0F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, 0,
- /* 0x10 - 0x17 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
- /* 0x18 - 0x1F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, ImplicitOps|Mov, ImplicitOps|Mov,
- /* 0x20 - 0x27 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
- /* 0x28 - 0x2F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
- /* 0x30 - 0x37 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
- /* 0x38 - 0x3F */
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstEax|SrcImm, DstEax|SrcImm, 0, ImplicitOps,
- /* 0x40 - 0x4F */
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- /* 0x50 - 0x5F */
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
- /* 0x60 - 0x67 */
- ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcNone|ModRM|Mov,
- 0, 0, 0, 0,
- /* 0x68 - 0x6F */
- DstImplicit|SrcImm|Mov, DstReg|SrcImm|ModRM|Mov,
- DstImplicit|SrcImmByte|Mov, DstReg|SrcImmByte|ModRM|Mov,
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
- /* 0x70 - 0x77 */
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- /* 0x78 - 0x7F */
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- /* 0x80 - 0x87 */
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- /* 0x88 - 0x8F */
- ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
- ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM,
- DstReg|SrcMem16|ModRM|Mov, DstMem|SrcNone|ModRM|Mov,
- /* 0x90 - 0x97 */
- DstImplicit|SrcEax, DstImplicit|SrcEax,
- DstImplicit|SrcEax, DstImplicit|SrcEax,
- DstImplicit|SrcEax, DstImplicit|SrcEax,
- DstImplicit|SrcEax, DstImplicit|SrcEax,
- /* 0x98 - 0x9F */
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps, ImplicitOps,
- /* 0xA0 - 0xA7 */
- ByteOp|DstEax|SrcMem|Mov, DstEax|SrcMem|Mov,
- ByteOp|DstMem|SrcEax|Mov, DstMem|SrcEax|Mov,
- ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps, ImplicitOps,
- /* 0xA8 - 0xAF */
- ByteOp|DstEax|SrcImm, DstEax|SrcImm,
- ByteOp|DstImplicit|SrcEax|Mov, DstImplicit|SrcEax|Mov,
- ByteOp|DstEax|SrcImplicit|Mov, DstEax|SrcImplicit|Mov,
- ByteOp|DstImplicit|SrcEax, DstImplicit|SrcEax,
- /* 0xB0 - 0xB7 */
- ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
- ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
- ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
- ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
- /* 0xB8 - 0xBF */
- DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
- DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
- /* 0xC0 - 0xC7 */
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
- DstImplicit|SrcImm16, ImplicitOps,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
- /* 0xC8 - 0xCF */
- DstImplicit|SrcImm16, ImplicitOps, DstImplicit|SrcImm16, ImplicitOps,
- ImplicitOps, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps,
- /* 0xD0 - 0xD7 */
- ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
- ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte, ImplicitOps, ImplicitOps,
- /* 0xD8 - 0xDF */
- ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
- ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
- ImplicitOps|ModRM, ImplicitOps|ModRM|Mov,
- DstImplicit|SrcMem16|ModRM, ImplicitOps|ModRM|Mov,
- /* 0xE0 - 0xE7 */
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- DstEax|SrcImmByte, DstEax|SrcImmByte,
- DstImplicit|SrcImmByte, DstImplicit|SrcImmByte,
- /* 0xE8 - 0xEF */
- DstImplicit|SrcImm|Mov, DstImplicit|SrcImm,
- ImplicitOps, DstImplicit|SrcImmByte,
- DstEax|SrcImplicit, DstEax|SrcImplicit, ImplicitOps, ImplicitOps,
- /* 0xF0 - 0xF7 */
- 0, ImplicitOps, 0, 0,
- ImplicitOps, ImplicitOps, ByteOp|ModRM, ModRM,
- /* 0xF8 - 0xFF */
- ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
-};
-
-enum disp8scale {
- /* Values 0 ... 4 are explicit sizes. */
- d8s_bw = 5,
- d8s_dq,
- /* EVEX.W ignored outside of 64-bit mode */
- d8s_dq64,
- /*
- * All further values must strictly be last and in the order
- * given so that arithmetic on the values works.
- */
- d8s_vl,
- d8s_vl_by_2,
- d8s_vl_by_4,
- d8s_vl_by_8,
-};
-typedef uint8_t disp8scale_t;
-
-static const struct twobyte_table {
- opcode_desc_t desc;
- simd_opsize_t size:4;
- disp8scale_t d8s:4;
-} twobyte_table[256] = {
- [0x00] = { ModRM },
- [0x01] = { ImplicitOps|ModRM },
- [0x02] = { DstReg|SrcMem16|ModRM },
- [0x03] = { DstReg|SrcMem16|ModRM },
- [0x05] = { ImplicitOps },
- [0x06] = { ImplicitOps },
- [0x07] = { ImplicitOps },
- [0x08] = { ImplicitOps },
- [0x09] = { ImplicitOps },
- [0x0b] = { ImplicitOps },
- [0x0d] = { ImplicitOps|ModRM },
- [0x0e] = { ImplicitOps },
- [0x0f] = { ModRM|SrcImmByte },
- [0x10] = { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl },
- [0x11] = { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl },
- [0x12] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 },
- [0x13] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
- [0x14 ... 0x15] = { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl },
- [0x16] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, 3 },
- [0x17] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
- [0x18 ... 0x1f] = { ImplicitOps|ModRM },
- [0x20 ... 0x21] = { DstMem|SrcImplicit|ModRM },
- [0x22 ... 0x23] = { DstImplicit|SrcMem|ModRM },
- [0x28] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
- [0x29] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_fp, d8s_vl },
- [0x2a] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 },
- [0x2b] = { DstMem|SrcImplicit|ModRM|Mov, simd_any_fp, d8s_vl },
- [0x2c ... 0x2d] = { DstImplicit|SrcMem|ModRM|Mov, simd_other },
- [0x2e ... 0x2f] = { ImplicitOps|ModRM|TwoOp, simd_none, d8s_dq },
- [0x30 ... 0x35] = { ImplicitOps },
- [0x37] = { ImplicitOps },
- [0x38] = { DstReg|SrcMem|ModRM },
- [0x3a] = { DstReg|SrcImmByte|ModRM },
- [0x40 ... 0x4f] = { DstReg|SrcMem|ModRM|Mov },
- [0x50] = { DstReg|SrcImplicit|ModRM|Mov },
- [0x51] = { DstImplicit|SrcMem|ModRM|TwoOp, simd_any_fp, d8s_vl },
- [0x52 ... 0x53] = { DstImplicit|SrcMem|ModRM|TwoOp, simd_single_fp },
- [0x54 ... 0x57] = { DstImplicit|SrcMem|ModRM, simd_packed_fp, d8s_vl },
- [0x58 ... 0x59] = { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl },
- [0x5a] = { DstImplicit|SrcMem|ModRM|Mov, simd_any_fp, d8s_vl },
- [0x5b] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
- [0x5c ... 0x5f] = { DstImplicit|SrcMem|ModRM, simd_any_fp, d8s_vl },
- [0x60 ... 0x62] = { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl },
- [0x63 ... 0x67] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0x68 ... 0x6a] = { DstImplicit|SrcMem|ModRM, simd_other, d8s_vl },
- [0x6b ... 0x6d] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0x6e] = { DstImplicit|SrcMem|ModRM|Mov, simd_none, d8s_dq64 },
- [0x6f] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_int, d8s_vl },
- [0x70] = { SrcImmByte|ModRM|TwoOp, simd_other, d8s_vl },
- [0x71 ... 0x73] = { DstImplicit|SrcImmByte|ModRM, simd_none, d8s_vl },
- [0x74 ... 0x76] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0x77] = { DstImplicit|SrcNone },
- [0x78 ... 0x79] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_vl },
- [0x7a] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
- [0x7b] = { DstImplicit|SrcMem|ModRM|Mov, simd_other, d8s_dq64 },
- [0x7c ... 0x7d] = { DstImplicit|SrcMem|ModRM, simd_other },
- [0x7e] = { DstMem|SrcImplicit|ModRM|Mov, simd_none, d8s_dq64 },
- [0x7f] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl },
- [0x80 ... 0x8f] = { DstImplicit|SrcImm },
- [0x90 ... 0x9f] = { ByteOp|DstMem|SrcNone|ModRM|Mov },
- [0xa0 ... 0xa1] = { ImplicitOps|Mov },
- [0xa2] = { ImplicitOps },
- [0xa3] = { DstBitBase|SrcReg|ModRM },
- [0xa4] = { DstMem|SrcImmByte|ModRM },
- [0xa5] = { DstMem|SrcReg|ModRM },
- [0xa6 ... 0xa7] = { ModRM },
- [0xa8 ... 0xa9] = { ImplicitOps|Mov },
- [0xaa] = { ImplicitOps },
- [0xab] = { DstBitBase|SrcReg|ModRM },
- [0xac] = { DstMem|SrcImmByte|ModRM },
- [0xad] = { DstMem|SrcReg|ModRM },
- [0xae] = { ImplicitOps|ModRM },
- [0xaf] = { DstReg|SrcMem|ModRM },
- [0xb0] = { ByteOp|DstMem|SrcReg|ModRM },
- [0xb1] = { DstMem|SrcReg|ModRM },
- [0xb2] = { DstReg|SrcMem|ModRM|Mov },
- [0xb3] = { DstBitBase|SrcReg|ModRM },
- [0xb4 ... 0xb5] = { DstReg|SrcMem|ModRM|Mov },
- [0xb6] = { ByteOp|DstReg|SrcMem|ModRM|Mov },
- [0xb7] = { DstReg|SrcMem16|ModRM|Mov },
- [0xb8] = { DstReg|SrcMem|ModRM },
- [0xb9] = { ModRM },
- [0xba] = { DstBitBase|SrcImmByte|ModRM },
- [0xbb] = { DstBitBase|SrcReg|ModRM },
- [0xbc ... 0xbd] = { DstReg|SrcMem|ModRM },
- [0xbe] = { ByteOp|DstReg|SrcMem|ModRM|Mov },
- [0xbf] = { DstReg|SrcMem16|ModRM|Mov },
- [0xc0] = { ByteOp|DstMem|SrcReg|ModRM },
- [0xc1] = { DstMem|SrcReg|ModRM },
- [0xc2] = { DstImplicit|SrcImmByte|ModRM, simd_any_fp, d8s_vl },
- [0xc3] = { DstMem|SrcReg|ModRM|Mov },
- [0xc4] = { DstImplicit|SrcImmByte|ModRM, simd_none, 1 },
- [0xc5] = { DstReg|SrcImmByte|ModRM|Mov },
- [0xc6] = { DstImplicit|SrcImmByte|ModRM, simd_packed_fp, d8s_vl },
- [0xc7] = { ImplicitOps|ModRM },
- [0xc8 ... 0xcf] = { ImplicitOps },
- [0xd0] = { DstImplicit|SrcMem|ModRM, simd_other },
- [0xd1 ... 0xd3] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
- [0xd4 ... 0xd5] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xd6] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
- [0xd7] = { DstReg|SrcImplicit|ModRM|Mov },
- [0xd8 ... 0xdf] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xe0] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xe1 ... 0xe2] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
- [0xe3 ... 0xe5] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xe6] = { DstImplicit|SrcMem|ModRM|Mov, simd_packed_fp, d8s_vl },
- [0xe7] = { DstMem|SrcImplicit|ModRM|Mov, simd_packed_int, d8s_vl },
- [0xe8 ... 0xef] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xf0] = { DstImplicit|SrcMem|ModRM|Mov, simd_other },
- [0xf1 ... 0xf3] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
- [0xf4 ... 0xf6] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xf7] = { DstMem|SrcMem|ModRM|Mov, simd_packed_int },
- [0xf8 ... 0xfe] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xff] = { ModRM }
-};
-
/*
* The next two tables are indexed by high opcode extension byte (the one
* that's encoded like an immediate) nibble, with each table element then
@@ -325,257 +57,9 @@ static const uint16_t _3dnow_ext_table[1
[0xb] = (1 << 0xb) /* pswapd */,
};
-/*
- * "two_op" and "four_op" below refer to the number of register operands
- * (one of which possibly also allowing to be a memory one). The named
- * operand counts do not include any immediate operands.
- */
-static const struct ext0f38_table {
- uint8_t simd_size:5;
- uint8_t to_mem:1;
- uint8_t two_op:1;
- uint8_t vsib:1;
- disp8scale_t d8s:4;
-} ext0f38_table[256] = {
- [0x00] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x01 ... 0x03] = { .simd_size = simd_packed_int },
- [0x04] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x05 ... 0x0a] = { .simd_size = simd_packed_int },
- [0x0b] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x0c ... 0x0d] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x0e ... 0x0f] = { .simd_size = simd_packed_fp },
- [0x10 ... 0x12] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x13] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x14 ... 0x16] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x17] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0x18] = { .simd_size = simd_scalar_opc, .two_op = 1, .d8s = 2 },
- [0x19] = { .simd_size = simd_scalar_opc, .two_op = 1, .d8s = 3 },
- [0x1a] = { .simd_size = simd_128, .two_op = 1, .d8s = 4 },
- [0x1b] = { .simd_size = simd_256, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x1c ... 0x1f] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0x20] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x21] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
- [0x22] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_8 },
- [0x23] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x24] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
- [0x25] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x26 ... 0x29] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x2a] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0x2b] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x2c] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x2d] = { .simd_size = simd_packed_fp, .d8s = d8s_dq },
- [0x2e ... 0x2f] = { .simd_size = simd_packed_fp, .to_mem = 1 },
- [0x30] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x31] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
- [0x32] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_8 },
- [0x33] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x34] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_4 },
- [0x35] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x36 ... 0x3f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x40] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x41] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0x42] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x43] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x44] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0x45 ... 0x47] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x4c] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x4d] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x4e] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x4f] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x50 ... 0x53] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x54 ... 0x55] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0x58] = { .simd_size = simd_other, .two_op = 1, .d8s = 2 },
- [0x59] = { .simd_size = simd_other, .two_op = 1, .d8s = 3 },
- [0x5a] = { .simd_size = simd_128, .two_op = 1, .d8s = 4 },
- [0x5b] = { .simd_size = simd_256, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x62] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_bw },
- [0x63] = { .simd_size = simd_packed_int, .to_mem = 1, .two_op = 1, .d8s = d8s_bw },
- [0x64 ... 0x66] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x68] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x70 ... 0x73] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x75 ... 0x76] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x77] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x78] = { .simd_size = simd_other, .two_op = 1 },
- [0x79] = { .simd_size = simd_other, .two_op = 1, .d8s = 1 },
- [0x7a ... 0x7c] = { .simd_size = simd_none, .two_op = 1 },
- [0x7d ... 0x7e] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x7f] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x82] = { .simd_size = simd_other },
- [0x83] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x88] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_dq },
- [0x89] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_dq },
- [0x8a] = { .simd_size = simd_packed_fp, .to_mem = 1, .two_op = 1, .d8s = d8s_dq },
- [0x8b] = { .simd_size = simd_packed_int, .to_mem = 1, .two_op = 1, .d8s = d8s_dq },
- [0x8c] = { .simd_size = simd_packed_int },
- [0x8d] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x8e] = { .simd_size = simd_packed_int, .to_mem = 1 },
- [0x8f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x90 ... 0x93] = { .simd_size = simd_other, .vsib = 1, .d8s = d8s_dq },
- [0x96 ... 0x98] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x99] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x9a] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x9b] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x9c] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x9d] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x9e] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x9f] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xa0 ... 0xa3] = { .simd_size = simd_other, .to_mem = 1, .vsib = 1, .d8s = d8s_dq },
- [0xa6 ... 0xa8] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xa9] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xaa] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xab] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xac] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xad] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xae] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xaf] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xb4 ... 0xb5] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0xb6 ... 0xb8] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xb9] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xba] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xbb] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xbc] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xbd] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xbe] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0xbf] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xc4] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0xc6 ... 0xc7] = { .simd_size = simd_other, .vsib = 1, .d8s = d8s_dq },
- [0xc8] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0xc9] = { .simd_size = simd_other },
- [0xca] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0xcb] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xcc] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0xcd] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xcf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0xdb] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xdc ... 0xdf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0xf0] = { .two_op = 1 },
- [0xf1] = { .to_mem = 1, .two_op = 1 },
- [0xf2 ... 0xf3] = {},
- [0xf5 ... 0xf7] = {},
- [0xf8] = { .simd_size = simd_other },
- [0xf9] = { .to_mem = 1, .two_op = 1 /* Mov */ },
-};
-
/* Shift values between src and dst sizes of pmov{s,z}x{b,w,d}{w,d,q}. */
static const uint8_t pmov_convert_delta[] = { 1, 2, 3, 1, 2, 1 };
-static const struct ext0f3a_table {
- uint8_t simd_size:5;
- uint8_t to_mem:1;
- uint8_t two_op:1;
- uint8_t four_op:1;
- disp8scale_t d8s:4;
-} ext0f3a_table[256] = {
- [0x00] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
- [0x01] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x02] = { .simd_size = simd_packed_int },
- [0x03] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x04 ... 0x05] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x06] = { .simd_size = simd_packed_fp },
- [0x08 ... 0x09] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x0a ... 0x0b] = { .simd_size = simd_scalar_opc, .d8s = d8s_dq },
- [0x0c ... 0x0d] = { .simd_size = simd_packed_fp },
- [0x0e] = { .simd_size = simd_packed_int },
- [0x0f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x14] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 0 },
- [0x15] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 1 },
- [0x16] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = d8s_dq64 },
- [0x17] = { .simd_size = simd_none, .to_mem = 1, .two_op = 1, .d8s = 2 },
- [0x18] = { .simd_size = simd_128, .d8s = 4 },
- [0x19] = { .simd_size = simd_128, .to_mem = 1, .two_op = 1, .d8s = 4 },
- [0x1a] = { .simd_size = simd_256, .d8s = d8s_vl_by_2 },
- [0x1b] = { .simd_size = simd_256, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x1d] = { .simd_size = simd_other, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x1e ... 0x1f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x20] = { .simd_size = simd_none, .d8s = 0 },
- [0x21] = { .simd_size = simd_other, .d8s = 2 },
- [0x22] = { .simd_size = simd_none, .d8s = d8s_dq64 },
- [0x23] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x25] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x26] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x27] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x30 ... 0x33] = { .simd_size = simd_other, .two_op = 1 },
- [0x38] = { .simd_size = simd_128, .d8s = 4 },
- [0x3a] = { .simd_size = simd_256, .d8s = d8s_vl_by_2 },
- [0x39] = { .simd_size = simd_128, .to_mem = 1, .two_op = 1, .d8s = 4 },
- [0x3b] = { .simd_size = simd_256, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
- [0x3e ... 0x3f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x40 ... 0x41] = { .simd_size = simd_packed_fp },
- [0x42 ... 0x43] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x44] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x46] = { .simd_size = simd_packed_int },
- [0x48 ... 0x49] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x4a ... 0x4b] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x4c] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0x50] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x51] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x54] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
- [0x55] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x56] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x57] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0x5c ... 0x5f] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x60 ... 0x63] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0x66] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
- [0x67] = { .simd_size = simd_scalar_vexw, .two_op = 1, .d8s = d8s_dq },
- [0x68 ... 0x69] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x6a ... 0x6b] = { .simd_size = simd_scalar_opc, .four_op = 1 },
- [0x6c ... 0x6d] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x6e ... 0x6f] = { .simd_size = simd_scalar_opc, .four_op = 1 },
- [0x70 ... 0x73] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0x78 ... 0x79] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x7a ... 0x7b] = { .simd_size = simd_scalar_opc, .four_op = 1 },
- [0x7c ... 0x7d] = { .simd_size = simd_packed_fp, .four_op = 1 },
- [0x7e ... 0x7f] = { .simd_size = simd_scalar_opc, .four_op = 1 },
- [0xcc] = { .simd_size = simd_other },
- [0xce ... 0xcf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0xdf] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xf0] = {},
-};
-
-static const opcode_desc_t xop_table[] = {
- DstReg|SrcImmByte|ModRM,
- DstReg|SrcMem|ModRM,
- DstReg|SrcImm|ModRM,
-};
-
-static const struct ext8f08_table {
- uint8_t simd_size:5;
- uint8_t two_op:1;
- uint8_t four_op:1;
-} ext8f08_table[256] = {
- [0xa2] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0x85 ... 0x87] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0x8e ... 0x8f] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0x95 ... 0x97] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0x9e ... 0x9f] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0xa3] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0xa6] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0xb6] = { .simd_size = simd_packed_int, .four_op = 1 },
- [0xc0 ... 0xc3] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xcc ... 0xcf] = { .simd_size = simd_packed_int },
- [0xec ... 0xef] = { .simd_size = simd_packed_int },
-};
-
-static const struct ext8f09_table {
- uint8_t simd_size:5;
- uint8_t two_op:1;
-} ext8f09_table[256] = {
- [0x01 ... 0x02] = { .two_op = 1 },
- [0x80 ... 0x81] = { .simd_size = simd_packed_fp, .two_op = 1 },
- [0x82 ... 0x83] = { .simd_size = simd_scalar_opc, .two_op = 1 },
- [0x90 ... 0x9b] = { .simd_size = simd_packed_int },
- [0xc1 ... 0xc3] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xc6 ... 0xc7] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xcb] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xd1 ... 0xd3] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xd6 ... 0xd7] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xdb] = { .simd_size = simd_packed_int, .two_op = 1 },
- [0xe1 ... 0xe3] = { .simd_size = simd_packed_int, .two_op = 1 },
-};
-
-#define VEX_PREFIX_DOUBLE_MASK 0x1
-#define VEX_PREFIX_SCALAR_MASK 0x2
-
static const uint8_t sse_prefix[] = { 0x66, 0xf3, 0xf2 };
#ifdef __x86_64__
@@ -637,12 +121,6 @@ static const uint8_t sse_prefix[] = { 0x
#define repe_prefix() (vex.pfx == vex_f3)
#define repne_prefix() (vex.pfx == vex_f2)
-#ifdef __x86_64__
-#define PTR_POISON ((void *)0x8086000000008086UL) /* non-canonical */
-#else
-#define PTR_POISON NULL /* 32-bit builds are for user-space, so NULL is OK. */
-#endif
-
/*
* 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
@@ -831,19 +309,6 @@ do{ asm volatile (
: [msk] "i" (EFLAGS_MASK), ## src); \
} while (0)
-/* Fetch next part of the instruction being emulated. */
-#define insn_fetch_bytes(_size) \
-({ unsigned long _x = 0, _ip = state->ip; \
- state->ip += (_size); /* real hardware doesn't truncate */ \
- generate_exception_if((uint8_t)(state->ip - \
- ctxt->regs->r(ip)) > MAX_INST_LEN, \
- EXC_GP, 0); \
- rc = ops->insn_fetch(x86_seg_cs, _ip, &_x, (_size), ctxt); \
- if ( rc ) goto done; \
- _x; \
-})
-#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
-
/*
* Given byte has even parity (even number of 1s)? SDM Vol. 1 Sec. 3.4.3.1,
* "Status Flags": EFLAGS.PF reflects parity of least-sig. byte of result only.
@@ -1354,13 +819,6 @@ static int ioport_access_check(
return rc;
}
-/* Initialise output state in x86_emulate_ctxt */
-static void init_context(struct x86_emulate_ctxt *ctxt)
-{
- ctxt->retire.raw = 0;
- x86_emul_reset_event(ctxt);
-}
-
static int
realmode_load_seg(
enum x86_segment seg,
@@ -1707,51 +1165,6 @@ static unsigned long *decode_vex_gpr(
return decode_gpr(regs, ~vex_reg & (mode_64bit() ? 0xf : 7));
}
-static unsigned int decode_disp8scale(enum disp8scale scale,
- const struct x86_emulate_state *state)
-{
- switch ( scale )
- {
- case d8s_bw:
- return state->evex.w;
-
- default:
- if ( scale < d8s_vl )
- return scale;
- if ( state->evex.brs )
- {
- case d8s_dq:
- return 2 + state->evex.w;
- }
- break;
-
- case d8s_dq64:
- return 2 + (state->op_bytes == 8);
- }
-
- switch ( state->simd_size )
- {
- case simd_any_fp:
- case simd_single_fp:
- if ( !(state->evex.pfx & VEX_PREFIX_SCALAR_MASK) )
- break;
- /* fall through */
- case simd_scalar_opc:
- case simd_scalar_vexw:
- return 2 + state->evex.w;
-
- case simd_128:
- /* These should have an explicit size specified. */
- ASSERT_UNREACHABLE();
- return 4;
-
- default:
- break;
- }
-
- return 4 + state->evex.lr - (scale - d8s_vl);
-}
-
#define avx512_vlen_check(lig) do { \
switch ( evex.lr ) \
{ \
@@ -1833,1138 +1246,6 @@ int x86emul_unhandleable_rw(
#define evex_encoded() (evex.mbs)
#define ea (state->ea)
-static int
-x86_decode_onebyte(
- struct x86_emulate_state *state,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- int rc = X86EMUL_OKAY;
-
- switch ( ctxt->opcode )
- {
- case 0x06: /* push %%es */
- case 0x07: /* pop %%es */
- case 0x0e: /* push %%cs */
- case 0x16: /* push %%ss */
- case 0x17: /* pop %%ss */
- case 0x1e: /* push %%ds */
- case 0x1f: /* pop %%ds */
- case 0x27: /* daa */
- case 0x2f: /* das */
- case 0x37: /* aaa */
- case 0x3f: /* aas */
- case 0x60: /* pusha */
- case 0x61: /* popa */
- case 0x62: /* bound */
- case 0xc4: /* les */
- case 0xc5: /* lds */
- case 0xce: /* into */
- case 0xd4: /* aam */
- case 0xd5: /* aad */
- case 0xd6: /* salc */
- state->not_64bit = true;
- break;
-
- case 0x82: /* Grp1 (x86/32 only) */
- state->not_64bit = true;
- /* fall through */
- case 0x80: case 0x81: case 0x83: /* Grp1 */
- if ( (modrm_reg & 7) == 7 ) /* cmp */
- state->desc = (state->desc & ByteOp) | DstNone | SrcMem;
- break;
-
- case 0x90: /* nop / pause */
- if ( repe_prefix() )
- ctxt->opcode |= X86EMUL_OPC_F3(0, 0);
- break;
-
- case 0x9a: /* call (far, absolute) */
- case 0xea: /* jmp (far, absolute) */
- generate_exception_if(mode_64bit(), EXC_UD);
-
- imm1 = insn_fetch_bytes(op_bytes);
- imm2 = insn_fetch_type(uint16_t);
- break;
-
- case 0xa0: case 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
- case 0xa2: case 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
- /* Source EA is not encoded via ModRM. */
- ea.type = OP_MEM;
- ea.mem.off = insn_fetch_bytes(ad_bytes);
- break;
-
- case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */
- if ( op_bytes == 8 ) /* Fetch more bytes to obtain imm64. */
- imm1 = ((uint32_t)imm1 |
- ((uint64_t)insn_fetch_type(uint32_t) << 32));
- break;
-
- case 0xc8: /* enter imm16,imm8 */
- imm2 = insn_fetch_type(uint8_t);
- break;
-
- case 0xf6: case 0xf7: /* Grp3 */
- if ( !(modrm_reg & 6) ) /* test */
- state->desc = (state->desc & ByteOp) | DstNone | SrcMem;
- break;
-
- case 0xff: /* Grp5 */
- switch ( modrm_reg & 7 )
- {
- case 2: /* call (near) */
- case 4: /* jmp (near) */
- if ( mode_64bit() && (op_bytes == 4 || !amd_like(ctxt)) )
- op_bytes = 8;
- state->desc = DstNone | SrcMem | Mov;
- break;
-
- case 3: /* call (far, absolute indirect) */
- case 5: /* jmp (far, absolute indirect) */
- /* REX.W ignored on a vendor-dependent basis. */
- if ( op_bytes == 8 && amd_like(ctxt) )
- op_bytes = 4;
- state->desc = DstNone | SrcMem | Mov;
- break;
-
- case 6: /* push */
- if ( mode_64bit() && op_bytes == 4 )
- op_bytes = 8;
- state->desc = DstNone | SrcMem | Mov;
- break;
- }
- break;
- }
-
- done:
- return rc;
-}
-
-static int
-x86_decode_twobyte(
- struct x86_emulate_state *state,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- int rc = X86EMUL_OKAY;
-
- switch ( ctxt->opcode & X86EMUL_OPC_MASK )
- {
- case 0x00: /* Grp6 */
- switch ( modrm_reg & 6 )
- {
- case 0:
- state->desc |= DstMem | SrcImplicit | Mov;
- break;
- case 2: case 4:
- state->desc |= SrcMem16;
- break;
- }
- break;
-
- case 0x78:
- state->desc = ImplicitOps;
- state->simd_size = simd_none;
- switch ( vex.pfx )
- {
- case vex_66: /* extrq $imm8, $imm8, xmm */
- case vex_f2: /* insertq $imm8, $imm8, xmm, xmm */
- imm1 = insn_fetch_type(uint8_t);
- imm2 = insn_fetch_type(uint8_t);
- break;
- }
- /* fall through */
- case 0x10 ... 0x18:
- case 0x28 ... 0x2f:
- case 0x50 ... 0x77:
- case 0x7a ... 0x7d:
- case 0x7f:
- case 0xc2 ... 0xc3:
- case 0xc5 ... 0xc6:
- case 0xd0 ... 0xef:
- case 0xf1 ... 0xfe:
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- case 0x20: case 0x22: /* mov to/from cr */
- if ( lock_prefix && vcpu_has_cr8_legacy() )
- {
- modrm_reg += 8;
- lock_prefix = false;
- }
- /* fall through */
- case 0x21: case 0x23: /* mov to/from dr */
- ASSERT(ea.type == OP_REG); /* Early operand adjustment ensures this. */
- generate_exception_if(lock_prefix, EXC_UD);
- op_bytes = mode_64bit() ? 8 : 4;
- break;
-
- case 0x79:
- state->desc = DstReg | SrcMem;
- state->simd_size = simd_packed_int;
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- case 0x7e:
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- if ( vex.pfx == vex_f3 ) /* movq xmm/m64,xmm */
- {
- case X86EMUL_OPC_VEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
- case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
- state->desc = DstImplicit | SrcMem | TwoOp;
- state->simd_size = simd_other;
- /* Avoid the state->desc clobbering of TwoOp below. */
- return X86EMUL_OKAY;
- }
- break;
-
- case X86EMUL_OPC_VEX(0, 0x90): /* kmov{w,q} */
- case X86EMUL_OPC_VEX_66(0, 0x90): /* kmov{b,d} */
- state->desc = DstReg | SrcMem | Mov;
- state->simd_size = simd_other;
- break;
-
- case X86EMUL_OPC_VEX(0, 0x91): /* kmov{w,q} */
- case X86EMUL_OPC_VEX_66(0, 0x91): /* kmov{b,d} */
- state->desc = DstMem | SrcReg | Mov;
- state->simd_size = simd_other;
- break;
-
- case 0xae:
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- /* fall through */
- case X86EMUL_OPC_VEX(0, 0xae):
- switch ( modrm_reg & 7 )
- {
- case 2: /* {,v}ldmxcsr */
- state->desc = DstImplicit | SrcMem | Mov;
- op_bytes = 4;
- break;
-
- case 3: /* {,v}stmxcsr */
- state->desc = DstMem | SrcImplicit | Mov;
- op_bytes = 4;
- break;
- }
- break;
-
- case 0xb2: /* lss */
- case 0xb4: /* lfs */
- case 0xb5: /* lgs */
- /* REX.W ignored on a vendor-dependent basis. */
- if ( op_bytes == 8 && amd_like(ctxt) )
- op_bytes = 4;
- break;
-
- case 0xb8: /* jmpe / popcnt */
- if ( rep_prefix() )
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- /* Intentionally not handling here despite being modified by F3:
- case 0xbc: bsf / tzcnt
- case 0xbd: bsr / lzcnt
- * They're being dealt with in the execution phase (if at all).
- */
-
- case 0xc4: /* pinsrw */
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- /* fall through */
- case X86EMUL_OPC_VEX_66(0, 0xc4): /* vpinsrw */
- case X86EMUL_OPC_EVEX_66(0, 0xc4): /* vpinsrw */
- state->desc = DstImplicit | SrcMem16;
- break;
-
- case 0xf0:
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- if ( vex.pfx == vex_f2 ) /* lddqu mem,xmm */
- {
- /* fall through */
- case X86EMUL_OPC_VEX_F2(0, 0xf0): /* vlddqu mem,{x,y}mm */
- state->desc = DstImplicit | SrcMem | TwoOp;
- state->simd_size = simd_other;
- /* Avoid the state->desc clobbering of TwoOp below. */
- return X86EMUL_OKAY;
- }
- break;
- }
-
- /*
- * Scalar forms of most VEX-/EVEX-encoded TwoOp instructions have
- * three operands. Those which do really have two operands
- * should have exited earlier.
- */
- if ( state->simd_size && vex.opcx &&
- (vex.pfx & VEX_PREFIX_SCALAR_MASK) )
- state->desc &= ~TwoOp;
-
- done:
- return rc;
-}
-
-static int
-x86_decode_0f38(
- struct x86_emulate_state *state,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- switch ( ctxt->opcode & X86EMUL_OPC_MASK )
- {
- case 0x00 ... 0xef:
- case 0xf2 ... 0xf5:
- case 0xf7 ... 0xf8:
- case 0xfa ... 0xff:
- op_bytes = 0;
- /* fall through */
- case 0xf6: /* adcx / adox */
- case 0xf9: /* movdiri */
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- case X86EMUL_OPC_EVEX_66(0, 0x2d): /* vscalefs{s,d} */
- state->simd_size = simd_scalar_vexw;
- break;
-
- case X86EMUL_OPC_EVEX_66(0, 0x7a): /* vpbroadcastb */
- case X86EMUL_OPC_EVEX_66(0, 0x7b): /* vpbroadcastw */
- case X86EMUL_OPC_EVEX_66(0, 0x7c): /* vpbroadcast{d,q} */
- break;
-
- case 0xf0: /* movbe / crc32 */
- state->desc |= repne_prefix() ? ByteOp : Mov;
- if ( rep_prefix() )
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- case 0xf1: /* movbe / crc32 */
- if ( repne_prefix() )
- state->desc = DstReg | SrcMem;
- if ( rep_prefix() )
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
- break;
-
- case X86EMUL_OPC_VEX(0, 0xf2): /* andn */
- case X86EMUL_OPC_VEX(0, 0xf3): /* Grp 17 */
- case X86EMUL_OPC_VEX(0, 0xf5): /* bzhi */
- case X86EMUL_OPC_VEX_F3(0, 0xf5): /* pext */
- case X86EMUL_OPC_VEX_F2(0, 0xf5): /* pdep */
- case X86EMUL_OPC_VEX_F2(0, 0xf6): /* mulx */
- case X86EMUL_OPC_VEX(0, 0xf7): /* bextr */
- case X86EMUL_OPC_VEX_66(0, 0xf7): /* shlx */
- case X86EMUL_OPC_VEX_F3(0, 0xf7): /* sarx */
- case X86EMUL_OPC_VEX_F2(0, 0xf7): /* shrx */
- break;
-
- default:
- op_bytes = 0;
- break;
- }
-
- return X86EMUL_OKAY;
-}
-
-static int
-x86_decode_0f3a(
- struct x86_emulate_state *state,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- if ( !vex.opcx )
- ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
-
- switch ( ctxt->opcode & X86EMUL_OPC_MASK )
- {
- case X86EMUL_OPC_66(0, 0x14)
- ... X86EMUL_OPC_66(0, 0x17): /* pextr*, extractps */
- case X86EMUL_OPC_VEX_66(0, 0x14)
- ... X86EMUL_OPC_VEX_66(0, 0x17): /* vpextr*, vextractps */
- case X86EMUL_OPC_EVEX_66(0, 0x14)
- ... X86EMUL_OPC_EVEX_66(0, 0x17): /* vpextr*, vextractps */
- case X86EMUL_OPC_VEX_F2(0, 0xf0): /* rorx */
- break;
-
- case X86EMUL_OPC_66(0, 0x20): /* pinsrb */
- case X86EMUL_OPC_VEX_66(0, 0x20): /* vpinsrb */
- case X86EMUL_OPC_EVEX_66(0, 0x20): /* vpinsrb */
- state->desc = DstImplicit | SrcMem;
- if ( modrm_mod != 3 )
- state->desc |= ByteOp;
- break;
-
- case X86EMUL_OPC_66(0, 0x22): /* pinsr{d,q} */
- case X86EMUL_OPC_VEX_66(0, 0x22): /* vpinsr{d,q} */
- case X86EMUL_OPC_EVEX_66(0, 0x22): /* vpinsr{d,q} */
- state->desc = DstImplicit | SrcMem;
- break;
-
- default:
- op_bytes = 0;
- break;
- }
-
- return X86EMUL_OKAY;
-}
-
-static int
-x86_decode(
- struct x86_emulate_state *state,
- struct x86_emulate_ctxt *ctxt,
- const struct x86_emulate_ops *ops)
-{
- uint8_t b, d;
- unsigned int def_op_bytes, def_ad_bytes, opcode;
- enum x86_segment override_seg = x86_seg_none;
- bool pc_rel = false;
- int rc = X86EMUL_OKAY;
-
- ASSERT(ops->insn_fetch);
-
- memset(state, 0, sizeof(*state));
- ea.type = OP_NONE;
- ea.mem.seg = x86_seg_ds;
- ea.reg = PTR_POISON;
- state->regs = ctxt->regs;
- state->ip = ctxt->regs->r(ip);
-
- op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8;
- if ( op_bytes == 8 )
- {
- op_bytes = def_op_bytes = 4;
-#ifndef __x86_64__
- return X86EMUL_UNHANDLEABLE;
-#endif
- }
-
- /* Prefix bytes. */
- for ( ; ; )
- {
- switch ( b = insn_fetch_type(uint8_t) )
- {
- case 0x66: /* operand-size override */
- op_bytes = def_op_bytes ^ 6;
- if ( !vex.pfx )
- vex.pfx = vex_66;
- break;
- case 0x67: /* address-size override */
- ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6);
- break;
- case 0x2e: /* CS override / ignored in 64-bit mode */
- if ( !mode_64bit() )
- override_seg = x86_seg_cs;
- break;
- case 0x3e: /* DS override / ignored in 64-bit mode */
- if ( !mode_64bit() )
- override_seg = x86_seg_ds;
- break;
- case 0x26: /* ES override / ignored in 64-bit mode */
- if ( !mode_64bit() )
- override_seg = x86_seg_es;
- break;
- case 0x64: /* FS override */
- override_seg = x86_seg_fs;
- break;
- case 0x65: /* GS override */
- override_seg = x86_seg_gs;
- break;
- case 0x36: /* SS override / ignored in 64-bit mode */
- if ( !mode_64bit() )
- override_seg = x86_seg_ss;
- break;
- case 0xf0: /* LOCK */
- lock_prefix = 1;
- break;
- case 0xf2: /* REPNE/REPNZ */
- vex.pfx = vex_f2;
- break;
- case 0xf3: /* REP/REPE/REPZ */
- vex.pfx = vex_f3;
- break;
- case 0x40 ... 0x4f: /* REX */
- if ( !mode_64bit() )
- goto done_prefixes;
- rex_prefix = b;
- continue;
- default:
- goto done_prefixes;
- }
-
- /* Any legacy prefix after a REX prefix nullifies its effect. */
- rex_prefix = 0;
- }
- done_prefixes:
-
- if ( rex_prefix & REX_W )
- op_bytes = 8;
-
- /* Opcode byte(s). */
- d = opcode_table[b];
- if ( d == 0 && b == 0x0f )
- {
- /* Two-byte opcode. */
- b = insn_fetch_type(uint8_t);
- d = twobyte_table[b].desc;
- switch ( b )
- {
- default:
- opcode = b | MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK);
- ext = ext_0f;
- state->simd_size = twobyte_table[b].size;
- break;
- case 0x38:
- b = insn_fetch_type(uint8_t);
- opcode = b | MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK);
- ext = ext_0f38;
- break;
- case 0x3a:
- b = insn_fetch_type(uint8_t);
- opcode = b | MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK);
- ext = ext_0f3a;
- break;
- }
- }
- else
- opcode = b;
-
- /* ModRM and SIB bytes. */
- if ( d & ModRM )
- {
- modrm = insn_fetch_type(uint8_t);
- modrm_mod = (modrm & 0xc0) >> 6;
-
- if ( !ext && ((b & ~1) == 0xc4 || (b == 0x8f && (modrm & 0x18)) ||
- b == 0x62) )
- switch ( def_ad_bytes )
- {
- default:
- BUG(); /* Shouldn't be possible. */
- case 2:
- if ( state->regs->eflags & X86_EFLAGS_VM )
- break;
- /* fall through */
- case 4:
- if ( modrm_mod != 3 || in_realmode(ctxt, ops) )
- break;
- /* fall through */
- case 8:
- /* VEX / XOP / EVEX */
- generate_exception_if(rex_prefix || vex.pfx, EXC_UD);
- /*
- * With operand size override disallowed (see above), op_bytes
- * should not have changed from its default.
- */
- ASSERT(op_bytes == def_op_bytes);
-
- vex.raw[0] = modrm;
- if ( b == 0xc5 )
- {
- opcode = X86EMUL_OPC_VEX_;
- vex.raw[1] = modrm;
- vex.opcx = vex_0f;
- vex.x = 1;
- vex.b = 1;
- vex.w = 0;
- }
- else
- {
- vex.raw[1] = insn_fetch_type(uint8_t);
- if ( mode_64bit() )
- {
- if ( !vex.b )
- rex_prefix |= REX_B;
- if ( !vex.x )
- rex_prefix |= REX_X;
- if ( vex.w )
- {
- rex_prefix |= REX_W;
- op_bytes = 8;
- }
- }
- else
- {
- /* Operand size fixed at 4 (no override via W bit). */
- op_bytes = 4;
- vex.b = 1;
- }
- switch ( b )
- {
- case 0x62:
- opcode = X86EMUL_OPC_EVEX_;
- evex.raw[0] = vex.raw[0];
- evex.raw[1] = vex.raw[1];
- evex.raw[2] = insn_fetch_type(uint8_t);
-
- generate_exception_if(!evex.mbs || evex.mbz, EXC_UD);
- generate_exception_if(!evex.opmsk && evex.z, EXC_UD);
-
- if ( !mode_64bit() )
- evex.R = 1;
-
- vex.opcx = evex.opcx;
- break;
- case 0xc4:
- opcode = X86EMUL_OPC_VEX_;
- break;
- default:
- opcode = 0;
- break;
- }
- }
- if ( !vex.r )
- rex_prefix |= REX_R;
-
- ext = vex.opcx;
- if ( b != 0x8f )
- {
- b = insn_fetch_type(uint8_t);
- switch ( ext )
- {
- case vex_0f:
- opcode |= MASK_INSR(0x0f, X86EMUL_OPC_EXT_MASK);
- d = twobyte_table[b].desc;
- state->simd_size = twobyte_table[b].size;
- break;
- case vex_0f38:
- opcode |= MASK_INSR(0x0f38, X86EMUL_OPC_EXT_MASK);
- d = twobyte_table[0x38].desc;
- break;
- case vex_0f3a:
- opcode |= MASK_INSR(0x0f3a, X86EMUL_OPC_EXT_MASK);
- d = twobyte_table[0x3a].desc;
- break;
- default:
- rc = X86EMUL_UNRECOGNIZED;
- goto done;
- }
- }
- else if ( ext < ext_8f08 + ARRAY_SIZE(xop_table) )
- {
- b = insn_fetch_type(uint8_t);
- opcode |= MASK_INSR(0x8f08 + ext - ext_8f08,
- X86EMUL_OPC_EXT_MASK);
- d = array_access_nospec(xop_table, ext - ext_8f08);
- }
- else
- {
- rc = X86EMUL_UNRECOGNIZED;
- goto done;
- }
-
- opcode |= b | MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
-
- if ( !evex_encoded() )
- evex.lr = vex.l;
-
- if ( !(d & ModRM) )
- break;
-
- modrm = insn_fetch_type(uint8_t);
- modrm_mod = (modrm & 0xc0) >> 6;
-
- break;
- }
- }
-
- if ( d & ModRM )
- {
- unsigned int disp8scale = 0;
-
- d &= ~ModRM;
-#undef ModRM /* Only its aliases are valid to use from here on. */
- modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3) |
- ((evex_encoded() && !evex.R) << 4);
- modrm_rm = modrm & 0x07;
-
- /*
- * Early operand adjustments. Only ones affecting further processing
- * prior to the x86_decode_*() calls really belong here. That would
- * normally be only addition/removal of SrcImm/SrcImm16, so their
- * fetching can be taken care of by the common code below.
- */
- switch ( ext )
- {
- case ext_none:
- switch ( b )
- {
- case 0xf6 ... 0xf7: /* Grp3 */
- switch ( modrm_reg & 7 )
- {
- case 0 ... 1: /* test */
- d |= DstMem | SrcImm;
- break;
- case 2: /* not */
- case 3: /* neg */
- d |= DstMem;
- break;
- case 4: /* mul */
- case 5: /* imul */
- case 6: /* div */
- case 7: /* idiv */
- /*
- * DstEax isn't really precise for all cases; updates to
- * rDX get handled in an open coded manner.
- */
- d |= DstEax | SrcMem;
- break;
- }
- break;
- }
- break;
-
- case ext_0f:
- if ( evex_encoded() )
- disp8scale = decode_disp8scale(twobyte_table[b].d8s, state);
-
- switch ( b )
- {
- case 0x12: /* vmovsldup / vmovddup */
- if ( evex.pfx == vex_f2 )
- disp8scale = evex.lr ? 4 + evex.lr : 3;
- /* fall through */
- case 0x16: /* vmovshdup */
- if ( evex.pfx == vex_f3 )
- disp8scale = 4 + evex.lr;
- break;
-
- case 0x20: /* mov cr,reg */
- case 0x21: /* mov dr,reg */
- case 0x22: /* mov reg,cr */
- case 0x23: /* mov reg,dr */
- /*
- * Mov to/from cr/dr ignore the encoding of Mod, and behave as
- * if they were encoded as reg/reg instructions. No further
- * disp/SIB bytes are fetched.
- */
- modrm_mod = 3;
- break;
-
- case 0x78:
- case 0x79:
- if ( !evex.pfx )
- break;
- /* vcvt{,t}ps2uqq need special casing */
- if ( evex.pfx == vex_66 )
- {
- if ( !evex.w && !evex.brs )
- --disp8scale;
- break;
- }
- /* vcvt{,t}s{s,d}2usi need special casing: fall through */
- case 0x2c: /* vcvtts{s,d}2si need special casing */
- case 0x2d: /* vcvts{s,d}2si need special casing */
- if ( evex_encoded() )
- disp8scale = 2 + (evex.pfx & VEX_PREFIX_DOUBLE_MASK);
- break;
-
- case 0x5a: /* vcvtps2pd needs special casing */
- if ( disp8scale && !evex.pfx && !evex.brs )
- --disp8scale;
- break;
-
- case 0x7a: /* vcvttps2qq and vcvtudq2pd need special casing */
- if ( disp8scale && evex.pfx != vex_f2 && !evex.w && !evex.brs )
- --disp8scale;
- break;
-
- case 0x7b: /* vcvtp{s,d}2qq need special casing */
- if ( disp8scale && evex.pfx == vex_66 )
- disp8scale = (evex.brs ? 2 : 3 + evex.lr) + evex.w;
- break;
-
- case 0x7e: /* vmovq xmm/m64,xmm needs special casing */
- if ( disp8scale == 2 && evex.pfx == vex_f3 )
- disp8scale = 3;
- break;
-
- case 0xe6: /* vcvtdq2pd needs special casing */
- if ( disp8scale && evex.pfx == vex_f3 && !evex.w && !evex.brs )
- --disp8scale;
- break;
- }
- break;
-
- case ext_0f38:
- d = ext0f38_table[b].to_mem ? DstMem | SrcReg
- : DstReg | SrcMem;
- if ( ext0f38_table[b].two_op )
- d |= TwoOp;
- if ( ext0f38_table[b].vsib )
- d |= vSIB;
- state->simd_size = ext0f38_table[b].simd_size;
- if ( evex_encoded() )
- {
- /*
- * VPMOVUS* are identical to VPMOVS* Disp8-scaling-wise, but
- * their attributes don't match those of the vex_66 encoded
- * insns with the same base opcodes. Rather than adding new
- * columns to the table, handle this here for now.
- */
- if ( evex.pfx != vex_f3 || (b & 0xf8) != 0x10 )
- disp8scale = decode_disp8scale(ext0f38_table[b].d8s, state);
- else
- {
- disp8scale = decode_disp8scale(ext0f38_table[b ^ 0x30].d8s,
- state);
- state->simd_size = simd_other;
- }
-
- switch ( b )
- {
- /* vp4dpwssd{,s} need special casing */
- case 0x52: case 0x53:
- /* v4f{,n}madd{p,s}s need special casing */
- case 0x9a: case 0x9b: case 0xaa: case 0xab:
- if ( evex.pfx == vex_f2 )
- {
- disp8scale = 4;
- state->simd_size = simd_128;
- }
- break;
- }
- }
- break;
-
- case ext_0f3a:
- /*
- * Cannot update d here yet, as the immediate operand still
- * needs fetching.
- */
- state->simd_size = ext0f3a_table[b].simd_size;
- if ( evex_encoded() )
- disp8scale = decode_disp8scale(ext0f3a_table[b].d8s, state);
- break;
-
- case ext_8f09:
- if ( ext8f09_table[b].two_op )
- d |= TwoOp;
- state->simd_size = ext8f09_table[b].simd_size;
- break;
-
- case ext_8f08:
- case ext_8f0a:
- /*
- * Cannot update d here yet, as the immediate operand still
- * needs fetching.
- */
- break;
-
- default:
- ASSERT_UNREACHABLE();
- return X86EMUL_UNIMPLEMENTED;
- }
-
- if ( modrm_mod == 3 )
- {
- generate_exception_if(d & vSIB, EXC_UD);
- modrm_rm |= ((rex_prefix & 1) << 3) |
- ((evex_encoded() && !evex.x) << 4);
- ea.type = OP_REG;
- }
- else if ( ad_bytes == 2 )
- {
- /* 16-bit ModR/M decode. */
- generate_exception_if(d & vSIB, EXC_UD);
- ea.type = OP_MEM;
- switch ( modrm_rm )
- {
- case 0:
- ea.mem.off = state->regs->bx + state->regs->si;
- break;
- case 1:
- ea.mem.off = state->regs->bx + state->regs->di;
- break;
- case 2:
- ea.mem.seg = x86_seg_ss;
- ea.mem.off = state->regs->bp + state->regs->si;
- break;
- case 3:
- ea.mem.seg = x86_seg_ss;
- ea.mem.off = state->regs->bp + state->regs->di;
- break;
- case 4:
- ea.mem.off = state->regs->si;
- break;
- case 5:
- ea.mem.off = state->regs->di;
- break;
- case 6:
- if ( modrm_mod == 0 )
- break;
- ea.mem.seg = x86_seg_ss;
- ea.mem.off = state->regs->bp;
- break;
- case 7:
- ea.mem.off = state->regs->bx;
- break;
- }
- switch ( modrm_mod )
- {
- case 0:
- if ( modrm_rm == 6 )
- ea.mem.off = insn_fetch_type(int16_t);
- break;
- case 1:
- ea.mem.off += insn_fetch_type(int8_t) * (1 << disp8scale);
- break;
- case 2:
- ea.mem.off += insn_fetch_type(int16_t);
- break;
- }
- }
- else
- {
- /* 32/64-bit ModR/M decode. */
- ea.type = OP_MEM;
- if ( modrm_rm == 4 )
- {
- uint8_t sib = insn_fetch_type(uint8_t);
- uint8_t sib_base = (sib & 7) | ((rex_prefix << 3) & 8);
-
- state->sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
- state->sib_scale = (sib >> 6) & 3;
- if ( unlikely(d & vSIB) )
- state->sib_index |= (mode_64bit() && evex_encoded() &&
- !evex.RX) << 4;
- else if ( state->sib_index != 4 )
- {
- ea.mem.off = *decode_gpr(state->regs, state->sib_index);
- ea.mem.off <<= state->sib_scale;
- }
- if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
- ea.mem.off += insn_fetch_type(int32_t);
- else if ( sib_base == 4 )
- {
- ea.mem.seg = x86_seg_ss;
- ea.mem.off += state->regs->r(sp);
- if ( !ext && (b == 0x8f) )
- /* POP <rm> computes its EA post increment. */
- ea.mem.off += ((mode_64bit() && (op_bytes == 4))
- ? 8 : op_bytes);
- }
- else if ( sib_base == 5 )
- {
- ea.mem.seg = x86_seg_ss;
- ea.mem.off += state->regs->r(bp);
- }
- else
- ea.mem.off += *decode_gpr(state->regs, sib_base);
- }
- else
- {
- generate_exception_if(d & vSIB, EXC_UD);
- modrm_rm |= (rex_prefix & 1) << 3;
- ea.mem.off = *decode_gpr(state->regs, modrm_rm);
- if ( (modrm_rm == 5) && (modrm_mod != 0) )
- ea.mem.seg = x86_seg_ss;
- }
- switch ( modrm_mod )
- {
- case 0:
- if ( (modrm_rm & 7) != 5 )
- break;
- ea.mem.off = insn_fetch_type(int32_t);
- pc_rel = mode_64bit();
- break;
- case 1:
- ea.mem.off += insn_fetch_type(int8_t) * (1 << disp8scale);
- break;
- case 2:
- ea.mem.off += insn_fetch_type(int32_t);
- break;
- }
- }
- }
- else
- {
- modrm_mod = 0xff;
- modrm_reg = modrm_rm = modrm = 0;
- }
-
- if ( override_seg != x86_seg_none )
- ea.mem.seg = override_seg;
-
- /* Fetch the immediate operand, if present. */
- switch ( d & SrcMask )
- {
- unsigned int bytes;
-
- case SrcImm:
- if ( !(d & ByteOp) )
- {
- if ( mode_64bit() && !amd_like(ctxt) &&
- ((ext == ext_none && (b | 1) == 0xe9) /* call / jmp */ ||
- (ext == ext_0f && (b | 0xf) == 0x8f) /* jcc */ ) )
- op_bytes = 4;
- bytes = op_bytes != 8 ? op_bytes : 4;
- }
- else
- {
- case SrcImmByte:
- bytes = 1;
- }
- /* NB. Immediates are sign-extended as necessary. */
- switch ( bytes )
- {
- case 1: imm1 = insn_fetch_type(int8_t); break;
- case 2: imm1 = insn_fetch_type(int16_t); break;
- case 4: imm1 = insn_fetch_type(int32_t); break;
- }
- break;
- case SrcImm16:
- imm1 = insn_fetch_type(uint16_t);
- break;
- }
-
- ctxt->opcode = opcode;
- state->desc = d;
-
- switch ( ext )
- {
- case ext_none:
- rc = x86_decode_onebyte(state, ctxt, ops);
- break;
-
- case ext_0f:
- rc = x86_decode_twobyte(state, ctxt, ops);
- break;
-
- case ext_0f38:
- rc = x86_decode_0f38(state, ctxt, ops);
- break;
-
- case ext_0f3a:
- d = ext0f3a_table[b].to_mem ? DstMem | SrcReg : DstReg | SrcMem;
- if ( ext0f3a_table[b].two_op )
- d |= TwoOp;
- else if ( ext0f3a_table[b].four_op && !mode_64bit() && vex.opcx )
- imm1 &= 0x7f;
- state->desc = d;
- rc = x86_decode_0f3a(state, ctxt, ops);
- break;
-
- case ext_8f08:
- d = DstReg | SrcMem;
- if ( ext8f08_table[b].two_op )
- d |= TwoOp;
- else if ( ext8f08_table[b].four_op && !mode_64bit() )
- imm1 &= 0x7f;
- state->desc = d;
- state->simd_size = ext8f08_table[b].simd_size;
- break;
-
- case ext_8f09:
- case ext_8f0a:
- break;
-
- default:
- ASSERT_UNREACHABLE();
- return X86EMUL_UNIMPLEMENTED;
- }
-
- if ( ea.type == OP_MEM )
- {
- if ( pc_rel )
- ea.mem.off += state->ip;
-
- ea.mem.off = truncate_ea(ea.mem.off);
- }
-
- /*
- * Simple op_bytes calculations. More complicated cases produce 0
- * and are further handled during execute.
- */
- switch ( state->simd_size )
- {
- case simd_none:
- /*
- * When prefix 66 has a meaning different from operand-size override,
- * operand size defaults to 4 and can't be overridden to 2.
- */
- if ( op_bytes == 2 &&
- (ctxt->opcode & X86EMUL_OPC_PFX_MASK) == X86EMUL_OPC_66(0, 0) )
- op_bytes = 4;
- break;
-
-#ifndef X86EMUL_NO_SIMD
- case simd_packed_int:
- switch ( vex.pfx )
- {
- case vex_none:
- if ( !vex.opcx )
- {
- op_bytes = 8;
- break;
- }
- /* fall through */
- case vex_66:
- op_bytes = 16 << evex.lr;
- break;
- default:
- op_bytes = 0;
- break;
- }
- break;
-
- case simd_single_fp:
- if ( vex.pfx & VEX_PREFIX_DOUBLE_MASK )
- {
- op_bytes = 0;
- break;
- case simd_packed_fp:
- if ( vex.pfx & VEX_PREFIX_SCALAR_MASK )
- {
- op_bytes = 0;
- break;
- }
- }
- /* fall through */
- case simd_any_fp:
- switch ( vex.pfx )
- {
- default:
- op_bytes = 16 << evex.lr;
- break;
- case vex_f3:
- generate_exception_if(evex_encoded() && evex.w, EXC_UD);
- op_bytes = 4;
- break;
- case vex_f2:
- generate_exception_if(evex_encoded() && !evex.w, EXC_UD);
- op_bytes = 8;
- break;
- }
- break;
-
- case simd_scalar_opc:
- op_bytes = 4 << (ctxt->opcode & 1);
- break;
-
- case simd_scalar_vexw:
- op_bytes = 4 << vex.w;
- break;
-
- case simd_128:
- /* The special cases here are MMX shift insns. */
- op_bytes = vex.opcx || vex.pfx ? 16 : 8;
- break;
-
- case simd_256:
- op_bytes = 32;
- break;
-#endif /* !X86EMUL_NO_SIMD */
-
- default:
- op_bytes = 0;
- break;
- }
-
- done:
- return rc;
-}
-
-/* No insn fetching past this point. */
-#undef insn_fetch_bytes
-#undef insn_fetch_type
-
/* Undo DEBUG wrapper. */
#undef x86_emulate
@@ -3000,7 +1281,7 @@ x86_emulate(
(_regs.eflags & X86_EFLAGS_VIP)),
EXC_GP, 0);
- rc = x86_decode(&state, ctxt, ops);
+ rc = x86emul_decode(&state, ctxt, ops);
if ( rc != X86EMUL_OKAY )
return rc;
@@ -10497,46 +8778,6 @@ int x86_emulate_wrapper(
}
#endif
-struct x86_emulate_state *
-x86_decode_insn(
- struct x86_emulate_ctxt *ctxt,
- int (*insn_fetch)(
- enum x86_segment seg, unsigned long offset,
- void *p_data, unsigned int bytes,
- struct x86_emulate_ctxt *ctxt))
-{
- static DEFINE_PER_CPU(struct x86_emulate_state, state);
- struct x86_emulate_state *state = &this_cpu(state);
- const struct x86_emulate_ops ops = {
- .insn_fetch = insn_fetch,
- .read = x86emul_unhandleable_rw,
- };
- int rc;
-
- init_context(ctxt);
-
- rc = x86_decode(state, ctxt, &ops);
- if ( unlikely(rc != X86EMUL_OKAY) )
- return ERR_PTR(-rc);
-
-#if defined(__XEN__) && !defined(NDEBUG)
- /*
- * While we avoid memory allocation (by use of per-CPU data) above,
- * nevertheless make sure callers properly release the state structure
- * for forward compatibility.
- */
- if ( state->caller )
- {
- printk(XENLOG_ERR "Unreleased emulation state acquired by %ps\n",
- state->caller);
- dump_execution_state();
- }
- state->caller = __builtin_return_address(0);
-#endif
-
- return state;
-}
-
static inline void check_state(const struct x86_emulate_state *state)
{
#if defined(__XEN__) && !defined(NDEBUG)
^ permalink raw reply [flat|nested] 8+ messages in thread