mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-18 13:34:37 +00:00
369 lines
15 KiB
C
369 lines
15 KiB
C
/**
|
|
* @file PtDefinitions.h
|
|
* @author Masoud Rahimi Jafari (Masoodrahimy1379@gmail.com)
|
|
* @brief Intel Processor Trace (PT) related data structures and hardware
|
|
* definitions shared between the kernel and user-mode components.
|
|
* @details
|
|
* @version 0.19
|
|
* @date 2026-04-29
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
//////////////////////////////////////////////////
|
|
// MSR Addresses //
|
|
// (Intel SDM Vol. 3, Chapter 32) //
|
|
//////////////////////////////////////////////////
|
|
|
|
#define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
|
|
#define MSR_IA32_RTIT_OUTPUT_MASK_PTRS 0x00000561
|
|
#define MSR_IA32_RTIT_CTL 0x00000570
|
|
#define MSR_IA32_RTIT_STATUS 0x00000571
|
|
#define MSR_IA32_RTIT_CR3_MATCH 0x00000572
|
|
|
|
#define MSR_IA32_RTIT_ADDR0_A 0x00000580
|
|
#define MSR_IA32_RTIT_ADDR0_B 0x00000581
|
|
#define MSR_IA32_RTIT_ADDR1_A 0x00000582
|
|
#define MSR_IA32_RTIT_ADDR1_B 0x00000583
|
|
#define MSR_IA32_RTIT_ADDR2_A 0x00000584
|
|
#define MSR_IA32_RTIT_ADDR2_B 0x00000585
|
|
#define MSR_IA32_RTIT_ADDR3_A 0x00000586
|
|
#define MSR_IA32_RTIT_ADDR3_B 0x00000587
|
|
|
|
//
|
|
// Used in PMI acknowledgment
|
|
//
|
|
#define MSR_IA32_PERF_GLOBAL_STATUS 0x0000038E
|
|
#define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x00000390
|
|
|
|
//
|
|
// Bit 55 of IA32_PERF_GLOBAL_STATUS: ToPA PMI pending
|
|
//
|
|
#define PERF_GLOBAL_STATUS_TOPA_PMI (1ULL << 55)
|
|
|
|
//////////////////////////////////////////////////
|
|
// Constants //
|
|
//////////////////////////////////////////////////
|
|
|
|
#define PT_PAGE_SIZE 0x1000ULL /* 4 KB */
|
|
#define PT_OVERFLOW_SIZE PT_PAGE_SIZE /* 4 KB overflow landing zone */
|
|
#define PT_MAX_ADDR_RANGES 4
|
|
|
|
//
|
|
// Maximum CPUs that the PT user-mode mmap surface can describe in a
|
|
// single request. Sized to fit one HYPERTRACE_PT_MMAP_PACKETS within a
|
|
// typical IOCTL buffer and to cover realistic host topologies.
|
|
//
|
|
#define PT_MAX_CPUS_FOR_MMAP 64
|
|
|
|
//
|
|
// ToPA entry Size field encoding: value N = 4KB * 2^N
|
|
//
|
|
#define PT_TOPA_SIZE_4K 0
|
|
#define PT_TOPA_SIZE_8K 1
|
|
#define PT_TOPA_SIZE_16K 2
|
|
#define PT_TOPA_SIZE_32K 3
|
|
#define PT_TOPA_SIZE_64K 4
|
|
#define PT_TOPA_SIZE_128K 5
|
|
#define PT_TOPA_SIZE_256K 6
|
|
#define PT_TOPA_SIZE_512K 7
|
|
#define PT_TOPA_SIZE_1M 8
|
|
#define PT_TOPA_SIZE_2M 9
|
|
#define PT_TOPA_SIZE_4M 10
|
|
#define PT_TOPA_SIZE_8M 11
|
|
#define PT_TOPA_SIZE_16M 12
|
|
#define PT_TOPA_SIZE_32M 13
|
|
#define PT_TOPA_SIZE_64M 14
|
|
#define PT_TOPA_SIZE_128M 15
|
|
|
|
//////////////////////////////////////////////////
|
|
// MSR Structures //
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief IA32_RTIT_CTL — PT master control register
|
|
* @details Intel SDM Vol. 3, Section 32.2.7.2
|
|
*/
|
|
typedef union _PT_RTIT_CTL_REGISTER
|
|
{
|
|
struct
|
|
{
|
|
UINT64 TraceEn : 1; /* [0] Enable tracing */
|
|
UINT64 CycEn : 1; /* [1] CYC packets */
|
|
UINT64 Os : 1; /* [2] Trace CPL 0 */
|
|
UINT64 User : 1; /* [3] Trace CPL > 0 */
|
|
UINT64 PwrEvtEn : 1; /* [4] Power event trace */
|
|
UINT64 FupOnPtw : 1; /* [5] FUP on PTWRITE */
|
|
UINT64 FabricEn : 1; /* [6] Trace to fabric (must be 0) */
|
|
UINT64 Cr3Filter : 1; /* [7] Filter by CR3 */
|
|
UINT64 ToPA : 1; /* [8] Use ToPA output scheme */
|
|
UINT64 MtcEn : 1; /* [9] MTC packets */
|
|
UINT64 TscEn : 1; /* [10] TSC packets */
|
|
UINT64 DisRetc : 1; /* [11] Disable RET compression */
|
|
UINT64 PtwEn : 1; /* [12] PTWRITE packets */
|
|
UINT64 BranchEn : 1; /* [13] Branch trace (TNT, TIP, FUP) */
|
|
UINT64 MtcFreq : 4; /* [14:17] MTC frequency */
|
|
UINT64 Reserved0 : 1; /* [18] Must be 0 */
|
|
UINT64 CycThresh : 4; /* [19:22] CYC threshold */
|
|
UINT64 Reserved1 : 1; /* [23] Must be 0 */
|
|
UINT64 PsbFreq : 4; /* [24:27] PSB frequency */
|
|
UINT64 Reserved2 : 4; /* [28:31] Must be 0 */
|
|
UINT64 Addr0Cfg : 4; /* [32:35] Range 0 mode (1=filter / 2=stop) */
|
|
UINT64 Addr1Cfg : 4; /* [36:39] Range 1 mode */
|
|
UINT64 Addr2Cfg : 4; /* [40:43] Range 2 mode */
|
|
UINT64 Addr3Cfg : 4; /* [44:47] Range 3 mode */
|
|
UINT64 Reserved3 : 16; /* [48:63] Must be 0 */
|
|
};
|
|
UINT64 Value;
|
|
} PT_RTIT_CTL_REGISTER, *PPT_RTIT_CTL_REGISTER;
|
|
|
|
/**
|
|
* @brief IA32_RTIT_STATUS — PT status / error register
|
|
* @details Intel SDM Vol. 3, Section 32.2.7.4
|
|
*/
|
|
typedef union _PT_RTIT_STATUS_REGISTER
|
|
{
|
|
struct
|
|
{
|
|
UINT64 FilterEn : 1; /* [0] RO: IP filter allowing trace */
|
|
UINT64 ContextEn : 1; /* [1] RO: Context (CR3) allowing trace */
|
|
UINT64 TriggerEn : 1; /* [2] RO: Trigger conditions met */
|
|
UINT64 Reserved0 : 1; /* [3] Must be 0 */
|
|
UINT64 Error : 1; /* [4] RO/Sticky: Operational error */
|
|
UINT64 Stopped : 1; /* [5] RO: TraceStop hit */
|
|
UINT64 PendTopaPmi : 1; /* [6] RW: ToPA PMI pending — clear this */
|
|
UINT64 PendPsbPmi : 1; /* [7] RW: PSB+ PMI pending — clear this */
|
|
UINT64 Reserved1 : 24; /* [8:31] Must be 0 */
|
|
UINT64 PacketByteCnt : 17; /* [32:48] Bytes since last PSB */
|
|
UINT64 Reserved2 : 15; /* [49:63] Must be 0 */
|
|
};
|
|
UINT64 Value;
|
|
} PT_RTIT_STATUS_REGISTER, *PPT_RTIT_STATUS_REGISTER;
|
|
|
|
/**
|
|
* @brief IA32_RTIT_OUTPUT_MASK_PTRS — Output position tracker
|
|
* @details Intel SDM Vol. 3, Section 32.2.7.8
|
|
*/
|
|
typedef union _PT_OUTPUT_MASK_PTRS_REGISTER
|
|
{
|
|
struct
|
|
{
|
|
UINT64 LowerMask : 7; /* [0:6] Forced to 0x7F */
|
|
UINT64 MaskOrTableOffset : 25; /* [7:31] ToPA: table entry index */
|
|
UINT64 OutputOffset : 32; /* [32:63] Byte offset in current entry */
|
|
};
|
|
UINT64 Value;
|
|
} PT_OUTPUT_MASK_PTRS_REGISTER, *PPT_OUTPUT_MASK_PTRS_REGISTER;
|
|
|
|
/**
|
|
* @brief ToPA Table Entry
|
|
* @details Intel SDM Vol. 3, Section 32.2.7.2 (Table of Physical Addresses)
|
|
*/
|
|
typedef union _PT_TOPA_ENTRY
|
|
{
|
|
struct
|
|
{
|
|
UINT64 End : 1; /* [0] Last entry — wraps to next table */
|
|
UINT64 Reserved0 : 1; /* [1] Must be 0 */
|
|
UINT64 Int : 1; /* [2] Generate PMI when region fills */
|
|
UINT64 Reserved1 : 1; /* [3] Must be 0 */
|
|
UINT64 Stop : 1; /* [4] Stop tracing when region fills */
|
|
UINT64 Reserved2 : 1; /* [5] Must be 0 */
|
|
UINT64 Size : 4; /* [6:9] Region size (4K*2^N) */
|
|
UINT64 Reserved3 : 2; /* [10:11] Must be 0 */
|
|
UINT64 BaseAddr : 36; /* [12:47] Physical address >> 12 */
|
|
UINT64 Reserved4 : 16; /* [48:63] Must be 0 */
|
|
};
|
|
UINT64 Value;
|
|
} PT_TOPA_ENTRY, *PPT_TOPA_ENTRY;
|
|
|
|
//////////////////////////////////////////////////
|
|
// Capability / Config //
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Discovered Intel PT capabilities (populated from CPUID leaf 0x14).
|
|
*/
|
|
typedef struct _PT_CAPABILITIES
|
|
{
|
|
UINT32 Cr3Filtering : 1; /* Can filter by process CR3 */
|
|
UINT32 PsbCycConfigurable : 1; /* PSBFreq and CYC configurable */
|
|
UINT32 IpFiltering : 1; /* IP filtering and TraceStop supported */
|
|
UINT32 MtcSupport : 1; /* MTC packets supported */
|
|
UINT32 PtwriteSupport : 1; /* PTWRITE instruction supported */
|
|
UINT32 PowerEventTrace : 1; /* Power event trace supported */
|
|
UINT32 VmxSupport : 1; /* PT works in VMX operations */
|
|
UINT32 TopaOutput : 1; /* ToPA output scheme supported */
|
|
UINT32 TopaMultiEntry : 1; /* ToPA tables can have >1 entry */
|
|
UINT32 SingleRangeOutput : 1; /* Single contiguous range output */
|
|
UINT32 TransportOutput : 1; /* Trace transport subsystem output */
|
|
UINT32 IpPayloadsAreLip : 1; /* IP payloads are LIP (not RIP) */
|
|
UINT32 Reserved : 20;
|
|
|
|
UINT32 NumAddrRanges; /* Number of ADDRn_CFG pairs (0-4) */
|
|
UINT16 MtcPeriodBitmap; /* Supported MTC period values */
|
|
UINT16 CycThresholdBitmap; /* Supported CYC threshold values */
|
|
UINT16 PsbFreqBitmap; /* Supported PSB frequency values */
|
|
|
|
} PT_CAPABILITIES, *PPT_CAPABILITIES;
|
|
|
|
/**
|
|
* @brief Intel PT trace state machine.
|
|
*/
|
|
typedef enum _PT_STATE
|
|
{
|
|
PT_STATE_DISABLED = 0, /* No buffers allocated, PT off */
|
|
PT_STATE_READY, /* Buffers allocated, MSRs not yet programmed */
|
|
PT_STATE_TRACING, /* TraceEn=1, actively generating packets */
|
|
PT_STATE_PAUSED, /* TraceEn=0 temporarily (PMI or user pause) */
|
|
PT_STATE_STOPPED, /* Tracing done, buffer has valid data */
|
|
PT_STATE_ERROR /* Hardware error (check IA32_RTIT_STATUS) */
|
|
} PT_STATE;
|
|
|
|
/**
|
|
* @brief Intel PT IP filter range.
|
|
*/
|
|
typedef struct _PT_ADDR_RANGE
|
|
{
|
|
UINT64 Start; /* Start virtual address — written to ADDRn_A */
|
|
UINT64 End; /* End virtual address — written to ADDRn_B */
|
|
BOOLEAN IsStopRange; /* FALSE = filter (only trace inside range)
|
|
TRUE = trace-stop (stop when entering range) */
|
|
} PT_ADDR_RANGE, *PPT_ADDR_RANGE;
|
|
|
|
/**
|
|
* @brief Intel PT trace configuration — what the user specifies.
|
|
*/
|
|
typedef struct _PT_TRACE_CONFIG
|
|
{
|
|
//
|
|
// What to trace
|
|
//
|
|
BOOLEAN TraceUser; /* Trace CPL 3 (user mode) */
|
|
BOOLEAN TraceKernel; /* Trace CPL 0 (kernel mode) */
|
|
UINT64 TargetCr3; /* Process to trace (0 = trace all) */
|
|
|
|
//
|
|
// IP filtering
|
|
//
|
|
UINT32 NumAddrRanges; /* 0-4 active ranges */
|
|
PT_ADDR_RANGE AddrRanges[PT_MAX_ADDR_RANGES];
|
|
|
|
//
|
|
// Packet options
|
|
//
|
|
BOOLEAN EnableBranch; /* BranchEn — must be TRUE for useful traces */
|
|
BOOLEAN EnableTsc; /* TscEn — timestamps at PSB boundaries */
|
|
BOOLEAN EnableMtc; /* MtcEn — wall-clock timing packets */
|
|
BOOLEAN EnableCyc; /* CycEn — cycle-accurate packets */
|
|
BOOLEAN EnableRetCompression; /* TRUE keeps RET compression */
|
|
UINT8 MtcFreq; /* 0-15: MTC period (must be in capabilities) */
|
|
UINT8 CycThresh; /* 0-15: CYC threshold */
|
|
UINT8 PsbFreq; /* 0-15: PSB frequency (0 = every 2KB) */
|
|
|
|
//
|
|
// Buffer size
|
|
//
|
|
UINT64 BufferSize; /* Main output buffer size in bytes
|
|
Must be 4KB * 2^N (4KB, 8KB, ..., 128MB)
|
|
Default: PT_DEFAULT_BUFFER_SIZE (2MB) */
|
|
} PT_TRACE_CONFIG, *PPT_TRACE_CONFIG;
|
|
|
|
//////////////////////////////////////////////////
|
|
// Per-CPU Trace State //
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Per-CPU PT buffer layout
|
|
*
|
|
* ToPA Table (one 4KB page, 3 entries used):
|
|
* Entry[0] — Main data buffer (BufferSize), INT=1
|
|
* Entry[1] — Overflow zone (4KB), INT=0
|
|
* Entry[2] — END, points back to ToPA table (circular)
|
|
*/
|
|
typedef struct _PT_BUFFER
|
|
{
|
|
//
|
|
// ToPA table
|
|
//
|
|
PT_TOPA_ENTRY * TopaVa; /* Virtual addr of the ToPA table */
|
|
UINT64 TopaPhysical; /* Physical addr — IA32_RTIT_OUTPUT_BASE */
|
|
|
|
//
|
|
// Main output buffer
|
|
//
|
|
PVOID OutputVa; /* Virtual addr — read trace data from here */
|
|
UINT64 OutputPhysical; /* Physical addr — goes into ToPA entry[0] */
|
|
UINT64 OutputSize; /* Bytes (e.g., 0x200000 for 2MB) */
|
|
|
|
//
|
|
// Overflow landing zone (4KB)
|
|
//
|
|
PVOID OverflowVa; /* Virtual addr of overflow page */
|
|
UINT64 OverflowPhysical; /* Physical addr — ToPA entry[1] */
|
|
|
|
} PT_BUFFER, *PPT_BUFFER;
|
|
|
|
/**
|
|
* @brief Per-CPU Intel PT state — one of these per logical processor.
|
|
*/
|
|
typedef struct _PT_PER_CPU
|
|
{
|
|
PT_BUFFER Buffer; /* ToPA + output buffers */
|
|
PT_RTIT_CTL_REGISTER SavedCtl; /* Last written IA32_RTIT_CTL */
|
|
PT_TRACE_CONFIG Config; /* Current trace configuration */
|
|
PT_STATE State; /* Current state machine position */
|
|
UINT64 TotalBytesCaptured; /* Accumulated across PMI events */
|
|
|
|
} PT_PER_CPU, *PPT_PER_CPU;
|
|
|
|
//////////////////////////////////////////////////
|
|
// Trace Output Descriptor //
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Trace output descriptor
|
|
*
|
|
* Passed to the engine to receive trace data. WriteOffset serves dual purpose:
|
|
* - Input: where in Buffer to start writing new data.
|
|
* - Output: updated to Buffer[0..WriteOffset) = valid data after the call.
|
|
*
|
|
* If the remaining space (Length - WriteOffset) is smaller than the new data,
|
|
* the copy is skipped and WriteOffset is not updated.
|
|
* Pass NULL instead of a PT_OUTPUT_BUFFER * to skip copying entirely.
|
|
*/
|
|
typedef struct _PT_OUTPUT_BUFFER
|
|
{
|
|
PVOID Buffer; /* Destination buffer for trace data */
|
|
UINT64 Length; /* Total size of Buffer in bytes */
|
|
UINT64 WriteOffset; /* Next write position; valid data is [0..WriteOffset) */
|
|
|
|
} PT_OUTPUT_BUFFER, *PPT_OUTPUT_BUFFER;
|
|
|
|
//////////////////////////////////////////////////
|
|
// User-mode mmap descriptor //
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief One per-CPU descriptor returned by the PT mmap surface.
|
|
*
|
|
* The main output buffer and the 4 KB overflow page are stitched
|
|
* into a single virtually contiguous region in the calling user
|
|
* process — main first, then overflow, matching the order PT
|
|
* writes them on a ToPA PMI. Consumers read the whole stream
|
|
* as Size bytes starting at UserVa.
|
|
*
|
|
* UserVa is valid only in the address space of the process that
|
|
* issued the mmap IOCTL, and only until PT is disabled / flushed
|
|
* (at which point the underlying kernel buffers are torn down).
|
|
*/
|
|
typedef struct _PT_USER_BUFFER_DESC
|
|
{
|
|
UINT32 CpuId;
|
|
UINT32 Reserved;
|
|
UINT64 UserVa; /* base of the combined main + overflow mapping */
|
|
UINT64 Size; /* total bytes in the mapping (main + overflow) */
|
|
|
|
} PT_USER_BUFFER_DESC, *PPT_USER_BUFFER_DESC;
|