#pragma once #include #ifdef MSVC #include #define platform_independent_cpuid(function_id, array_of_registers) \ __cpuid(array_of_registers, function_id) #define platform_independent_cpuidex(function_id, sub_function_id, array_of_registers) \ __cpuid_count(array_of_registers, function_id, sub_function_id) #else #include #define platform_independent_cpuid(function_id, array_of_registers) \ __cpuid(function_id, array_of_registers[0], array_of_registers[1], \ array_of_registers[2],array_of_registers[3]) #define platform_independent_cpuidex(function_id, sub_function_id, array_of_registers) \ __cpuid_count (function_id, sub_function_id, array_of_registers[0], \ array_of_registers[1], array_of_registers[2], \ array_of_registers[3]) #endif enum struct Edx_1_Feature_Flags { fpu = 1<<0, // Onboard x87 FPU vme = 1<<1, // Virtual 8086 mode extensions (such as VIF, VIP, PIV) de = 1<<2, // Debugging extensions (CR4 bit 3) pse = 1<<3, // Page Size Extension tsc = 1<<4, // Time Stamp Counter msr = 1<<5, // Model-specific registers pae = 1<<6, // Physical Address Extension mce = 1<<7, // Machine Check Exception cx8 = 1<<8, // CMPXCHG8 (compare-and-swap) instruction apic = 1<<9, // Onboard Advanced Programmable Interrupt Controller _resv1 = 1<<10, // (reserved) sep = 1<<11, // SYSENTER and SYSEXIT instructions mtrr = 1<<12, // Memory Type Range Registers pge = 1<<13, // Page Global Enable bit in CR4 mca = 1<<14, // Machine check architecture cmov = 1<<15, // Conditional move and FCMOV instructions pat = 1<<16, // Page Attribute Table pse_36 = 1<<17, // 36-bit page size extension psn = 1<<18, // Processor Serial Number clfsh = 1<<19, // CLFLUSH instruction (SSE2) _resv2 = 1<<20, // (reserved) ds = 1<<21, // Debug store: save trace of executed jumps acpi = 1<<22, // Onboard thermal control MSRs for ACPI mmx = 1<<23, // MMX instructions fxsr = 1<<24, // FXSAVE, FXRESTOR instructions, CR4 bit 9 sse = 1<<25, // SSE instructions (a.k.a. Katmai New Instructions) sse2 = 1<<26, // SSE2 instructions ss = 1<<27, // CPU cache implements self-snoop htt = 1<<28, // Hyper-threading tm = 1<<29, // Thermal monitor automatically limits temperature ia64 = 1<<30, // IA64 processor emulating x86 pbe = 1<<31, // Pending Break Enable (PBE# pin) wakeup capability }; enum struct Ecx_1_Feature_Flags { sse3 = 1<<0, // Prescott New Instructions-SSE3 (PNI) pclmulqdq = 1<<1, // PCLMULQDQ dtes64 = 1<<2, // 64-bit debug store (edx bit 21) monitor = 1<<3, // MONITOR and MWAIT instructions (SSE3) ds_cpl = 1<<4, // CPL qualified debug store vmx = 1<<5, // Virtual Machine eXtensions smx = 1<<6, // Safer Mode Extensions (LaGrande) est = 1<<7, // Enhanced SpeedStep tm2 = 1<<8, // Thermal Monitor 2 ssse3 = 1<<9, // Supplemental SSE3 instructions cnxt_id = 1<<10, // L1 Context ID sdbg = 1<<11, // Silicon Debug interface fma = 1<<12, // Fused multiply-add (FMA3) cx16 = 1<<13, // CMPXCHG16B instruction xtpr = 1<<14, // Can disable sending task priority messages pdcm = 1<<15, // Perfmon & debug capability _resv1 = 1<<16, // (reserved) pcid = 1<<17, // Process context identifiers (CR4 bit 17) dca = 1<<18, // Direct cache access for DMA writes sse4_1 = 1<<19, // SSE4.1 instructions sse4_2 = 1<<20, // SSE4.2 instructions x2apic = 1<<21, // x2APIC movbe = 1<<22, // MOVBE instruction (big-endian) popcnt = 1<<23, // POPCNT instruction tsc_deadline = 1<<24, // APIC implements one-shot operation using a TSC deadline value aes = 1<<25, // AES instruction set xsave = 1<<26, // XSAVE, XRESTOR, XSETBV, XGETBV osxsave = 1<<27, // XSAVE enabled by OS avx = 1<<28, // Advanced Vector Extensions f16c = 1<<29, // F16C (half-precision) FP feature rdrnd = 1<<30, // RDRAND (on-chip random number generator) feature hypervisor = 1<<31, // Hypervisor present (always zero on physical CPUs) }; enum struct Ebx_7_Extended_Feature_Flags { fsgsbase = 1<<0, // Access to base of %fs and %gs _idk1 = 1<<1, // sgx = 1<<2, // Software Guard Extensions bmi1 = 1<<3, // Bit Manipulation Instruction Set 1 hle = 1<<4, // TSX Hardware Lock Elision avx2 = 1<<5, // Advanced Vector Extensions 2 _idk2 = 1<<6, // smep = 1<<7, // Supervisor Mode Execution Prevention bmi2 = 1<<8, // Bit Manipulation Instruction Set 2 erms = 1<<9, // Enhanced REP MOVSB/STOSB invpcid = 1<<10, // INVPCID instruction rtm = 1<<11, // TSX Restricted Transactional Memory pqm = 1<<12, // Platform Quality of Service Monitoring _idk3 = 1<<13, // mpx = 1<<14, // Intel MPX (Memory Protection Extensions) pqe = 1<<15, // Platform Quality of Service Enforcement avx512_f = 1<<16, // AVX-512 Foundation avx512_dq = 1<<17, // AVX-512 Doubleword and Quadword Instructions rdseed = 1<<18, // RDSEED instruction adx = 1<<19, // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) smap = 1<<20, // Supervisor Mode Access Prevention avx512_ifma = 1<<21, // AVX-512 Integer Fused Multiply-Add Instructions pcommit = 1<<22, // PCOMMIT instruction clflushopt = 1<<23, // CLFLUSHOPT instruction clwb = 1<<24, // CLWB instruction intel_pt = 1<<25, // Intel Processor Trace avx512_pf = 1<<26, // AVX-512 Prefetch Instructions avx512_er = 1<<27, // AVX-512 Exponential and Reciprocal Instructions avx512_cd = 1<<28, // AVX-512 Conflict Detection Instructions sha = 1<<29, // Intel SHA extensions avx512_bw = 1<<30, // AVX-512 Byte and Word Instructions avx512_vl = 1<<31, // AVX-512 Vector Length Extensions }; enum struct Ecx_7_Extended_Feature_Flags { prefetchwt1 = 1<<0, // PREFETCHWT1 instruction avx512_vbmi = 1<<1, // AVX-512 Vector Bit Manipulation Instructions umip = 1<<2, // User-mode Instruction Prevention pku = 1<<3, // Memory Protection Keys for User-mode pages ospke = 1<<4, // PKU enabled by OS waitpkg = 1<<5, // Timed pause and user-level monitor/wait avx512_vbmi2 = 1<<6, // AVX-512 Vector Bit Manipulation Instructions 2 cet_ss = 1<<7, // Control flow enforcement (CET) shadow stack gfni = 1<<8, // Galois Field instructions vaes = 1<<9, // Vector AES instruction set (VEX-256/EVEX) vpclmulqdq = 1<<10, // CLMUL instruction set (VEX-256/EVEX) avx512_vnni = 1<<11, // AVX-512 Vector Neural Network Instructions avx512_bitalg = 1<<12, // AVX-512 BITALG instructions _resv1 = 1<<13, // (reserved) avx512_vpopcntdq = 1<<14, // AVX-512 Vector Population Count Double and Quad-word _resv2 = 1<<15, // (reserved) intel_5lp = 1<<16, // 5-level paging mawau1 = 1<<17, // The value of userspace MPX Address-Width Adjust used ... mawau2 = 1<<18, // ... by the BNDLDX and BNDSTX Intel MPX instructions ... mawau3 = 1<<19, // ... in 64-bit mode mawau4 = 1<<20, // mawau5 = 1<<21, // rdpid = 1<<22, // Read Processor ID and IA32_TSC_AUX _resv3 = 1<<23, // (reserved) _resv4 = 1<<24, // (reserved) cldemote = 1<<25, // Cache line demote _resv5 = 1<<26, // (reserved) movdiri = 1<<27, // movdir64b = 1<<28, // enqcmd = 1<<29, // Enqueue Stores sgx_lc = 1<<30, // SGX Launch Configuration pks = 1<<31, // Protection keys for supervisor-mode pages }; enum struct Edx_7_Extended_Feature_Flags { _resv1 = 1<<0, // (reserved) _resv2 = 1<<1, // (reserved) avx512_4vnniw = 1<<2, // AVX-512 4-register Neural Network Instructions avx512_4fmaps = 1<<3, // AVX-512 4-register Multiply Accumulation Single precision fsrm = 1<<4, // Fast Short REP MOVSB _resv3 = 1<<5, // (reserved) _resv4 = 1<<6, // (reserved) _resv5 = 1<<7, // (reserved) avx512_vp2intersect = 1<<8, // AVX-512 VP2INTERSECT Doubleword and Quadword Instructions SRBDS_CTRL = 1<<9, // Special Register Buffer Data Sampling Mitigations md_clear = 1<<10, // VERW instruction clears CPU buffers _resv6 = 1<<11, // (reserved) _resv7 = 1<<12, // (reserved) tsx_force_abort = 1<<13, // serialize = 1<<14, // Serialize instruction execution hybrid = 1<<15, // TSXLDTRK = 1<<16, // TSX suspend load address tracking _resv8 = 1<<17, // (reserved) pconfig = 1<<18, // Platform configuration (Memory Encryption Technologies Instructions) lbr = 1<<19, // Architectural Last Branch Records cet_ibt = 1<<20, // Control flow enforcement (CET) indirect branch tracking _resv9 = 1<<21, // (reserved) amx_bf16 = 1<<22, // Tile computation on bfloat16 numbers _resv10 = 1<<23, // (reserved) amx_tile = 1<<24, // Tile architecture amx_int8 = 1<<25, // Tile computation on 8-bit integers spec_ctrl = 1<<26, // Speculation Control, part of Indirect Branch Control (IBC): // Indirect Branch Restricted Speculation (IBRS) and // Indirect Branch Prediction Barrier (IBPB) stibp = 1<<27, // Single Thread Indirect Branch Predictor, part of IBC l1d_flush = 1<<28, // IA32_FLUSH_CMD MSR ia32_arch_capabilities = 1<<29, // Speculative Side Channel Mitigations ia32_core_capabilities = 1<<30, // Support for a MSR listing model-specific core capabilities ssbd = 1<<31, // Speculative Store Bypass Disable, as mitigation for Speculative Store Bypass (IA32_SPEC_CTRL) }; // NOTE(Felix): Left out flags are duplicates from Edx_1_Feature_Flags enum struct Edx_81_Extended_Feature_Flags { syscall = 1<<11, // SYSCALL and SYSRET instructions mp = 1<<19, // Multiprocessor Capable nx = 1<<20, // NX (no-execute) bit mmxext = 1<<22, // Extended MMX fxsr_opt = 1<<25, // FXSAVE/FXRSTOR optimizations pdpe1gb = 1<<26, // Gibibyte pages rdtscp = 1<<27, // RDTSCP instruction l1d_flush = 1<<28, // IA32_FLUSH_CMD MSR lm = 1<<29, // Long mode _3dnowext = 1<<30, // Extended 3DNow! _3dnow = 1<<31, // 3DNow! }; enum struct Ecx_81_Extended_Feature_Flags { lahf_lm = 1<<0, // LAHF/SAHF in long mode cmp_legacy = 1<<1, // Hyperthreading not valid svm = 1<<2, // Secure Virtual Machine extapic = 1<<3, // Extended APIC space cr8_legacy = 1<<4, // CR8 in 32-bit mode abm = 1<<5, // Advanced bit manipulation (lzcnt and popcnt) sse4a = 1<<6, // SSE4a misalignsse = 1<<7, // Misaligned SSE mode _3dnowprefetch= 1<<8, // PREFETCH and PREFETCHW instructions osvw = 1<<9, // OS Visible Workaround ibs = 1<<10, // Instruction Based Sampling xop = 1<<11, // XOP instruction set skinit = 1<<12, // SKINIT/STGI instructions wdt = 1<<13, // Watchdog timer _resv1 = 1<<14, // (reserved) lwp = 1<<15, // Light Weight Profiling fma4 = 1<<16, // 4 operands fused multiply-add tce = 1<<17, // Translation Cache Extension _resv2 = 1<<18, // (reserved) nodeid_msr = 1<<19, // NodeID MSR _resv3 = 1<<20, // (reserved) tbm = 1<<21, // Trailing Bit Manipulation topoext = 1<<22, // opology Extensions perfctr_core = 1<<23, // Core performance counter extensions perfctr_nb = 1<<24, // NB performance counter extensions _resv4 = 1<<25, // (reserved) dbx = 1<<26, // Data breakpoint extensions perftsc = 1<<27, // Performance TSC pcx_l2i = 1<<28, // L2I perf counter extensions _resv5 = 1<<29, // (reserved) _resv6 = 1<<30, // (reserved) _resv7 = 1<<31, // (reserved) }; struct Cpu_Info { char vendor[0x20]; char brand[0x40]; bool is_intel; bool is_amd; int f_1_ECX; int f_1_EDX; int f_7_EBX; int f_7_ECX; int f_7_EDX; int f_81_ECX; int f_81_EDX; }; inline auto query_cpu_feature(Cpu_Info* info, Edx_1_Feature_Flags flag) -> bool { return info->f_1_EDX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Ecx_1_Feature_Flags flag) -> bool { return info->f_1_ECX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Ebx_7_Extended_Feature_Flags flag) -> bool { return info->f_7_EBX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Ecx_7_Extended_Feature_Flags flag) -> bool { return info->f_7_ECX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Edx_7_Extended_Feature_Flags flag) -> bool { return info->f_7_EDX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Edx_81_Extended_Feature_Flags flag) -> bool { return info->f_81_EDX & (int)flag; } inline auto query_cpu_feature(Cpu_Info* info, Ecx_81_Extended_Feature_Flags flag) -> bool { return info->f_81_ECX & (int)flag; } auto get_cpu_info(Cpu_Info* info) -> void { *info = {}; int nIds_ = 0; int nExIds_ = 0; int register_sets[3][4]; info->is_intel = false; info->is_amd = false; // Calling __cpuid with 0x0 as the function_id argument // gets the number of the highest valid function ID. platform_independent_cpuid(0, register_sets[0]); nIds_ = register_sets[0][0]; // Capture vendor string memset(info->vendor, 0, sizeof(info->vendor)); memcpy(info->vendor + 0, register_sets[0]+1, sizeof(int)); memcpy(info->vendor + 4, register_sets[0]+3, sizeof(int)); memcpy(info->vendor + 8, register_sets[0]+2, sizeof(int)); if (strcmp(info->vendor, "GenuineIntel") == 0) { info->is_intel = true; } else if (strcmp(info->vendor, "AuthenticAMD") == 0) { info->is_amd = true; } if (nIds_ >= 1) { platform_independent_cpuidex(1, 0, register_sets[0]); info->f_1_ECX = register_sets[0][2]; info->f_1_EDX = register_sets[0][3]; if (nIds_ >= 7) { platform_independent_cpuidex(7, 0, register_sets[1]); info->f_7_EBX = register_sets[1][1]; info->f_7_ECX = register_sets[1][2]; info->f_7_EDX = register_sets[1][3]; } } // Calling __cpuid with 0x80000000 as the function_id argument // gets the number of the highest valid extended ID. platform_independent_cpuid(0x80000000, register_sets[2]); nExIds_ = register_sets[2][0]; memset(info->brand, 0, sizeof(info->brand)); // load bitset with flags for function 0x80000001 if (nExIds_ >= 0x80000001) { platform_independent_cpuidex(0x80000001, 0, register_sets[2]); info->f_81_ECX = register_sets[2][2]; info->f_81_EDX = register_sets[2][3]; // Interpret CPU brand string if reported if (nExIds_ >= 0x80000004) { platform_independent_cpuidex(0x80000002, 0, register_sets[0]); platform_independent_cpuidex(0x80000003, 0, register_sets[1]); platform_independent_cpuidex(0x80000004, 0, register_sets[2]); memcpy(info->brand + 0, register_sets[0], sizeof(register_sets[0])); memcpy(info->brand + 16, register_sets[1], sizeof(register_sets[1])); memcpy(info->brand + 32, register_sets[2], sizeof(register_sets[2])); } } }