mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86emul: split off opcode 0f01 handling
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> Acked-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
1 parent
d6e0b4c41a
commit
9ace97ab9b
10 files changed
+951
-821
No files matched your search
@@ -13,9 +13,11 @@ endif
|
||||
ln -nsf $< $@
|
||||
|
||||
x86_emulate: FORCE
|
||||
ln -nsf $(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 ;
|
||||
|
||||
%.c: $(XEN_ROOT)/tools/tests/x86_emulator/%.c FORCE
|
||||
ln -nsf $< $@
|
||||
@@ -29,17 +31,26 @@ GCOV_FLAGS := --coverage
|
||||
%-cov.o: %.c
|
||||
$(CC) -c $(CFLAGS) $(GCOV_FLAGS) $< -o $@
|
||||
|
||||
OBJS := fuzz-emul.o x86-emulate.o
|
||||
OBJS += x86_emulate/0f01.o
|
||||
|
||||
x86-emulate.h: x86_emulate/x86_emulate.h
|
||||
x86-emulate.o x86-emulate-cov.o: x86-emulate.h x86_emulate/x86_emulate.c
|
||||
x86-emulate.o x86-emulate-cov.o: x86-emulate.h x86_emulate/x86_emulate.c x86_emulate/private.h
|
||||
fuzz-emul.o fuzz-emul-cov.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
|
||||
|
||||
@@ -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/include/xen/asm/,\
|
||||
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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef X86_EMULATE_H
|
||||
#define X86_EMULATE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -124,6 +127,9 @@ static inline bool xcr0_mask(uint64_t mask)
|
||||
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
|
||||
@@ -201,3 +207,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 */
|
||||
@@ -9,6 +9,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) :=
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <asm/x86_emulate.h>
|
||||
#include <asm/processor.h> /* current_cpu_info */
|
||||
#include <asm/prot-key.h>
|
||||
#include <asm/xstate.h>
|
||||
#include <asm/amd.h> /* cpu_has_amd_erratum() */
|
||||
#include <asm/debugreg.h>
|
||||
@@ -26,8 +25,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)
|
||||
|
||||
@@ -56,12 +53,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 cf_check x86emul_read_xcr(
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
|
||||
#ifdef __XEN__
|
||||
#include <asm/prot-key.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
obj-y += 0f01.o
|
||||
@@ -0,0 +1,532 @@
|
||||
/******************************************************************************
|
||||
* 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_nscb() (ctxt->cpuid->extd.nscb)
|
||||
|
||||
#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_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_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk)
|
||||
#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);
|
||||
}
|
||||
@@ -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[256] = {
|
||||
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_t ec, ...)
|
||||
})
|
||||
#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; \
|
||||
@@ -1899,29 +1556,6 @@ static int ioport_access_check(
|
||||
return rc;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -1934,108 +1568,6 @@ amd_like(const struct x86_emulate_ctxt *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_nscb() (ctxt->cpuid->extd.nscb)
|
||||
|
||||
#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_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_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk)
|
||||
#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)
|
||||
{
|
||||
@@ -2082,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;
|
||||
|
||||
@@ -2482,17 +2014,6 @@ static bool is_branch_step(struct x86_emulate_ctxt *ctxt,
|
||||
(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)
|
||||
{
|
||||
@@ -5706,317 +5227,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);
|
||||
@@ -11337,6 +10549,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 )
|
||||
|
||||