layer for x64

This commit is contained in:
Nikita Smith
2025-11-07 14:39:45 -08:00
committed by Ryan Fleury
parent 942c354bd9
commit e6a01472c8
3 changed files with 420 additions and 0 deletions
+2
View File
@@ -194,6 +194,7 @@
//- rjf: [h]
#include "base/base_inc.h"
#include "x64/x64.h"
#include "linker/hash_table.h"
#include "os/os_inc.h"
#include "artifact_cache/artifact_cache.h"
@@ -242,6 +243,7 @@
//- rjf: [c]
#include "base/base_inc.c"
#include "x64/x64.c"
#include "linker/hash_table.c"
#include "os/os_inc.c"
#include "artifact_cache/artifact_cache.c"
+184
View File
@@ -0,0 +1,184 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
x64_cpuid(U32 leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx)
{
U32 info[4] = {0};
#if COMPILER_MSVC
__cpuid(info, leaf);
if (eax) { *eax = info[0]; }
if (ebx) { *ebx = info[1]; }
if (ecx) { *ecx = info[2]; }
if (edx) { *edx = info[3]; }
#elif COMPILER_CLANG || COMPILER_GCC
if (!eax) { eax = &info[0]; }
if (!ebx) { ebx = &info[1]; }
if (!ecx) { ecx = &info[2]; }
if (!edx) { edx = &info[3]; }
__get_cpuid(leaf, eax, ebx, ecx, edx);
#else
# error "cpuid is not defined for this compiler"
#endif
}
internal void
x64_cpuid_ex(U32 leaf, U32 sub_leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx)
{
U32 info[4];
#if COMPILER_MSVC
__cpuidex(info, leaf, sub_leaf);
if (eax) { *eax = info[0]; }
if (ebx) { *ebx = info[1]; }
if (ecx) { *ecx = info[2]; }
if (edx) { *edx = info[3]; }
#elif COMPILER_CLANG || COMPILER_GCC
if (!eax) { eax = &info[0]; }
if (!ebx) { ebx = &info[1]; }
if (!ecx) { ecx = &info[2]; }
if (!edx) { edx = &info[3]; }
__get_cpuid_count(leaf, sub_leaf, eax, ebx, ecx, edx);
#else
# error "cpuid_count is not defined for this compiler"
#endif
}
internal B32
x64_is_xsave_supported(void)
{
U32 ecx = 0;
x64_cpuid(1, 0, 0, &ecx, 0);
return !!(ecx & (1 << 26));
}
internal U32
x64_get_xsave_size(void)
{
U32 xsave_size = 0;
x64_cpuid_ex(0xd, 0, 0, &xsave_size, 0, 0);
return xsave_size;
}
internal U16
x64_xsave_tag_word_from_real_tag_word(U16 ftw)
{
U16 compact = 0;
for EachIndex(fpr, 8) {
U32 tag = (ftw >> (fpr * 2)) & 3;
if (tag != 3) {
compact |= (1 << fpr);
}
}
return compact;
}
internal U32
x64_xsave_offset_from_feature_flag(U64 xcr0, X64_XStateComponentIdx comp_idx)
{
U32 offset = 0;
if (xcr0 & (1 << comp_idx)) {
if(comp_idx == X64_XStateComponentIdx_FP) {
offset = 0;
} else if(comp_idx == X64_XStateComponentIdx_SSE) {
offset = 160;
} else {
x64_cpuid_ex(0xd, comp_idx, 0, &offset, 0, 0);
}
}
return offset;
}
internal X64_XSaveLayout
x64_get_xsave_layout(U64 xcr0)
{
X64_XSaveLayout xsave_layout = {0};
xsave_layout.x87_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_FP);
xsave_layout.sse_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_SSE);
xsave_layout.avx_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_AVX);
xsave_layout.bndregs_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_BNDREGS);
xsave_layout.bndcfg_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_BNDCSR);
xsave_layout.opmask_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_OPMASK);
xsave_layout.zmm_h_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_ZMM_H);
xsave_layout.zmm_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_ZMM);
xsave_layout.pt_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PT);
xsave_layout.pkru_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PKRU);
xsave_layout.pasid_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PASID);
xsave_layout.cet_u_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_CETU);
xsave_layout.cet_s_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_CETS);
xsave_layout.hdc_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_HDC);
xsave_layout.uintr_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_UINTR);
xsave_layout.lbr_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_LBR);
xsave_layout.hwp_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_HWP);
xsave_layout.tile_cfg_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_TILECFG);
xsave_layout.tile_data_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_TILEDATA);
return xsave_layout;
}
internal void
x64_set_debug_break(U64 *drs, U64 trap_idx, U64 addr, U64 size, X64_BreakpointType bp_type, X64_DebugBreakType break_type)
{
// set breakpoint address
switch (trap_idx) {
case 0: { drs[0] = addr; } break;
case 1: { drs[1] = addr; } break;
case 2: { drs[2] = addr; } break;
case 3: { drs[3] = addr; } break;
default: { InvalidPath; } break;
}
// enable breakpoint
drs[7] &= ~(3 << (trap_idx * 2));
switch (bp_type)
{
case X64_BreakpointType_Null: break;
case X64_BreakpointType_Local: { drs[7] |= 1 << (trap_idx * 2); } break;
case X64_BreakpointType_Global: { drs[7] |= 2 << (trap_idx * 2); } break;
default: { InvalidPath; } break;
}
// set break access type
switch (break_type) {
case X64_DebugBreakType_Exec:
Assert(size == 0);
case X64_DebugBreakType_Null: {
drs[7] &= ~((1u << 16) << (trap_idx * 4));
drs[7] &= ~((1u << 17) << (trap_idx * 4));
} break;
case X64_DebugBreakType_Write: {
drs[7] |= (1u << 16) << (trap_idx * 4);
drs[7] &= ~((1u << 17) << (trap_idx * 4));
} break;
case X64_DebugBreakType_ReadWriteIO: {
drs[7] &= ~((1u << 16) << (trap_idx * 4));
drs[7] |= (1u << 17) << (trap_idx * 4);
} break;
case X64_DebugBreakType_ReadWriteNoFetch: {
drs[7] |= (1u << 16) << (trap_idx * 4);
drs[7] |= (1u << 17) << (trap_idx * 4);
} break;
default: { InvalidPath; } break;
}
// set breakpoint size
switch (size) {
case 0:
case 1: {
drs[7] &= ~((1u << 18) << (trap_idx * 4));
drs[7] &= ~((1u << 19) << (trap_idx * 4));
} break;
case 2: {
drs[7] |= (1 << 18) << (trap_idx * 4);
drs[7] &= ~((1 << 19) << (trap_idx * 4));
} break;
case 4: {
drs[7] |= (1 << 18) << (trap_idx * 4);
drs[7] |= (1 << 19) << (trap_idx * 4);
} break;
case 8: {
drs[7] &= ~((1 << 18) << (trap_idx * 4));
drs[7] |= (1 << 19) << (trap_idx * 4);
} break;
default: { InvalidPath; }
}
}
+234
View File
@@ -0,0 +1,234 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef X64_H
#define X64_H
////////////////////////////////
//~ RFlags
typedef U64 X64_RFlags;
enum
{
X64_RFlag_Carry = (1 << 0),
X64_RFlag_Parity = (1 << 2),
X64_RFlag_AuxCarry = (1 << 4),
X64_RFlag_Zero = (1 << 6),
X64_RFlag_Sign = (1 << 7),
X64_RFlag_Trap = (1 << 8),
X64_RFlag_Interrupt = (1 << 9),
X64_RFlag_Direction = (1 << 10),
X64_RFlag_Overflow = (1 << 11),
X64_RFlag_IoPrivilege = (3 << 12),
X64_RFlag_NT = (1 << 14),
X64_RFlag_MD = (1 << 15),
X64_RFlag_RF = (1 << 16),
X64_RFlag_VM = (1 << 17),
X64_RFlag_AC = (1 << 18),
X64_RFlag_VIF = (1 << 19),
X64_RFlag_VIP = (1 << 20),
X64_RFlag_AES = (1 << 30),
X64_RFlag_AI = (1 << 31),
};
////////////////////////////////
//~ fxsave/xsave
typedef struct AlignType(16) X64_FXSave
{
U16 fcw;
U16 fsw;
U16 ftw;
U16 fop;
union {
struct {
U64 fip;
U64 fdp;
} b64;
struct {
U32 fip;
U16 fcs, _pad0;
U32 fdp;
U16 fds, _pad1;
} b32;
};
U32 mxcsr;
U32 mxcsr_mask;
U128 st_space[8];
U128 xmm_space[16];
U8 padding[96];
} X64_FXSave;
StaticAssert(sizeof(X64_FXSave) == 512, g_x64_xsave_legacy_size_check);
typedef struct X64_XSaveHeader
{
U64 xstate_bv;
U64 xcomp_bv;
U8 reserved[48];
} X64_XSaveHeader;
StaticAssert(sizeof(X64_XSaveHeader) == 64, g_x64_xsave_header_size_check);
typedef struct AlignType(64) X64_XSave
{
X64_FXSave fxsave;
X64_XSaveHeader header;
// U8 ext_area[0];
} X64_XSave;
StaticAssert(sizeof(X64_XSave) == 576, g_x64_xsave_size_check);
typedef U32 X64_XStateComponentIdx;
enum
{
X64_XStateComponentIdx_FP = 0,
X64_XStateComponentIdx_SSE = 1,
X64_XStateComponentIdx_AVX = 2,
X64_XStateComponentIdx_BNDREGS = 3,
X64_XStateComponentIdx_BNDCSR = 4,
X64_XStateComponentIdx_OPMASK = 5,
X64_XStateComponentIdx_ZMM_H = 6,
X64_XStateComponentIdx_ZMM = 7,
X64_XStateComponentIdx_PT = 8,
X64_XStateComponentIdx_PKRU = 9,
X64_XStateComponentIdx_PASID = 10,
X64_XStateComponentIdx_CETU = 11,
X64_XStateComponentIdx_CETS = 12,
X64_XStateComponentIdx_HDC = 13,
X64_XStateComponentIdx_UINTR = 14,
X64_XStateComponentIdx_LBR = 15,
X64_XStateComponentIdx_HWP = 16,
X64_XStateComponentIdx_TILECFG = 17,
X64_XStateComponentIdx_TILEDATA = 18,
};
enum
{
X64_XStateComponentFlag_FP = (1 << X64_XStateComponentIdx_FP),
X64_XStateComponentFlag_SSE = (1 << X64_XStateComponentIdx_SSE),
X64_XStateComponentFlag_AVX = (1 << X64_XStateComponentIdx_AVX),
X64_XStateComponentFlag_BNDREGS = (1 << X64_XStateComponentIdx_BNDREGS),
X64_XStateComponentFlag_BNDCSR = (1 << X64_XStateComponentIdx_BNDCSR),
X64_XStateComponentFlag_OPMASK = (1 << X64_XStateComponentIdx_OPMASK),
X64_XStateComponentFlag_ZMM_H = (1 << X64_XStateComponentIdx_ZMM_H),
X64_XStateComponentFlag_ZMM = (1 << X64_XStateComponentIdx_ZMM),
X64_XStateComponentFlag_PT = (1 << X64_XStateComponentIdx_PT),
X64_XStateComponentFlag_PKRU = (1 << X64_XStateComponentIdx_PKRU),
X64_XStateComponentFlag_PASID = (1 << X64_XStateComponentIdx_PASID),
X64_XStateComponentFlag_CETU = (1 << X64_XStateComponentIdx_CETU),
X64_XStateComponentFlag_CETS = (1 << X64_XStateComponentIdx_CETS),
X64_XStateComponentFlag_HDC = (1 << X64_XStateComponentIdx_HDC),
X64_XStateComponentFlag_UINTR = (1 << X64_XStateComponentIdx_UINTR),
X64_XStateComponentFlag_LBR = (1 << X64_XStateComponentIdx_LBR),
X64_XStateComponentFlag_HWP = (1 << X64_XStateComponentIdx_HWP),
X64_XStateComponentFlag_TILECFG = (1 << X64_XStateComponentIdx_TILECFG),
X64_XStateComponentFlag_TILEDATA = (1 << X64_XStateComponentIdx_TILEDATA),
};
typedef struct
{
U64 x87_offset;
U64 sse_offset;
U64 avx_offset;
U64 bndregs_offset;
U64 bndcfg_offset;
U64 opmask_offset;
U64 zmm_h_offset;
U64 zmm_offset;
U64 pt_offset;
U64 pkru_offset;
U64 pasid_offset;
U64 cet_u_offset;
U64 cet_s_offset;
U64 hdc_offset;
U64 uintr_offset;
U64 lbr_offset;
U64 hwp_offset;
U64 tile_cfg_offset;
U64 tile_data_offset;
} X64_XSaveLayout;
////////////////////////////////
//~ Debug Status Register
typedef enum
{
X64_DebugStatusFlag_B0 = (1 << 0),
X64_DebugStatusFlag_B1 = (1 << 1),
X64_DebugStatusFlag_B2 = (1 << 2),
X64_DebugStatusFlag_B3 = (1 << 3),
X64_DebugStatusFlag_BusLock = (1 << 11),
X64_DebugStatusFlag_DebugRegisterAccess = (1 << 13),
X64_DebugStatusFlag_SingleStep = (1 << 14),
X64_DebugStatusFlag_TaskSwitch = (1 << 15),
X64_DebugStatusFlag_RTM = (1 << 16),
} X64_DebugStatusFlags;
////////////////////////////////
//~ Debug Control Register
typedef enum X64_BreakpointType {
X64_BreakpointType_Null,
X64_BreakpointType_Local,
X64_BreakpointType_Global,
} X64_BreakpointType;
typedef enum X64_DebugBreakType
{
X64_DebugBreakType_Null,
X64_DebugBreakType_Exec,
X64_DebugBreakType_Write,
X64_DebugBreakType_ReadWriteIO,
X64_DebugBreakType_ReadWriteNoFetch,
} X64_DebugBreakType;
typedef enum X64_DebugControlFlags
{
X64_DebugControlFlag_L0 = (1 << 0),
X64_DebugControlFlag_L1 = (1 << 2),
X64_DebugControlFlag_L2 = (1 << 4),
X64_DebugControlFlag_L3 = (1 << 6),
X64_DebugControlFlag_G0 = (1 << 1),
X64_DebugControlFlag_G1 = (1 << 3),
X64_DebugControlFlag_G3 = (1 << 5),
X64_DebugControlFlag_G4 = (1 << 7),
X64_DebugControlFlag_LE = (1 << 8),
X64_DebugControlFlag_GE = (1 << 9),
X64_DebugControlFlag_RTM = (1 << 11),
X64_DebugControlFlag_GD = (1 << 13),
X64_DebugControlFlag_RW0 = (3 << 16),
X64_DebugControlFlag_RW1 = (3 << 20),
X64_DebugControlFlag_RW2 = (3 << 24),
X64_DebugControlFlag_FW3 = (3 << 26),
X64_DebugControlFlag_LEN0 = (3 << 18),
X64_DebugControlFlag_LEN1 = (3 << 22),
X64_DebugControlFlag_LEN2 = (3 << 26),
X64_DebugControlFlag_LEN3 = (3 << 30),
} X64_DebugControlFlags;
////////////////////////////////
//~ cpuid
internal void x64_cpuid(U32 leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx);
internal void x64_cpuid_ex(U32 leaf, U32 sub_leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx);
////////////////////////////////
//~ fxsave/xsave
internal B32 x64_is_xsave_supported(void);
internal U32 x64_get_xsave_size(void);
internal U16 x64_xsave_tag_word_from_real_tag_word(U16 ftw);
internal U32 x64_xsave_offset_from_feature_flag(U64 xcr0, X64_XStateComponentIdx comp_idx);
internal X64_XSaveLayout x64_get_xsave_layout(U64 xcr0);
////////////////////////////////
//~ Debug Control Register
internal void x64_set_debug_break(U64 *drs, U64 trap_idx, U64 addr, U64 size, X64_BreakpointType bp_type, X64_DebugBreakType break_type);
#endif // BASE_X64_H