Change XGETBV architecture modeling to hypercall

This commit is contained in:
Duncan Ogilvie
2026-03-26 15:53:12 +01:00
committed by Kyle Elliott
parent 56eee94851
commit 7055a0c54a
5 changed files with 15 additions and 77 deletions
+1
View File
@@ -30,6 +30,7 @@ class SyncHyperCall {
kX86CPUID,
kX86ReadTSC,
kX86ReadTSCP,
kX86XGetBV,
kX86LoadGlobalDescriptorTable,
kX86LoadInterruptDescriptorTable,
kX86LoadAccessRights,
+1 -29
View File
@@ -445,34 +445,6 @@ struct alignas(8) ArithFlags final {
static_assert(16 == sizeof(ArithFlags), "Invalid packing of `ArithFlags`.");
union XCR0 {
uint64_t flat;
struct {
uint32_t eax;
uint32_t edx;
} __attribute__((packed));
// Bits specify what process states should be saved.
struct {
uint64_t x87_fpu_mmx : 1; // Must be 1; bit 0.
uint64_t xmm : 1; // SSE.
uint64_t ymm : 1; // AVX and AVX2.
uint64_t bndreg : 1; // Part of MPX.
uint64_t bndcsr : 1; // Part of MPX.
uint64_t opmask : 1; // Registers k0 through k7, AVX512-only.
uint64_t
zmm_hi256 : 1; // High 256 bits of ZMM0 through ZMM15, AVX512-only.
uint64_t hi16_zmm : 1; // ZMM16 through ZMM31, AVX512-only.
uint64_t pkru : 1; // Protected key stuff.
uint64_t _reserved0 : 53;
uint64_t lwp : 1; // AMD lightweight profiling.
uint64_t _reserved1 : 1;
} __attribute__((packed));
} __attribute__((packed));
static_assert(8 == sizeof(XCR0), "Invalid packing of `XCR0`.");
struct alignas(8) Segments final {
volatile uint16_t _0;
SegmentSelector ss;
@@ -794,7 +766,7 @@ struct alignas(16) X86State : public ArchState {
X87Stack st; // 128 bytes.
MMX mmx; // 128 bytes.
FPUStatusFlags sw; // 24 bytes
XCR0 xcr0; // 8 bytes.
uint8_t _padding[8]; // 8 bytes
FPU x87; // 512 bytes
SegmentCaches seg_caches; // 96 bytes
K_REG k_reg; // 128 bytes.
+10
View File
@@ -89,6 +89,16 @@ Memory *__remill_sync_hyper_call(State &state, Memory *mem,
"d"(state.gpr.rdx.aword));
break;
case SyncHyperCall::kX86XGetBV: {
uint32_t eax = 0;
uint32_t edx = 0;
const auto selector = static_cast<uint32_t>(state.addr_to_load);
asm volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(selector));
state.gpr.rax.aword = eax;
state.gpr.rdx.aword = edx;
break;
}
case SyncHyperCall::kX86LoadGlobalDescriptorTable: {
const auto read =
__remill_read_memory_64(mem, static_cast<addr_t>(state.addr_to_load));
+3 -27
View File
@@ -16,33 +16,9 @@
namespace {
DEF_SEM(DoXGETBV, PC next_pc) {
switch (Read(REG_ECX)) {
// Current state of the `xcr0` register.
case 0:
WriteZExt(IF_64BIT_ELSE(REG_RAX, REG_EAX), state.xcr0.eax);
WriteZExt(IF_64BIT_ELSE(REG_RDX, REG_EDX), state.xcr0.edx);
break;
// Current state of the `xcr0` register, anded with the `xinuse` register.
// We fake this as saying: this is what
case 1: {
XCR0 xcr0 = {};
xcr0.x87_fpu_mmx = 1;
xcr0.xmm = 1;
IF_AVX(xcr0.ymm = 1;)
IF_AVX512(xcr0.opmask = 1;)
IF_AVX512(xcr0.zmm_hi256 = 1;)
IF_AVX512(xcr0.hi16_zmm = 1;)
WriteZExt(IF_64BIT_ELSE(REG_RAX, REG_EAX), xcr0.eax);
WriteZExt(IF_64BIT_ELSE(REG_RDX, REG_EDX), xcr0.edx);
break;
}
default: WriteZExt(REG_PC, Read(next_pc)); StopFailure();
}
return memory;
DEF_SEM(DoXGETBV, PC) {
state.addr_to_load = ZExtTo<uint64_t>(Read(REG_ECX));
return __remill_sync_hyper_call(state, memory, SyncHyperCall::kX86XGetBV);
}
} // namespace
-21
View File
@@ -914,26 +914,6 @@ static void RunWithFlags(const test::TestInfo *info, Flags flags,
ImportX87State(native_state);
ResetFlags();
#if defined(__x86_64__) || defined(__i386__)
{
uint32_t eax = 1;
uint32_t ebx = 0;
uint32_t ecx = 0;
uint32_t edx = 0;
asm volatile("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(eax), "b"(ebx), "c"(ecx), "d"(edx));
if (ecx & (1U << 26U)) {
uint32_t xcr0_lo = 0;
uint32_t xcr0_hi = 0;
asm volatile("xgetbv" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0));
native_state->xcr0.eax = xcr0_lo;
native_state->xcr0.edx = xcr0_hi;
lifted_state->xcr0 = native_state->xcr0;
}
}
#endif
// Set up the RIP correctly.
lifted_state->gpr.rip.aword = static_cast<addr_t>(info->test_begin);
native_state->gpr.rip.aword = static_cast<addr_t>(info->test_end);
@@ -1206,7 +1186,6 @@ static void RunWithFlags(const test::TestInfo *info, Flags flags,
<< "st:" << offsetof(State, st) << "\n"
<< "mmx:" << offsetof(State, mmx) << "\n"
<< "sw:" << offsetof(State, sw) << "\n"
<< "xcr0:" << offsetof(State, xcr0) << "\n"
<< "x87:" << offsetof(State, x87) << "\n"
<< "seg_caches:" << offsetof(State, seg_caches) << "\n";
}