mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
Change XGETBV architecture modeling to hypercall
This commit is contained in:
committed by
Kyle Elliott
parent
56eee94851
commit
7055a0c54a
@@ -30,6 +30,7 @@ class SyncHyperCall {
|
||||
kX86CPUID,
|
||||
kX86ReadTSC,
|
||||
kX86ReadTSCP,
|
||||
kX86XGetBV,
|
||||
kX86LoadGlobalDescriptorTable,
|
||||
kX86LoadInterruptDescriptorTable,
|
||||
kX86LoadAccessRights,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user