mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Gcc 11 looks to make incorrect assumptions about valid ranges that pointers may be used for addressing when they are derived from e.g. a plain constant. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100680. Utilize RELOC_HIDE() to work around the issue, which for x86 manifests in at least - mpparse.c:efi_check_config(), - tboot.c:tboot_probe(), - tboot.c:tboot_gen_frametable_integrity(), - x86_emulate.c:x86_emulate() (at -O2 only). The last case is particularly odd not just because it only triggers at higher optimization levels, but also because it only affects one of at least three similar constructs. Various "note" diagnostics claim the valid index range to be [0, 2⁶³-1]. Signed-off-by: Jan Beulich <jbeulich@suse.com> Tested-by: Jason Andryuk <jandryuk@gmail.com> Acked-by: Roger Pau Monné <roger.pau@citrix.com>
279 lines
6.6 KiB
C
279 lines
6.6 KiB
C
#include "x86-emulate.h"
|
|
|
|
#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_; \
|
|
__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 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
|
|
|
|
#define get_stub(stb) ({ \
|
|
assert(!(stb).addr); \
|
|
(void *)((stb).addr = (uintptr_t)(stb).buf); \
|
|
})
|
|
#define put_stub(stb) ((stb).addr = 0)
|
|
|
|
uint32_t mxcsr_mask = 0x0000ffbf;
|
|
struct cpuid_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.)
|
|
*/
|
|
#define FXSAVE_AREA ((struct x86_fxsr *)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_cpuid_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.avx512pf = cp.feat.avx512f;
|
|
cp.feat.rdpid = 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;
|
|
|
|
static unsigned int rdpkru(void)
|
|
{
|
|
return pkru;
|
|
}
|
|
|
|
static void wrpkru(unsigned int val)
|
|
{
|
|
pkru = val;
|
|
}
|
|
|
|
#include "x86_emulate/x86_emulate.c"
|