Files
xen/tools/tests/x86_emulator/x86-emulate.c
T
Jan Beulich 85191cf321 x86: drop Xeon Phi support
Do as was decided in Lisbon. Reportedly Xen hasn't been working very
well on those processors anyway.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-By: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Roger Pau Monné <roger.pau@citrix.com>
2024-08-02 08:43:25 +02:00

269 lines
6.2 KiB
C

#include "x86-emulate.h"
#include <errno.h>
#include <sys/mman.h>
/* See gcc bug 100680, but here don't bother making this version dependent. */
#define gcc11_wrap(x) ({ \
unsigned long x_; \
__asm__ ( "" : "=g" (x_) : "0" (x) ); \
(typeof(x))x_; \
})
#define cpu_has_amd_erratum(nr) 0
#define cpu_has_mpx false
#define read_bndcfgu() 0
#define xstate_set_init(what)
/* For generic assembly code: use macros to define operation/operand sizes. */
#ifdef __i386__
# define __OS "l" /* Operation Suffix */
# define __OP "e" /* Operand Prefix */
#else
# define __OS "q" /* Operation Suffix */
# define __OP "r" /* Operand Prefix */
#endif
uint32_t mxcsr_mask = 0x0000ffbf;
struct cpu_policy cp;
static char fpu_save_area[0x4000] __attribute__((__aligned__((64))));
static bool use_xsave;
/*
* Re-use the area above also as scratch space for the emulator itself.
* (When debugging the emulator, care needs to be taken when inserting
* printf() or alike function calls into regions using this.)
*/
struct x86_fxsr *get_fpu_save_area(void)
{
return (void *)fpu_save_area;
}
void emul_save_fpu_state(void)
{
if ( use_xsave )
asm volatile ( "xsave %[ptr]"
: [ptr] "=m" (fpu_save_area)
: "a" (~0ul), "d" (~0ul) );
else
asm volatile ( "fxsave %0" : "=m" (fpu_save_area) );
}
void emul_restore_fpu_state(void)
{
/* Older gcc can't deal with "m" array inputs; make them outputs instead. */
if ( use_xsave )
asm volatile ( "xrstor %[ptr]"
: [ptr] "+m" (fpu_save_area)
: "a" (~0ul), "d" (~0ul) );
else
asm volatile ( "fxrstor %0" : "+m" (fpu_save_area) );
}
bool emul_test_init(void)
{
union {
char x[464];
struct {
uint32_t other[6];
uint32_t mxcsr;
uint32_t mxcsr_mask;
/* ... */
};
} *fxs = (void *)fpu_save_area;
unsigned long sp;
x86_cpu_policy_fill_native(&cp);
/*
* The emulator doesn't use these instructions, so can always emulate
* them.
*/
cp.basic.movbe = true;
cp.feat.invpcid = true;
cp.feat.adx = true;
cp.feat.rdpid = true;
cp.feat.wrmsrns = true;
cp.extd.clzero = true;
if ( cpu_has_xsave )
{
unsigned int tmp, ebx;
asm ( "cpuid"
: "=a" (tmp), "=b" (ebx), "=c" (tmp), "=d" (tmp)
: "a" (0xd), "c" (0) );
/*
* Sanity check that fpu_save_area[] is large enough. This assertion
* will trip eventually, at which point fpu_save_area[] needs to get
* larger.
*/
assert(ebx < sizeof(fpu_save_area));
/* Use xsave if available... */
use_xsave = true;
}
else
/* But use fxsave if xsave isn't available. */
assert(cpu_has_fxsr);
/* Reuse the save state buffer to find mcxsr_mask. */
asm ( "fxsave %0" : "=m" (*fxs) );
if ( fxs->mxcsr_mask )
mxcsr_mask = fxs->mxcsr_mask;
/*
* Mark the entire stack executable so that the stub executions
* don't fault
*/
#ifdef __x86_64__
asm ("movq %%rsp, %0" : "=g" (sp));
#else
asm ("movl %%esp, %0" : "=g" (sp));
#endif
return mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000),
MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0;
}
int emul_test_cpuid(
uint32_t leaf,
uint32_t subleaf,
struct cpuid_leaf *res,
struct x86_emulate_ctxt *ctxt)
{
asm ("cpuid"
: "=a" (res->a), "=b" (res->b), "=c" (res->c), "=d" (res->d)
: "a" (leaf), "c" (subleaf));
/*
* The emulator doesn't itself use MOVBE, so we can always run the
* respective tests.
*/
if ( leaf == 1 )
res->c |= 1U << 22;
/*
* The emulator doesn't itself use ADCX/ADOX/RDPID nor the S/G prefetch
* insns, so we can always run the respective tests.
*/
if ( leaf == 7 && subleaf == 0 )
{
res->b |= (1U << 10) | (1U << 19);
if ( res->b & (1U << 16) )
res->b |= 1U << 26;
res->c |= 1U << 22;
}
/*
* The emulator doesn't itself use CLZERO, so we can always run the
* respective test(s).
*/
if ( leaf == 0x80000008 )
res->b |= 1U << 0;
return X86EMUL_OKAY;
}
int emul_test_read_cr(
unsigned int reg,
unsigned long *val,
struct x86_emulate_ctxt *ctxt)
{
/* Fake just enough state for the emulator's _get_fpu() to be happy. */
switch ( reg )
{
case 0:
*val = 0x00000001; /* PE */
return X86EMUL_OKAY;
case 4:
*val = X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_PKE |
(cpu_has_xsave ? X86_CR4_OSXSAVE : 0);
return X86EMUL_OKAY;
}
return X86EMUL_UNHANDLEABLE;
}
int emul_test_read_xcr(
unsigned int reg,
uint64_t *val,
struct x86_emulate_ctxt *ctxt)
{
uint32_t lo, hi;
ASSERT(cpu_has_xsave);
switch ( reg )
{
case 0:
break;
case 1:
if ( cpu_has_xgetbv1 )
break;
/* fall through */
default:
x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
return X86EMUL_EXCEPTION;
}
asm ( "xgetbv" : "=a" (lo), "=d" (hi) : "c" (reg) );
*val = lo | ((uint64_t)hi << 32);
return X86EMUL_OKAY;
}
int emul_test_get_fpu(
enum x86_emulate_fpu_type type,
struct x86_emulate_ctxt *ctxt)
{
switch ( type )
{
case X86EMUL_FPU_fpu:
break;
case X86EMUL_FPU_mmx:
if ( cpu_has_mmx )
break;
case X86EMUL_FPU_xmm:
if ( cpu_has_sse )
break;
case X86EMUL_FPU_ymm:
if ( cpu_has_avx )
break;
case X86EMUL_FPU_opmask:
case X86EMUL_FPU_zmm:
if ( cpu_has_avx512f )
break;
default:
return X86EMUL_UNHANDLEABLE;
}
return X86EMUL_OKAY;
}
void emul_test_put_fpu(
struct x86_emulate_ctxt *ctxt,
enum x86_emulate_fpu_type backout,
const struct x86_emul_fpu_aux *aux)
{
/* TBD */
}
static uint32_t pkru;
unsigned int rdpkru(void)
{
return pkru;
}
void wrpkru(unsigned int val)
{
pkru = val;
}
#include "x86_emulate/x86_emulate.c"