1 /** 2 * x86 CPU Identification tool 3 * 4 * This was initially used internally, so it's pretty unfriendly. 5 * 6 * The best way to use this module would be: 7 * --- 8 * CPUINFO info; // Important to let the struct init to zero! 9 * getLeaves(info); // Get maximum CPUID leaves (mandatory step before info) 10 * getVendor(info); // Get vendor string (mandatory step before info) 11 * getInfo(info); // Fill CPUINFO structure (optional) 12 * --- 13 * 14 * Then checking the corresponding field: 15 * --- 16 * if (info.ext.amx_xfd) { 17 * // Intel AMX is available 18 * } else { 19 * // Feature unavailable 20 * } 21 * --- 22 * 23 * See the CPUINFO structure for available fields. 24 * 25 * For more information, it's encouraged to consult the technical manual. 26 * 27 * Authors: dd86k (dd@dax.moe) 28 * Copyright: © 2016-2021 dd86k 29 * License: MIT 30 */ 31 module ddcpuid; 32 33 //TODO: Consider moving all lone instructions into extras (again?) 34 // And probs have an argument to show them (to ouput) 35 //TODO: reset(CPUINFO) 36 // Doesn't touch leaves and vendor strings 37 //TODO: getAll(CPUINFO, bool, bool, bool...) 38 // Auto-clear, fill by parameter 39 40 // NOTE: Please no naked assembler. 41 // I'd rather deal with a bit of prolog and epilog than slamming 42 // my head into my desk violently trying to match every operating 43 // system ABI, compiler versions, and major compilers. 44 // Besides, final compiled binary is plenty fine. 45 // NOTE: GAS syntax reminder 46 // asm { "asm;\n\t" : "constraint" output : "constraint" input : clobbers } 47 // NOTE: bhyve doesn't not emit cpuid bits past 0x40000000, so not supported 48 49 @system: 50 extern (C): 51 52 version (X86) 53 enum DDCPUID_PLATFORM = "x86"; /// Target platform 54 else version (X86_64) 55 enum DDCPUID_PLATFORM = "amd64"; /// Target platform 56 else static assert(0, "Unsupported platform"); 57 58 version (DigitalMars) { 59 version = DMD; 60 } else version (GNU) { 61 version = GDC; 62 } else version (LDC) { 63 64 } else static assert(0, "Unsupported compiler"); 65 66 enum DDCPUID_VERSION = "0.18.1"; /// Library version 67 private enum CACHE_LEVELS = 6; /// For buffer 68 private enum CACHE_MAX_LEVEL = CACHE_LEVELS - 1; 69 private enum VENDOR_OFFSET = CPUINFO.vendor.offsetof; 70 private enum BRAND_OFFSET = CPUINFO.brand.offsetof; 71 private enum VIRTVENDOR_OFFSET = CPUINFO.virt.offsetof + CPUINFO.virt.vendor.offsetof; 72 73 version (PrintInfo) { 74 pragma(msg, "VENDOR_OFFSET\t", VENDOR_OFFSET); 75 pragma(msg, "BRAND_OFFSET\t", BRAND_OFFSET); 76 pragma(msg, "VIRTVENDOR_OFFSET\t", VIRTVENDOR_OFFSET); 77 pragma(msg, "CPUINFO.sizeof\t", CPUINFO.sizeof); 78 pragma(msg, "CACHE.sizeof\t", CACHEINFO.sizeof); 79 } 80 81 /// Make a bit mask of one bit at n position 82 private 83 template BIT(int n) if (n <= 31) { enum uint BIT = 1 << n; } 84 85 /// Vendor ID template 86 // Little-endian only, unless x86 gets any crazier 87 private 88 template ID(char[4] c) { 89 enum uint ID = c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24; 90 } 91 92 /// Vendor ID. 93 /// 94 /// The CPUINFO.vendor_id field is set according to the Vendor String. 95 /// They are validated in the getVendor function, so they are safe to use. 96 enum Vendor { 97 Other = 0, 98 Intel = ID!("Genu"), /// `"GenuineIntel"`: Intel 99 AMD = ID!("Auth"), /// `"AuthenticAMD"`: AMD 100 VIA = ID!("VIA "), /// `"VIA VIA VIA "`: VIA 101 } 102 103 /// Virtual Vendor ID, used as the interface type. 104 /// 105 /// The CPUINFO.virt.vendor_id field is set according to the Vendor String. 106 /// They are validated in the getVendor function, so they are safe to use. 107 /// The VBoxHyperV ID will be adjusted for HyperV since it's the same interface, 108 /// but simply a different implementation. 109 enum VirtVendor { 110 Other = 0, 111 KVM = ID!("KVMK"), /// `"KVMKVMKVM\0\0\0"`: KVM 112 HyperV = ID!("Micr"), /// `"Microsoft Hv"`: Hyper-V interface 113 VBoxHyperV = ID!("VBox"), /// `"VBoxVBoxVBox"`: VirtualBox's Hyper-V interface 114 VBoxMin = 0, /// Unset: VirtualBox minimal interface 115 } 116 117 private 118 union __01ebx_t { // 01h.EBX internal 119 uint all; 120 struct { 121 ubyte brand_index; /// Processor brand index. No longer used. 122 ubyte clflush_linesize; /// Linesize of CLFLUSH in bytes 123 ubyte max_apic_id; /// Maximum APIC ID 124 ubyte apic_id; /// Initial APIC ID (running core where CPUID was called) 125 } 126 } 127 128 /// Registers structure used with the asmcpuid function. 129 struct REGISTERS { uint eax, ebx, ecx, edx; } 130 131 /// CPU cache entry 132 struct CACHEINFO { align(1): 133 union { 134 package uint __bundle1; 135 struct { 136 ubyte linesize; /// Size of the line in bytes 137 ubyte partitions; /// Number of partitions 138 ubyte ways; /// Number of ways per line 139 package ubyte _amdsize; /// (AMD, legacy) Size in KiB 140 } 141 } 142 /// Cache Size in kilobytes. 143 // (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1) 144 // (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1) 145 uint size; 146 /// Number of cache sets. 147 ushort sets; 148 /// Number of CPU cores sharing this cache. 149 ushort sharedCores; 150 /// Cache feature, bit flags. 151 /// - Bit 0: Self Initializing cache 152 /// - Bit 1: Fully Associative cache 153 /// - Bit 2: No Write-Back Invalidation (toggle) 154 /// - Bit 3: Cache Inclusiveness (toggle) 155 /// - Bit 4: Complex Cache Indexing (toggle) 156 ushort feat; 157 ubyte level; /// Cache level: L1, L2, etc. 158 char type = 0; /// Type entry character: 'D'=Data, 'I'=Instructions, 'U'=Unified 159 } 160 161 /// CPU information structure 162 struct CPUINFO { align(1): 163 uint max_leaf; /// Highest cpuid leaf 164 uint max_virt_leaf; /// Highest cpuid virtualization leaf 165 uint max_ext_leaf; /// Highest cpuid extended leaf 166 167 // Vendor strings 168 169 union { 170 package uint[3] vendor32; /// Vendor 32-bit parts 171 char[12] vendor; /// Vendor String 172 } 173 union { 174 package uint[12] brand32; // For init 175 char[48] brand; /// Processor Brand String 176 } 177 union { 178 package uint vendor_id32; 179 Vendor vendor_id; /// Validated vendor ID 180 } 181 ubyte brand_index; /// Brand string index (not used) 182 183 // Core 184 185 /// Contains the information on the number of cores. 186 struct Cores { 187 //TODO: Physical cores 188 // ushort physical; /// Physical cores in this processor 189 ushort logical; /// Logical cores in this processor 190 } 191 align(2) Cores cores; /// Processor package cores 192 193 // Identifier 194 195 ubyte family; /// Effective family identifier 196 ubyte family_base; /// Base family identifier 197 ubyte family_ext; /// Extended family identifier 198 ubyte model; /// Effective model identifier 199 ubyte model_base; /// Base model identifier 200 ubyte model_ext; /// Extended model identifier 201 ubyte stepping; /// Stepping revision 202 ubyte type; /// Processor type number 203 const(char) *type_string; /// Processor type string. 204 205 //TODO: Consider bit flags for some families 206 // Like MMX, SSE, AVX, AMX, you get the gist 207 /// Contains processor extensions. 208 /// Extensions contain a variety of instructions to aid particular 209 /// tasks. 210 struct Extensions { 211 bool fpu; /// On-Chip x87 FPU 212 bool f16c; /// Float16 Conversions 213 bool mmx; /// MMX 214 bool mmxext; /// MMX Extended 215 bool _3dnow; /// 3DNow! 216 bool _3dnowext; /// 3DNow! Extended 217 bool aes_ni; /// Advanced Encryption Standard New Instructions 218 bool sha; /// SHA-1 219 bool fma3; /// Fused Multiply-Add 220 bool fma4; /// FMA4 221 bool bmi1; /// BMI1 222 bool bmi2; /// BMI2 223 bool x86_64; /// 64-bit mode (Long mode) 224 bool lahf64; /// LAHF+SAHF in 64-bit mode 225 bool waitpkg; /// User Level Monitor Wait (UMWAIT) 226 bool xop; /// AMD eXtended OPerations 227 bool tbm; /// Trailing Bit Manipulation 228 bool adx; /// Multi-precision Add-Carry (ADCX+ADOX) 229 230 // SSE 231 bool sse; /// Streaming SIMD Extensions 232 bool sse2; /// SSE2 233 bool sse3; /// SSE3 234 bool ssse3; /// SSSE3 235 bool sse41; /// SSE4.1 236 bool sse42; /// SSE4.2 237 bool sse4a; /// SSE4a 238 239 // AVX 240 bool avx; /// Advanced Vector eXtension 241 bool avx2; /// AVX-2 242 bool avx512f; /// AVX-512 243 bool avx512er; /// AVX-512-ER 244 bool avx512pf; /// AVX-512-PF 245 bool avx512cd; /// AVX-512-CD 246 bool avx512dq; /// AVX-512-DQ 247 bool avx512bw; /// AVX-512-BW 248 bool avx512vl; /// AVX-512-VL 249 bool avx512_ifma; /// AVX-512-IFMA 250 bool avx512_vbmi; /// AVX-512-VBMI 251 bool avx512_vbmi2; /// AVX-512-VBMI2 252 bool avx512_gfni; /// AVX-512-GFNI 253 bool avx512_vaes; /// AVX-512-VAES 254 bool avx512_vnni; /// AVX-512-VNNI 255 bool avx512_bitalg; /// AVX-512-BITALG 256 bool avx512_vpopcntdq; /// AVX-512-VPOPCNTDQ 257 bool avx512_4vnniw; /// AVX-512-4VNNIW 258 bool avx512_4fmaps; /// AVX-512-4FMAPS 259 bool avx512_bf16; /// AVX-512-BF16 260 bool avx512_vp2intersect; /// AVX-512-VP2INTERSECT 261 262 // AMX 263 bool amx; /// Advanced Matrix eXtension 264 bool amx_bf16; /// AMX-BF16 265 bool amx_int8; /// AMX-INT8 266 bool amx_xtilecfg; /// AMX-XTILECFG 267 bool amx_xtiledata; /// AMX-XTILEDATA 268 bool amx_xfd; /// AMX-XFD 269 } 270 align(2) Extensions ext; /// Extensions 271 272 /// Additional instructions. Often not part of extensions. 273 struct Extras { 274 bool pclmulqdq; /// PCLMULQDQ instruction 275 bool monitor; /// MONITOR and MWAIT instructions 276 ushort mwait_min; /// (With MONITOR+MWAIT) MWAIT minimum size in bytes 277 ushort mwait_max; /// (With MONITOR+MWAIT) MWAIT maximum size in bytes 278 bool cmpxchg8b; /// CMPXCHG8B 279 bool cmpxchg16b; /// CMPXCHG16B instruction 280 bool movbe; /// MOVBE instruction 281 bool rdrand; /// RDRAND instruction 282 bool rdseed; /// RDSEED instruction 283 bool rdmsr; /// RDMSR instruction 284 bool sysenter; /// SYSENTER and SYSEXIT instructions 285 bool rdtsc; /// RDTSC instruction 286 bool rdtsc_deadline; /// (With RDTSC) IA32_TSC_DEADLINE MSR 287 bool rdtsc_invariant; /// (With RDTSC) Timestamp counter invariant of C/P/T-state 288 bool rdtscp; /// RDTSCP instruction 289 bool rdpid; /// RDPID instruction 290 bool cmov; /// CMOVcc instruction 291 bool lzcnt; /// LZCNT instruction 292 bool popcnt; /// POPCNT instruction 293 bool xsave; /// XSAVE and XRSTOR instructions 294 bool osxsave; /// OSXSAVE and XGETBV instructions 295 bool fxsr; /// FXSAVE and FXRSTOR instructions 296 bool pconfig; /// PCONFIG instruction 297 bool cldemote; /// CLDEMOTE instruction 298 bool movdiri; /// MOVDIRI instruction 299 bool movdir64b; /// MOVDIR64B instruction 300 bool enqcmd; /// ENQCMD instruction 301 bool syscall; /// SYSCALL and SYSRET instructions 302 bool monitorx; /// MONITORX and MWAITX instructions 303 bool skinit; /// SKINIT instruction 304 bool serialize; /// SERIALIZE instruction 305 } 306 align(2) Extras extras; /// Additional instructions 307 308 /// Processor technologies. 309 struct Technologies { 310 bool eist; /// Intel SpeedStep/AMD PowerNow/AMD Cool'n'Quiet 311 bool turboboost; /// Intel TurboBoost/AMD CorePerformanceBoost 312 bool turboboost30; /// Intel TurboBoost 3.0 313 bool smx; /// Intel TXT 314 bool sgx; /// Intel SGX 315 bool htt; /// (HTT) HyperThreading Technology 316 } 317 align(2) Technologies tech; /// Processor technologies 318 319 /// Cache information. 320 struct CacheInfo { 321 uint levels; 322 CACHEINFO[CACHE_LEVELS] level; 323 bool clflush; /// CLFLUSH instruction 324 ubyte clflush_linesize; /// Linesize of CLFLUSH in bytes 325 bool clflushopt; /// CLFLUSH instruction 326 bool cnxt_id; /// L1 Context ID 327 bool ss; /// SelfSnoop 328 bool prefetchw; /// PREFETCHW instruction 329 bool invpcid; /// INVPCID instruction 330 bool wbnoinvd; /// WBNOINVD instruction 331 } 332 align(2) CacheInfo cache; /// Cache information 333 334 /// ACPI information. 335 struct AcpiInfo { 336 bool available; /// ACPI 337 bool apic; /// APIC 338 bool x2apic; /// x2APIC 339 bool arat; /// Always-Running-APIC-Timer 340 bool tm; /// Thermal Monitor 341 bool tm2; /// Thermal Monitor 2 342 ubyte max_apic_id; /// Maximum APIC ID 343 ubyte apic_id; /// Initial APIC ID (running core where CPUID was called) 344 } 345 align(2) AcpiInfo acpi; /// ACPI features 346 347 /// Virtualization features. If a paravirtual interface is available, 348 /// its information will be found here. 349 struct Virtualization { 350 bool available; /// Intel VT-x/AMD-V 351 ubyte version_; /// (AMD) Virtualization platform version 352 bool vme; /// Enhanced vm8086 353 bool apivc; /// (AMD) APICv. Intel's is available via a MSR. 354 union { 355 package uint[3] vendor32; 356 char[12] vendor; /// Paravirtualization interface vendor string 357 } 358 union { 359 package uint vendor_id32; 360 VirtVendor vendor_id; /// Effective paravirtualization vendor id 361 } 362 363 //TODO: Consider bit flags for paravirtualization flags 364 365 // VBox 366 367 uint vbox_tsc_freq_khz; /// (VBox) Timestamp counter frequency in KHz 368 uint vbox_apic_freq_khz; /// (VBox) Paravirtualization API KHz frequency 369 370 // KVM 371 372 bool kvm_feature_clocksource; /// (KVM) kvmclock interface 373 bool kvm_feature_nop_io_delay; /// (KVM) No delays required on I/O operations 374 bool kvm_feature_mmu_op; /// (KVM) Deprecated 375 bool kvm_feature_clocksource2; /// (KVM) Remapped kvmclock interface 376 bool kvm_feature_async_pf; /// (KVM) Asynchronous Page Fault 377 bool kvm_feature_steal_time; /// (KVM) Steal time 378 bool kvm_feature_pv_eoi; /// (KVM) Paravirtualized End Of the Interrupt handler 379 bool kvm_feature_pv_unhault; /// (KVM) Paravirtualized spinlock 380 bool kvm_feature_pv_tlb_flush; /// (KVM) Paravirtualized TLB flush 381 bool kvm_feature_async_pf_vmexit; /// (KVM) Asynchronous Page Fault at VM exit 382 bool kvm_feature_pv_send_ipi; /// (KVM) Paravirtualized SEBD inter-processor-interrupt 383 bool kvm_feature_pv_poll_control; /// (KVM) Host-side polling on HLT 384 bool kvm_feature_pv_sched_yield; /// (KVM) paravirtualized scheduler yield 385 bool kvm_feature_clocsource_stable_bit; /// (KVM) kvmclock warning 386 bool kvm_hint_realtime; /// (KVM) vCPUs are never preempted for an unlimited amount of time 387 388 // Hyper-V 389 390 ushort hv_guest_vendor_id; /// (Hyper-V) Paravirtualization Guest Vendor ID 391 ushort hv_guest_build; /// (Hyper-V) Paravirtualization Guest Build number 392 ubyte hv_guest_os; /// (Hyper-V) Paravirtualization Guest OS ID 393 ubyte hv_guest_major; /// (Hyper-V) Paravirtualization Guest OS Major version 394 ubyte hv_guest_minor; /// (Hyper-V) Paravirtualization Guest OS Minor version 395 ubyte hv_guest_service; /// (Hyper-V) Paravirtualization Guest Service ID 396 bool hv_guest_opensource; /// (Hyper-V) Paravirtualization Guest additions open-source 397 bool hv_base_feat_vp_runtime_msr; /// (Hyper-V) Virtual processor runtime MSR 398 bool hv_base_feat_part_time_ref_count_msr; /// (Hyper-V) Partition reference counter MSR 399 bool hv_base_feat_basic_synic_msrs; /// (Hyper-V) Basic Synthetic Interrupt Controller MSRs 400 bool hv_base_feat_stimer_msrs; /// (Hyper-V) Synthetic Timer MSRs 401 bool hv_base_feat_apic_access_msrs; /// (Hyper-V) APIC access MSRs (EOI, ICR, TPR) 402 bool hv_base_feat_hypercall_msrs; /// (Hyper-V) Hypercalls API MSRs 403 bool hv_base_feat_vp_id_msr; /// (Hyper-V) vCPU index MSR 404 bool hv_base_feat_virt_sys_reset_msr; /// (Hyper-V) Virtual system reset MSR 405 bool hv_base_feat_stat_pages_msr; /// (Hyper-V) Statistic pages MSRs 406 bool hv_base_feat_part_ref_tsc_msr; /// (Hyper-V) Partition reference timestamp counter MSR 407 bool hv_base_feat_guest_idle_state_msr; /// (Hyper-V) Virtual guest idle state MSR 408 bool hv_base_feat_timer_freq_msrs; /// (Hyper-V) Timer frequency MSRs (TSC and APIC) 409 bool hv_base_feat_debug_msrs; /// (Hyper-V) Debug MSRs 410 bool hv_part_flags_create_part; /// (Hyper-V) Partitions can be created 411 bool hv_part_flags_access_part_id; /// (Hyper-V) Partitions IDs can be accessed 412 bool hv_part_flags_access_memory_pool; /// (Hyper-V) Memory pool can be accessed 413 bool hv_part_flags_adjust_msg_buffers; /// (Hyper-V) Possible to adjust message buffers 414 bool hv_part_flags_post_msgs; /// (Hyper-V) Possible to send messages 415 bool hv_part_flags_signal_events; /// (Hyper-V) Possible to signal events 416 bool hv_part_flags_create_port; /// (Hyper-V) Possible to create ports 417 bool hv_part_flags_connect_port; /// (Hyper-V) Possible to connect to ports 418 bool hv_part_flags_access_stats; /// (Hyper-V) Can access statistics 419 bool hv_part_flags_debugging; /// (Hyper-V) Debugging features available 420 bool hv_part_flags_cpu_mgmt; /// (Hyper-V) Processor management available 421 bool hv_part_flags_cpu_profiler; /// (Hyper-V) Processor profiler available 422 bool hv_part_flags_expanded_stack_walk; /// (Hyper-V) Extended stack walking available 423 bool hv_part_flags_access_vsm; /// (Hyper-V) Virtual system monitor available 424 bool hv_part_flags_access_vp_regs; /// (Hyper-V) Virtual private registers available 425 bool hv_part_flags_extended_hypercalls; /// (Hyper-V) Extended hypercalls API available 426 bool hv_part_flags_start_vp; /// (Hyper-V) Virtual processor has started 427 bool hv_pm_max_cpu_power_state_c0; /// (Hyper-V) Processor C0 is maximum state 428 bool hv_pm_max_cpu_power_state_c1; /// (Hyper-V) Processor C1 is maximum state 429 bool hv_pm_max_cpu_power_state_c2; /// (Hyper-V) Processor C2 is maximum state 430 bool hv_pm_max_cpu_power_state_c3; /// (Hyper-V) Processor C3 is maximum state 431 bool hv_pm_hpet_reqd_for_c3; /// (Hyper-V) High-precision event timer required for C3 state 432 bool hv_misc_feat_mwait; /// (Hyper-V) MWAIT instruction available for guest 433 bool hv_misc_feat_guest_debugging; /// (Hyper-V) Guest supports debugging 434 bool hv_misc_feat_perf_mon; /// (Hyper-V) Performance monitor support available 435 bool hv_misc_feat_pcpu_dyn_part_event; /// (Hyper-V) Physicap CPU dynamic partitioning event available 436 bool hv_misc_feat_xmm_hypercall_input; /// (Hyper-V) Hypercalls via XMM registers available 437 bool hv_misc_feat_guest_idle_state; /// (Hyper-V) Virtual guest supports idle state 438 bool hv_misc_feat_hypervisor_sleep_state; /// (Hyper-V) Hypervisor supports sleep 439 bool hv_misc_feat_query_numa_distance; /// (Hyper-V) NUMA distance query available 440 bool hv_misc_feat_timer_freq; /// (Hyper-V) Determining timer frequencies available 441 bool hv_misc_feat_inject_synmc_xcpt; /// (Hyper-V) Support for injecting synthetic machine checks 442 bool hv_misc_feat_guest_crash_msrs; /// (Hyper-V) Guest crash MSR available 443 bool hv_misc_feat_debug_msrs; /// (Hyper-V) Debug MSR available 444 bool hv_misc_feat_npiep1; /// (Hyper-V) Documentation unavailable 445 bool hv_misc_feat_disable_hypervisor; /// (Hyper-V) Hypervisor can be disabled 446 bool hv_misc_feat_ext_gva_range_for_flush_va_list; /// (Hyper-V) Extended guest virtual address (GVA) ranges for FlushVirtualAddressList available 447 bool hv_misc_feat_hypercall_output_xmm; /// (Hyper-V) Returning hypercall output via XMM registers available 448 bool hv_misc_feat_sint_polling_mode; /// (Hyper-V) Synthetic interrupt source polling mode available 449 bool hv_misc_feat_hypercall_msr_lock; /// (Hyper-V) Hypercall MISR lock feature available 450 bool hv_misc_feat_use_direct_synth_msrs; /// (Hyper-V) Possible to directly use synthetic MSRs 451 bool hv_hint_hypercall_for_process_switch; /// (Hyper-V) Guest should use the Hypercall API for address space switches rather than MOV CR3 452 bool hv_hint_hypercall_for_tlb_flush; /// (Hyper-V) Guest should use the Hypercall API for local TLB flushes rather than INVLPG/MOV CR3 453 bool hv_hint_hypercall_for_tlb_shootdown; /// (Hyper-V) Guest should use the Hypercall API for inter-CPU TLB flushes rather than inter-processor-interrupts (IPI) 454 bool hv_hint_msr_for_apic_access; /// (Hyper-V) Guest should use the MSRs for APIC access (EOI, ICR, TPR) rather than memory-mapped input/output (MMIO) 455 bool hv_hint_msr_for_sys_reset; /// (Hyper-V) Guest should use the hypervisor-provided MSR for a system reset instead of traditional methods 456 bool hv_hint_relax_time_checks; /// (Hyper-V) Guest should relax timer-related checks (watchdogs/deadman timeouts) that rely on timely deliver of external interrupts 457 bool hv_hint_dma_remapping; /// (Hyper-V) Guest should use the direct memory access (DMA) remapping 458 bool hv_hint_interrupt_remapping; /// (Hyper-V) Guest should use the interrupt remapping 459 bool hv_hint_x2apic_msrs; /// (Hyper-V) Guest should use the X2APIC MSRs rather than memory mapped input/output (MMIO) 460 bool hv_hint_deprecate_auto_eoi; /// (Hyper-V) Guest should deprecate Auto EOI (End Of Interrupt) features 461 bool hv_hint_synth_cluster_ipi_hypercall; /// (Hyper-V) Guest should use the SyntheticClusterIpi Hypercall 462 bool hv_hint_ex_proc_masks_interface; /// (Hyper-V) Guest should use the newer ExProcessMasks interface over ProcessMasks 463 bool hv_hint_nested_hyperv; /// (Hyper-V) Hyper-V instance is nested within a Hyper-V partition 464 bool hv_hint_int_for_mbec_syscalls; /// (Hyper-V) Guest should use the INT instruction for Mode Based Execution Control (MBEC) system calls 465 bool hv_hint_nested_enlightened_vmcs_interface; /// (Hyper-V) Guest should use enlightened Virtual Machine Control Structure (VMCS) interfaces and nested enlightenment 466 bool hv_host_feat_avic; /// (Hyper-V) Hypervisor is using the Advanced Virtual Interrupt Controller (AVIC) overlay 467 bool hv_host_feat_msr_bitmap; /// (Hyper-V) Hypervisor is using MSR bitmaps 468 bool hv_host_feat_perf_counter; /// (Hyper-V) Hypervisor supports the architectural performance counter 469 bool hv_host_feat_nested_paging; /// (Hyper-V) Hypervisor is using nested paging 470 bool hv_host_feat_dma_remapping; /// (Hyper-V) Hypervisor is using direct memory access (DMA) remapping 471 bool hv_host_feat_interrupt_remapping; /// (Hyper-V) Hypervisor is using interrupt remapping 472 bool hv_host_feat_mem_patrol_scrubber; /// (Hyper-V) Hypervisor's memory patrol scrubber is present 473 bool hv_host_feat_dma_prot_in_use; /// (Hyper-V) Hypervisor is using direct memory access (DMA) protection 474 bool hv_host_feat_hpet_requested; /// (Hyper-V) Hypervisor requires a High Precision Event Timer (HPET) 475 bool hv_host_feat_stimer_volatile; /// (Hyper-V) Hypervisor's synthetic timers are volatile 476 } 477 align(2) Virtualization virt; /// Virtualization features 478 479 /// Memory features. 480 struct Memory { 481 bool pae; /// Physical Address Extension 482 bool pse; /// Page Size Extension 483 bool pse_36; /// 36-bit PSE 484 bool page1gb; /// 1GiB pages in 4-level paging and higher 485 bool mtrr; /// Memory Type Range Registers 486 bool pat; /// Page Attribute Table 487 bool pge; /// Page Global Bit 488 bool dca; /// Direct Cache Access 489 bool nx; /// Intel XD (No eXecute bit) 490 union { 491 uint tsx; /// Intel TSX. If set, has one of HLE, RTM, or TSXLDTRK. 492 struct { 493 bool hle; /// (TSX) Hardware Lock Elision 494 bool rtm; /// (TSX) Restricted Transactional Memory 495 bool tsxldtrk; /// (TSX) Suspend Load Address Tracking 496 } 497 } 498 bool smep; /// Supervisor Mode Execution Protection 499 bool smap; /// Supervisor Mode Access Protection 500 bool pku; /// Protection Key Units 501 bool _5pl; /// 5-level paging 502 bool fsrepmov; /// Fast Short REP MOVSB optimization 503 bool lam; /// Linear Address Masking 504 union { 505 package ushort b_8000_0008_ax; 506 struct { 507 ubyte phys_bits; /// Memory physical bits 508 ubyte line_bits; /// Memory linear bits 509 } 510 } 511 } 512 align (2) Memory mem; /// Memory features 513 514 /// Debugging features. 515 struct Debugging { 516 bool mca; /// Machine Check Architecture 517 bool mce; /// Machine Check Exception 518 bool de; /// Degging Extensions 519 bool ds; /// Debug Store 520 bool ds_cpl; /// Debug Store - Curernt Privilege Level 521 bool dtes64; /// 64-bit Debug Store area 522 bool pdcm; /// Perfmon And Debug Capability 523 bool sdbg; /// Silicon Debug 524 bool pbe; /// Pending Break Enable 525 } 526 align(2) Debugging dbg; /// Debugging feature 527 528 /// Security features and mitigations. 529 struct Security { 530 bool ia32_arch_capabilities; /// IA32_ARCH_CAPABILITIES MSR 531 // NOTE: IA32_CORE_CAPABILITIES is currently empty 532 bool ibpb; /// Indirect Branch Predictor Barrier 533 bool ibrs; /// Indirect Branch Restricted Speculation 534 bool ibrs_on; /// IBRS always enabled 535 bool ibrs_pref; /// IBRS preferred 536 bool stibp; /// Single Thread Indirect Branch Predictors 537 bool stibp_on; /// STIBP always enabled 538 bool ssbd; /// Speculative Store Bypass Disable 539 bool l1d_flush; /// L1D Cache Flush 540 bool md_clear; /// MDS mitigation 541 bool cet_ibt; /// (Control-flow Enforcement Technology) Indirect Branch Tracking 542 bool cet_ss; /// (Control-flow Enforcement Technology) Shadow Stack 543 } 544 align(2) Security sec; /// Security features 545 546 /// Miscellaneous features. 547 struct Miscellaneous { 548 bool psn; /// Processor Serial Number (Pentium III only) 549 bool pcid; /// PCID 550 bool xtpr; /// xTPR 551 bool fsgsbase; /// FS and GS register base 552 bool uintr; /// User Interrupts 553 } 554 align(2) Miscellaneous misc; /// Miscellaneous features 555 } 556 557 // EAX[4:0], 0-31, but there aren't that many 558 // So we limit it to 0-7 559 private 560 enum CACHE_MASK = 7; // Max 31 561 private 562 immutable const(char)* CACHE_TYPE = "?DIU????"; 563 564 private 565 immutable const(char)*[] PROCESSOR_TYPE = [ "Original", "OverDrive", "Dual", "Reserved" ]; 566 567 /// Query processor with CPUID. 568 /// Params: 569 /// regs = REGISTERS structure 570 /// level = Leaf (EAX) 571 /// sublevel = Sub-leaf (ECX) 572 pragma(inline, false) 573 void asmcpuid(ref REGISTERS regs, uint level, uint sublevel = 0) { 574 version (DMD) { 575 version (X86) asm { 576 mov EDI, regs; 577 mov EAX, level; 578 mov ECX, sublevel; 579 cpuid; 580 mov [EDI + regs.eax.offsetof], EAX; 581 mov [EDI + regs.ebx.offsetof], EBX; 582 mov [EDI + regs.ecx.offsetof], ECX; 583 mov [EDI + regs.edx.offsetof], EDX; 584 } else version (X86_64) asm { 585 mov RDI, regs; 586 mov EAX, level; 587 mov ECX, sublevel; 588 cpuid; 589 mov [RDI + regs.eax.offsetof], EAX; 590 mov [RDI + regs.ebx.offsetof], EBX; 591 mov [RDI + regs.ecx.offsetof], ECX; 592 mov [RDI + regs.edx.offsetof], EDX; 593 } 594 } else version (GDC) { 595 asm { 596 "cpuid" 597 : "=a" (regs.eax), "=b" (regs.ebx), "=c" (regs.ecx), "=d" (regs.edx) 598 : "a" (level), "c" (sublevel); 599 } 600 } else version (LDC) { 601 version (X86) asm { 602 lea EDI, regs; 603 mov EAX, level; 604 mov ECX, sublevel; 605 cpuid; 606 mov [EDI + regs.eax.offsetof], EAX; 607 mov [EDI + regs.ebx.offsetof], EBX; 608 mov [EDI + regs.ecx.offsetof], ECX; 609 mov [EDI + regs.edx.offsetof], EDX; 610 } else version (X86_64) asm { 611 lea RDI, regs; 612 mov EAX, level; 613 mov ECX, sublevel; 614 cpuid; 615 mov [RDI + regs.eax.offsetof], EAX; 616 mov [RDI + regs.ebx.offsetof], EBX; 617 mov [RDI + regs.ecx.offsetof], ECX; 618 mov [RDI + regs.edx.offsetof], EDX; 619 } 620 } 621 } 622 623 /// Get CPU leaf levels. 624 /// Params: info = CPUINFO structure 625 pragma(inline, false) 626 void getLeaves(ref CPUINFO info) { 627 version (DMD) { 628 version (X86) asm { 629 mov EDI, info; 630 mov EAX, 0; 631 cpuid; 632 mov [EDI + info.max_leaf.offsetof], EAX; 633 mov EAX, 0x4000_0000; 634 cpuid; 635 mov [EDI + info.max_virt_leaf.offsetof], EAX; 636 mov EAX, 0x8000_0000; 637 cpuid; 638 mov [EDI + info.max_ext_leaf.offsetof], EAX; 639 } else version (X86_64) asm { 640 mov RDI, info; 641 mov EAX, 0; 642 cpuid; 643 mov [RDI + info.max_leaf.offsetof], EAX; 644 mov EAX, 0x4000_0000; 645 cpuid; 646 mov [RDI + info.max_virt_leaf.offsetof], EAX; 647 mov EAX, 0x8000_0000; 648 cpuid; 649 mov [RDI + info.max_ext_leaf.offsetof], EAX; 650 } 651 } else version (GDC) { 652 asm { 653 "cpuid" 654 : "=a" (info.max_leaf) 655 : "a" (0); 656 } 657 asm { 658 "cpuid" 659 : "=a" (info.max_virt_leaf) 660 : "a" (0x40000000); 661 } 662 asm { 663 "cpuid" 664 : "=a" (info.max_ext_leaf) 665 : "a" (0x80000000); 666 } 667 } else version (LDC) { 668 version (X86) asm { 669 lea EDI, info; 670 mov EAX, 0; 671 cpuid; 672 mov [EDI + info.max_leaf.offsetof], EAX; 673 mov EAX, 0x4000_0000; 674 cpuid; 675 mov [EDI + info.max_virt_leaf.offsetof], EAX; 676 mov EAX, 0x8000_0000; 677 cpuid; 678 mov [EDI + info.max_ext_leaf.offsetof], EAX; 679 } else version (X86_64) asm { 680 lea RDI, info; 681 mov EAX, 0; 682 cpuid; 683 mov [RDI + info.max_leaf.offsetof], EAX; 684 mov EAX, 0x4000_0000; 685 cpuid; 686 mov [RDI + info.max_virt_leaf.offsetof], EAX; 687 mov EAX, 0x8000_0000; 688 cpuid; 689 mov [RDI + info.max_ext_leaf.offsetof], EAX; 690 } 691 } 692 } 693 694 /// Fetch CPU vendor 695 pragma(inline, false) 696 void getVendor(ref CPUINFO info) { 697 version (DMD) { 698 version (X86) asm { 699 mov EDI, info; 700 mov EAX, 0; 701 cpuid; 702 mov [EDI + VENDOR_OFFSET], EBX; 703 mov [EDI + VENDOR_OFFSET + 4], EDX; 704 mov [EDI + VENDOR_OFFSET + 8], ECX; 705 } else asm { // x86-64 706 mov RDI, info; 707 mov EAX, 0; 708 cpuid; 709 mov [RDI + VENDOR_OFFSET], EBX; 710 mov [RDI + VENDOR_OFFSET + 4], EDX; 711 mov [RDI + VENDOR_OFFSET + 8], ECX; 712 } 713 } else version (GDC) { 714 version (X86) asm { 715 "lea %0, %%edi\n\t"~ 716 "mov $0, %%eax\n\t"~ 717 "cpuid\n"~ 718 "mov %%ebx, (%%edi)\n\t"~ 719 "mov %%edx, 4(%%edi)\n\t"~ 720 "mov %%ecx, 8(%%edi)" 721 : 722 : "m" (info.vendor) 723 : "edi", "eax", "ebx", "ecx", "edx"; 724 } else asm { // x86-64 725 "lea %0, %%rdi\n\t"~ 726 "mov $0, %%eax\n\t"~ 727 "cpuid\n"~ 728 "mov %%ebx, (%%rdi)\n\t"~ 729 "mov %%edx, 4(%%rdi)\n\t"~ 730 "mov %%ecx, 8(%%rdi)" 731 : 732 : "m" (info.vendor) 733 : "rdi", "rax", "rbx", "rcx", "rdx"; 734 } 735 } else version (LDC) { 736 version (X86) asm { 737 lea EDI, info; 738 mov EAX, 0; 739 cpuid; 740 mov [EDI + VENDOR_OFFSET], EBX; 741 mov [EDI + VENDOR_OFFSET + 4], EDX; 742 mov [EDI + VENDOR_OFFSET + 8], ECX; 743 } else asm { // x86-64 744 lea RDI, info; 745 mov EAX, 0; 746 cpuid; 747 mov [RDI + VENDOR_OFFSET], EBX; 748 mov [RDI + VENDOR_OFFSET + 4], EDX; 749 mov [RDI + VENDOR_OFFSET + 8], ECX; 750 } 751 } 752 753 // Vendor string verification 754 // If the rest of the string doesn't correspond, the id is unset 755 switch (info.vendor32[0]) { 756 case Vendor.Intel: // "GenuineIntel" 757 if (info.vendor32[1] != ID!("ineI")) goto default; 758 if (info.vendor32[2] != ID!("ntel")) goto default; 759 break; 760 case Vendor.AMD: // "AuthenticAMD" 761 if (info.vendor32[1] != ID!("enti")) goto default; 762 if (info.vendor32[2] != ID!("cAMD")) goto default; 763 break; 764 case Vendor.VIA: // "VIA VIA VIA " 765 if (info.vendor32[1] != ID!("VIA ")) goto default; 766 if (info.vendor32[2] != ID!("VIA ")) goto default; 767 break; 768 default: // Unknown 769 info.vendor_id32 = 0; 770 return; 771 } 772 773 info.vendor_id32 = info.vendor32[0]; 774 } 775 776 pragma(inline, false) 777 private 778 void getBrand(ref CPUINFO info) { 779 version (DMD) { 780 version (X86) asm { 781 mov EDI, info; 782 mov EAX, 0x8000_0002; 783 cpuid; 784 mov [EDI + BRAND_OFFSET], EAX; 785 mov [EDI + BRAND_OFFSET + 4], EBX; 786 mov [EDI + BRAND_OFFSET + 8], ECX; 787 mov [EDI + BRAND_OFFSET + 12], EDX; 788 mov EAX, 0x8000_0003; 789 cpuid; 790 mov [EDI + BRAND_OFFSET + 16], EAX; 791 mov [EDI + BRAND_OFFSET + 20], EBX; 792 mov [EDI + BRAND_OFFSET + 24], ECX; 793 mov [EDI + BRAND_OFFSET + 28], EDX; 794 mov EAX, 0x8000_0004; 795 cpuid; 796 mov [EDI + BRAND_OFFSET + 32], EAX; 797 mov [EDI + BRAND_OFFSET + 36], EBX; 798 mov [EDI + BRAND_OFFSET + 40], ECX; 799 mov [EDI + BRAND_OFFSET + 44], EDX; 800 } else version (X86_64) asm { 801 mov RDI, info; 802 mov EAX, 0x8000_0002; 803 cpuid; 804 mov [RDI + BRAND_OFFSET], EAX; 805 mov [RDI + BRAND_OFFSET + 4], EBX; 806 mov [RDI + BRAND_OFFSET + 8], ECX; 807 mov [RDI + BRAND_OFFSET + 12], EDX; 808 mov EAX, 0x8000_0003; 809 cpuid; 810 mov [RDI + BRAND_OFFSET + 16], EAX; 811 mov [RDI + BRAND_OFFSET + 20], EBX; 812 mov [RDI + BRAND_OFFSET + 24], ECX; 813 mov [RDI + BRAND_OFFSET + 28], EDX; 814 mov EAX, 0x8000_0004; 815 cpuid; 816 mov [RDI + BRAND_OFFSET + 32], EAX; 817 mov [RDI + BRAND_OFFSET + 36], EBX; 818 mov [RDI + BRAND_OFFSET + 40], ECX; 819 mov [RDI + BRAND_OFFSET + 44], EDX; 820 } 821 } else version (GDC) { 822 version (X86) asm { 823 "lea %0, %%edi\n\t"~ 824 "mov $0x80000002, %%eax\n\t"~ 825 "cpuid\n\t"~ 826 "mov %%eax, (%%rdi)\n\t"~ 827 "mov %%ebx, 4(%%rdi)\n\t"~ 828 "mov %%ecx, 8(%%rdi)\n\t"~ 829 "mov %%edx, 12(%%rdi)\n\t"~ 830 "mov $0x80000003, %%eax\n\t"~ 831 "cpuid\n\t"~ 832 "mov %%eax, 16(%%rdi)\n\t"~ 833 "mov %%ebx, 20(%%rdi)\n\t"~ 834 "mov %%ecx, 24(%%rdi)\n\t"~ 835 "mov %%edx, 28(%%rdi)\n\t"~ 836 "mov $0x80000004, %%eax\n\t"~ 837 "cpuid\n\t"~ 838 "mov %%eax, 32(%%rdi)\n\t"~ 839 "mov %%ebx, 36(%%rdi)\n\t"~ 840 "mov %%ecx, 40(%%rdi)\n\t"~ 841 "mov %%edx, 44(%%rdi)" 842 : 843 : "m" (info.brand) 844 : "edi", "eax", "ebx", "ecx", "edx"; 845 } else version (X86_64) asm { 846 "lea %0, %%rdi\n\t"~ 847 "mov $0x80000002, %%eax\n\t"~ 848 "cpuid\n\t"~ 849 "mov %%eax, (%%rdi)\n\t"~ 850 "mov %%ebx, 4(%%rdi)\n\t"~ 851 "mov %%ecx, 8(%%rdi)\n\t"~ 852 "mov %%edx, 12(%%rdi)\n\t"~ 853 "mov $0x80000003, %%eax\n\t"~ 854 "cpuid\n\t"~ 855 "mov %%eax, 16(%%rdi)\n\t"~ 856 "mov %%ebx, 20(%%rdi)\n\t"~ 857 "mov %%ecx, 24(%%rdi)\n\t"~ 858 "mov %%edx, 28(%%rdi)\n\t"~ 859 "mov $0x80000004, %%eax\n\t"~ 860 "cpuid\n\t"~ 861 "mov %%eax, 32(%%rdi)\n\t"~ 862 "mov %%ebx, 36(%%rdi)\n\t"~ 863 "mov %%ecx, 40(%%rdi)\n\t"~ 864 "mov %%edx, 44(%%rdi)" 865 : 866 : "m" (info.brand) 867 : "rdi", "rax", "rbx", "rcx", "rdx"; 868 } 869 } else version (LDC) { 870 version (X86) asm { 871 lea EDI, info; 872 mov EAX, 0x8000_0002; 873 cpuid; 874 mov [EDI + BRAND_OFFSET], EAX; 875 mov [EDI + BRAND_OFFSET + 4], EBX; 876 mov [EDI + BRAND_OFFSET + 8], ECX; 877 mov [EDI + BRAND_OFFSET + 12], EDX; 878 mov EAX, 0x8000_0003; 879 cpuid; 880 mov [EDI + BRAND_OFFSET + 16], EAX; 881 mov [EDI + BRAND_OFFSET + 20], EBX; 882 mov [EDI + BRAND_OFFSET + 24], ECX; 883 mov [EDI + BRAND_OFFSET + 28], EDX; 884 mov EAX, 0x8000_0004; 885 cpuid; 886 mov [EDI + BRAND_OFFSET + 32], EAX; 887 mov [EDI + BRAND_OFFSET + 36], EBX; 888 mov [EDI + BRAND_OFFSET + 40], ECX; 889 mov [EDI + BRAND_OFFSET + 44], EDX; 890 } else version (X86_64) asm { 891 lea RDI, info; 892 mov EAX, 0x8000_0002; 893 cpuid; 894 mov [RDI + BRAND_OFFSET], EAX; 895 mov [RDI + BRAND_OFFSET + 4], EBX; 896 mov [RDI + BRAND_OFFSET + 8], ECX; 897 mov [RDI + BRAND_OFFSET + 12], EDX; 898 mov EAX, 0x8000_0003; 899 cpuid; 900 mov [RDI + BRAND_OFFSET + 16], EAX; 901 mov [RDI + BRAND_OFFSET + 20], EBX; 902 mov [RDI + BRAND_OFFSET + 24], ECX; 903 mov [RDI + BRAND_OFFSET + 28], EDX; 904 mov EAX, 0x8000_0004; 905 cpuid; 906 mov [RDI + BRAND_OFFSET + 32], EAX; 907 mov [RDI + BRAND_OFFSET + 36], EBX; 908 mov [RDI + BRAND_OFFSET + 40], ECX; 909 mov [RDI + BRAND_OFFSET + 44], EDX; 910 } 911 } 912 } 913 914 pragma(inline, false) 915 private 916 void getVirtVendor(ref CPUINFO info) { 917 version (DMD) { 918 version (X86) asm { 919 mov EDI, info; 920 mov EAX, 0x40000000; 921 cpuid; 922 mov [EDI + VIRTVENDOR_OFFSET], EBX; 923 mov [EDI + VIRTVENDOR_OFFSET + 4], ECX; 924 mov [EDI + VIRTVENDOR_OFFSET + 8], EDX; 925 } else asm { // x86-64 926 mov RDI, info; 927 mov EAX, 0x40000000; 928 cpuid; 929 mov [RDI + VIRTVENDOR_OFFSET], EBX; 930 mov [RDI + VIRTVENDOR_OFFSET + 4], ECX; 931 mov [RDI + VIRTVENDOR_OFFSET + 8], EDX; 932 } 933 } else version (GDC) { 934 version (X86) asm { 935 "lea %0, %%edi\n\t"~ 936 "mov $0x40000000, %%eax\n\t"~ 937 "cpuid\n"~ 938 "mov %%ebx, (%%edi)\n\t"~ 939 "mov %%ecx, 4(%%edi)\n\t"~ 940 "mov %%edx, 8(%%edi)" 941 : 942 : "m" (info.virt.vendor) 943 : "edi", "eax", "ebx", "ecx", "edx"; 944 } else asm { // x86-64 945 "lea %0, %%rdi\n\t"~ 946 "mov $0x40000000, %%eax\n\t"~ 947 "cpuid\n"~ 948 "mov %%ebx, (%%rdi)\n\t"~ 949 "mov %%ecx, 4(%%rdi)\n\t"~ 950 "mov %%edx, 8(%%rdi)" 951 : 952 : "m" (info.virt.vendor) 953 : "rdi", "rax", "rbx", "rcx", "rdx"; 954 } 955 } else version (LDC) { 956 version (X86) asm { 957 lea EDI, info; 958 mov EAX, 0x40000000; 959 cpuid; 960 mov [EDI + VIRTVENDOR_OFFSET], EBX; 961 mov [EDI + VIRTVENDOR_OFFSET + 4], ECX; 962 mov [EDI + VIRTVENDOR_OFFSET + 8], EDX; 963 } else asm { // x86-64 964 lea RDI, info; 965 mov EAX, 0x40000000; 966 cpuid; 967 mov [RDI + VIRTVENDOR_OFFSET], EBX; 968 mov [RDI + VIRTVENDOR_OFFSET + 4], ECX; 969 mov [RDI + VIRTVENDOR_OFFSET + 8], EDX; 970 } 971 } 972 973 // Paravirtual vendor string verification 974 // If the rest of the string doesn't correspond, the id is unset 975 switch (info.virt.vendor32[0]) { 976 case VirtVendor.KVM: // "KVMKVMKVM\0\0\0" 977 if (info.virt.vendor32[1] != ID!("VMKV")) goto default; 978 if (info.virt.vendor32[2] != ID!("M\0\0\0")) goto default; 979 break; 980 case VirtVendor.HyperV: // "Microsoft Hv" 981 if (info.virt.vendor32[1] != ID!("osof")) goto default; 982 if (info.virt.vendor32[2] != ID!("t Hv")) goto default; 983 break; 984 case VirtVendor.VBoxHyperV: // "VBoxVBoxVBox" 985 if (info.virt.vendor32[1] != ID!("VBox")) goto default; 986 if (info.virt.vendor32[2] != ID!("VBox")) goto default; 987 info.virt.vendor_id = VirtVendor.HyperV; 988 return; 989 default: 990 info.virt.vendor_id32 = 0; 991 return; 992 } 993 994 info.virt.vendor_id32 = info.virt.vendor32[0]; 995 } 996 997 /// Fetch CPU information. 998 /// Params: info = CPUINFO structure 999 // There are essentially 5 sections to this function: 1000 // - Brand String 1001 // - Normal leaf information 1002 // - Paravirtualization leaf information 1003 // - Extended leaf information 1004 // - Cache information 1005 pragma(inline, false) 1006 void getInfo(ref CPUINFO info) { 1007 getVendor(info); 1008 getBrand(info); 1009 1010 REGISTERS regs = void; 1011 1012 // 1013 // Leaf 1H 1014 // 1015 1016 asmcpuid(regs, 1); 1017 1018 // EAX 1019 info.stepping = regs.eax & 0xF; // EAX[3:0] 1020 info.model_base = regs.eax >> 4 & 0xF; // EAX[7:4] 1021 info.family_base = regs.eax >> 8 & 0xF; // EAX[11:8] 1022 info.type = regs.eax >> 12 & 0b11; // EAX[13:12] 1023 info.type_string = PROCESSOR_TYPE[info.type]; 1024 info.model_ext = regs.eax >> 16 & 0xF; // EAX[19:16] 1025 info.family_ext = cast(ubyte)(regs.eax >> 20); // EAX[27:20] 1026 1027 switch (info.vendor_id) { 1028 case Vendor.Intel: 1029 info.family = info.family_base != 0 ? 1030 info.family_base : 1031 cast(ubyte)(info.family_ext + info.family_base); 1032 1033 info.model = info.family_base == 6 || info.family_base == 0 ? 1034 cast(ubyte)((info.model_ext << 4) + info.model_base) : 1035 info.model_base; // DisplayModel = Model_ID; 1036 1037 // ECX 1038 info.dbg.dtes64 = (regs.ecx & BIT!(2)) != 0; 1039 info.dbg.ds_cpl = (regs.ecx & BIT!(4)) != 0; 1040 info.virt.available = (regs.ecx & BIT!(5)) != 0; 1041 info.tech.smx = (regs.ecx & BIT!(6)) != 0; 1042 info.tech.eist = (regs.ecx & BIT!(7)) != 0; 1043 info.acpi.tm2 = (regs.ecx & BIT!(8)) != 0; 1044 info.cache.cnxt_id = (regs.ecx & BIT!(10)) != 0; 1045 info.dbg.sdbg = (regs.ecx & BIT!(11)) != 0; 1046 info.misc.xtpr = (regs.ecx & BIT!(14)) != 0; 1047 info.dbg.pdcm = (regs.ecx & BIT!(15)) != 0; 1048 info.misc.pcid = (regs.ecx & BIT!(17)) != 0; 1049 info.dbg.mca = (regs.ecx & BIT!(18)) != 0; 1050 info.acpi.x2apic = (regs.ecx & BIT!(21)) != 0; 1051 info.extras.rdtsc_deadline = (regs.ecx & BIT!(24)) != 0; 1052 1053 // EDX 1054 info.misc.psn = (regs.edx & BIT!(18)) != 0; 1055 info.dbg.ds = (regs.edx & BIT!(21)) != 0; 1056 info.acpi.available = (regs.edx & BIT!(22)) != 0; 1057 info.cache.ss = (regs.edx & BIT!(27)) != 0; 1058 info.acpi.tm = (regs.edx & BIT!(29)) != 0; 1059 info.dbg.pbe = regs.edx >= BIT!(31); 1060 break; 1061 case Vendor.AMD: 1062 if (info.family_base < 0xF) { 1063 info.family = info.family_base; 1064 info.model = info.model_base; 1065 } else { 1066 info.family = cast(ubyte)(info.family_ext + info.family_base); 1067 info.model = cast(ubyte)((info.model_ext << 4) + info.model_base); 1068 } 1069 break; 1070 default: 1071 } 1072 1073 // EBX 1074 __01ebx_t t = void; // BrandIndex, CLFLUSHLineSize, MaxIDs, InitialAPICID 1075 t.all = regs.ebx; 1076 info.brand_index = t.brand_index; 1077 info.cache.clflush_linesize = t.clflush_linesize; 1078 info.acpi.max_apic_id = t.max_apic_id; 1079 info.acpi.apic_id = t.apic_id; 1080 1081 // ECX 1082 info.ext.sse3 = (regs.ecx & BIT!(0)) != 0; 1083 info.extras.pclmulqdq = (regs.ecx & BIT!(1)) != 0; 1084 info.extras.monitor = (regs.ecx & BIT!(3)) != 0; 1085 info.ext.ssse3 = (regs.ecx & BIT!(9)) != 0; 1086 info.ext.fma3 = (regs.ecx & BIT!(12)) != 0; 1087 info.extras.cmpxchg16b = (regs.ecx & BIT!(13)) != 0; 1088 info.ext.sse41 = (regs.ecx & BIT!(15)) != 0; 1089 info.ext.sse42 = (regs.ecx & BIT!(20)) != 0; 1090 info.extras.movbe = (regs.ecx & BIT!(22)) != 0; 1091 info.extras.popcnt = (regs.ecx & BIT!(23)) != 0; 1092 info.ext.aes_ni = (regs.ecx & BIT!(25)) != 0; 1093 info.extras.xsave = (regs.ecx & BIT!(26)) != 0; 1094 info.extras.osxsave = (regs.ecx & BIT!(27)) != 0; 1095 info.ext.avx = (regs.ecx & BIT!(28)) != 0; 1096 info.ext.f16c = (regs.ecx & BIT!(29)) != 0; 1097 info.extras.rdrand = (regs.ecx & BIT!(30)) != 0; 1098 1099 // EDX 1100 info.ext.fpu = (regs.edx & BIT!(0)) != 0; 1101 info.virt.vme = (regs.edx & BIT!(1)) != 0; 1102 info.dbg.de = (regs.edx & BIT!(2)) != 0; 1103 info.mem.pse = (regs.edx & BIT!(3)) != 0; 1104 info.extras.rdtsc = (regs.edx & BIT!(4)) != 0; 1105 info.extras.rdmsr = (regs.edx & BIT!(5)) != 0; 1106 info.mem.pae = (regs.edx & BIT!(6)) != 0; 1107 info.dbg.mce = (regs.edx & BIT!(7)) != 0; 1108 info.extras.cmpxchg8b = (regs.edx & BIT!(8)) != 0; 1109 info.acpi.apic = (regs.edx & BIT!(9)) != 0; 1110 info.extras.sysenter = (regs.edx & BIT!(11)) != 0; 1111 info.mem.mtrr = (regs.edx & BIT!(12)) != 0; 1112 info.mem.pge = (regs.edx & BIT!(13)) != 0; 1113 info.dbg.mca = (regs.edx & BIT!(14)) != 0; 1114 info.extras.cmov = (regs.edx & BIT!(15)) != 0; 1115 info.mem.pat = (regs.edx & BIT!(16)) != 0; 1116 info.mem.pse_36 = (regs.edx & BIT!(17)) != 0; 1117 info.cache.clflush = (regs.edx & BIT!(19)) != 0; 1118 info.ext.mmx = (regs.edx & BIT!(23)) != 0; 1119 info.extras.fxsr = (regs.edx & BIT!(24)) != 0; 1120 info.ext.sse = (regs.edx & BIT!(25)) != 0; 1121 info.ext.sse2 = (regs.edx & BIT!(26)) != 0; 1122 info.tech.htt = (regs.edx & BIT!(28)) != 0; 1123 1124 switch (info.vendor_id) { 1125 case Vendor.AMD: 1126 if (info.tech.htt) 1127 info.cores.logical = info.acpi.max_apic_id; 1128 break; 1129 default: 1130 } 1131 1132 if (info.max_leaf < 5) goto L_VIRT; 1133 1134 // 1135 // Leaf 5H 1136 // 1137 1138 asmcpuid(regs, 5); 1139 1140 info.extras.mwait_min = cast(ushort)regs.eax; 1141 info.extras.mwait_max = cast(ushort)regs.ebx; 1142 1143 if (info.max_leaf < 6) goto L_VIRT; 1144 1145 // 1146 // Leaf 6H 1147 // 1148 1149 asmcpuid(regs, 6); 1150 1151 switch (info.vendor_id) { 1152 case Vendor.Intel: 1153 info.tech.turboboost = (regs.eax & BIT!(1)) != 0; 1154 info.tech.turboboost30 = (regs.eax & BIT!(14)) != 0; 1155 break; 1156 default: 1157 } 1158 1159 info.acpi.arat = (regs.eax & BIT!(2)) != 0; 1160 1161 if (info.max_leaf < 7) goto L_VIRT; 1162 1163 // 1164 // Leaf 7H 1165 // 1166 1167 asmcpuid(regs, 7); 1168 1169 switch (info.vendor_id) { 1170 case Vendor.Intel: 1171 // EBX 1172 info.tech.sgx = (regs.ebx & BIT!(2)) != 0; 1173 info.mem.hle = (regs.ebx & BIT!(4)) != 0; 1174 info.cache.invpcid = (regs.ebx & BIT!(10)) != 0; 1175 info.mem.rtm = (regs.ebx & BIT!(11)) != 0; 1176 info.ext.avx512f = (regs.ebx & BIT!(16)) != 0; 1177 info.mem.smap = (regs.ebx & BIT!(20)) != 0; 1178 info.ext.avx512er = (regs.ebx & BIT!(27)) != 0; 1179 info.ext.avx512pf = (regs.ebx & BIT!(26)) != 0; 1180 info.ext.avx512cd = (regs.ebx & BIT!(28)) != 0; 1181 info.ext.avx512dq = (regs.ebx & BIT!(17)) != 0; 1182 info.ext.avx512bw = (regs.ebx & BIT!(30)) != 0; 1183 info.ext.avx512_ifma = (regs.ebx & BIT!(21)) != 0; 1184 info.ext.avx512_vbmi = regs.ebx >= BIT!(31); 1185 // ECX 1186 info.ext.avx512vl = (regs.ecx & BIT!(1)) != 0; 1187 info.mem.pku = (regs.ecx & BIT!(3)) != 0; 1188 info.mem.fsrepmov = (regs.ecx & BIT!(4)) != 0; 1189 info.ext.waitpkg = (regs.ecx & BIT!(5)) != 0; 1190 info.ext.avx512_vbmi2 = (regs.ecx & BIT!(6)) != 0; 1191 info.sec.cet_ss = (regs.ecx & BIT!(7)) != 0; 1192 info.ext.avx512_gfni = (regs.ecx & BIT!(8)) != 0; 1193 info.ext.avx512_vaes = (regs.ecx & BIT!(9)) != 0; 1194 info.ext.avx512_vnni = (regs.ecx & BIT!(11)) != 0; 1195 info.ext.avx512_bitalg = (regs.ecx & BIT!(12)) != 0; 1196 info.ext.avx512_vpopcntdq = (regs.ecx & BIT!(14)) != 0; 1197 info.mem._5pl = (regs.ecx & BIT!(16)) != 0; 1198 info.extras.cldemote = (regs.ecx & BIT!(25)) != 0; 1199 info.extras.movdiri = (regs.ecx & BIT!(27)) != 0; 1200 info.extras.movdir64b = (regs.ecx & BIT!(28)) != 0; 1201 info.extras.enqcmd = (regs.ecx & BIT!(29)) != 0; 1202 // EDX 1203 info.ext.avx512_4vnniw = (regs.edx & BIT!(2)) != 0; 1204 info.ext.avx512_4fmaps = (regs.edx & BIT!(3)) != 0; 1205 info.misc.uintr = (regs.edx & BIT!(5)) != 0; 1206 info.ext.avx512_vp2intersect = (regs.edx & BIT!(8)) != 0; 1207 info.sec.md_clear = (regs.edx & BIT!(10)) != 0; 1208 info.extras.serialize = (regs.edx & BIT!(14)) != 0; 1209 info.mem.tsxldtrk = (regs.edx & BIT!(16)) != 0; 1210 info.extras.pconfig = (regs.edx & BIT!(18)) != 0; 1211 info.sec.cet_ibt = (regs.edx & BIT!(20)) != 0; 1212 info.ext.amx_bf16 = (regs.edx & BIT!(22)) != 0; 1213 info.ext.amx = (regs.edx & BIT!(24)) != 0; 1214 info.ext.amx_int8 = (regs.edx & BIT!(25)) != 0; 1215 info.sec.ibrs = (regs.edx & BIT!(26)) != 0; 1216 info.sec.stibp = (regs.edx & BIT!(27)) != 0; 1217 info.sec.l1d_flush = (regs.edx & BIT!(28)) != 0; 1218 info.sec.ia32_arch_capabilities = (regs.edx & BIT!(29)) != 0; 1219 info.sec.ssbd = regs.edx >= BIT!(31); 1220 break; 1221 default: 1222 } 1223 1224 // ebx 1225 info.misc.fsgsbase = (regs.ebx & BIT!(0)) != 0; 1226 info.ext.bmi1 = (regs.ebx & BIT!(3)) != 0; 1227 info.ext.avx2 = (regs.ebx & BIT!(5)) != 0; 1228 info.mem.smep = (regs.ebx & BIT!(7)) != 0; 1229 info.ext.bmi2 = (regs.ebx & BIT!(8)) != 0; 1230 info.extras.rdseed = (regs.ebx & BIT!(18)) != 0; 1231 info.ext.adx = (regs.ebx & BIT!(19)) != 0; 1232 info.cache.clflushopt = (regs.ebx & BIT!(23)) != 0; 1233 info.ext.sha = (regs.ebx & BIT!(29)) != 0; 1234 // ecx 1235 info.extras.rdpid = (regs.ecx & BIT!(22)) != 0; 1236 1237 // 1238 // Leaf 7H(ECX=01h) 1239 // 1240 1241 switch (info.vendor_id) { 1242 case Vendor.Intel: 1243 asmcpuid(regs, 7, 1); 1244 // a 1245 info.ext.avx512_bf16 = (regs.eax & BIT!(5)) != 0; 1246 info.mem.lam = (regs.eax & BIT!(26)) != 0; 1247 break; 1248 default: 1249 } 1250 1251 if (info.max_leaf < 0xD) goto L_VIRT; 1252 1253 // 1254 // Leaf DH 1255 // 1256 1257 switch (info.vendor_id) { 1258 case Vendor.Intel: 1259 asmcpuid(regs, 0xd); 1260 info.ext.amx_xtilecfg = (regs.eax & BIT!(17)) != 0; 1261 info.ext.amx_xtiledata = (regs.eax & BIT!(18)) != 0; 1262 break; 1263 default: 1264 } 1265 1266 // 1267 // Leaf DH(ECX=01h) 1268 // 1269 1270 switch (info.vendor_id) { 1271 case Vendor.Intel: 1272 asmcpuid(regs, 0xd, 1); 1273 info.ext.amx_xfd = (regs.eax & BIT!(18)) != 0; 1274 break; 1275 default: 1276 } 1277 1278 if (info.max_virt_leaf < 0x4000_0000) goto L_VIRT; 1279 1280 // 1281 // Leaf 4000_000H 1282 // 1283 1284 L_VIRT: 1285 getVirtVendor(info); 1286 1287 if (info.max_virt_leaf < 0x4000_0001) goto L_EXTENDED; 1288 1289 // 1290 // Leaf 4000_0001H 1291 // 1292 1293 switch (info.virt.vendor_id) { 1294 case VirtVendor.KVM: 1295 asmcpuid(regs, 0x4000_0001); 1296 info.virt.kvm_feature_clocksource = (regs.eax & BIT!(0)) != 0; 1297 info.virt.kvm_feature_nop_io_delay = (regs.eax & BIT!(1)) != 0; 1298 info.virt.kvm_feature_mmu_op = (regs.eax & BIT!(2)) != 0; 1299 info.virt.kvm_feature_clocksource2 = (regs.eax & BIT!(3)) != 0; 1300 info.virt.kvm_feature_async_pf = (regs.eax & BIT!(4)) != 0; 1301 info.virt.kvm_feature_steal_time = (regs.eax & BIT!(5)) != 0; 1302 info.virt.kvm_feature_pv_eoi = (regs.eax & BIT!(6)) != 0; 1303 info.virt.kvm_feature_pv_unhault = (regs.eax & BIT!(7)) != 0; 1304 info.virt.kvm_feature_pv_tlb_flush = (regs.eax & BIT!(9)) != 0; 1305 info.virt.kvm_feature_async_pf_vmexit = (regs.eax & BIT!(10)) != 0; 1306 info.virt.kvm_feature_pv_send_ipi = (regs.eax & BIT!(11)) != 0; 1307 info.virt.kvm_feature_pv_poll_control = (regs.eax & BIT!(12)) != 0; 1308 info.virt.kvm_feature_pv_sched_yield = (regs.eax & BIT!(13)) != 0; 1309 info.virt.kvm_feature_clocsource_stable_bit = (regs.eax & BIT!(24)) != 0; 1310 info.virt.kvm_hint_realtime = (regs.edx & BIT!(0)) != 0; 1311 break; 1312 default: 1313 } 1314 1315 if (info.max_virt_leaf < 0x4000_0002) goto L_EXTENDED; 1316 1317 // 1318 // Leaf 4000_002H 1319 // 1320 1321 switch (info.virt.vendor_id) { 1322 case VirtVendor.HyperV: 1323 asmcpuid(regs, 0x4000_0002); 1324 info.virt.hv_guest_minor = cast(ubyte)(regs.eax >> 24); 1325 info.virt.hv_guest_service = cast(ubyte)(regs.eax >> 16); 1326 info.virt.hv_guest_build = cast(ushort)regs.eax; 1327 info.virt.hv_guest_opensource = regs.edx >= BIT!(31); 1328 info.virt.hv_guest_vendor_id = (regs.edx >> 16) & 0xFFF; 1329 info.virt.hv_guest_os = cast(ubyte)(regs.edx >> 8); 1330 info.virt.hv_guest_major = cast(ubyte)regs.edx; 1331 break; 1332 default: 1333 } 1334 1335 if (info.max_virt_leaf < 0x4000_0003) goto L_EXTENDED; 1336 1337 // 1338 // Leaf 4000_0003H 1339 // 1340 1341 switch (info.virt.vendor_id) { 1342 case VirtVendor.HyperV: 1343 asmcpuid(regs, 0x4000_0003); 1344 info.virt.hv_base_feat_vp_runtime_msr = (regs.eax & BIT!(0)) != 0; 1345 info.virt.hv_base_feat_part_time_ref_count_msr = (regs.eax & BIT!(1)) != 0; 1346 info.virt.hv_base_feat_basic_synic_msrs = (regs.eax & BIT!(2)) != 0; 1347 info.virt.hv_base_feat_stimer_msrs = (regs.eax & BIT!(3)) != 0; 1348 info.virt.hv_base_feat_apic_access_msrs = (regs.eax & BIT!(4)) != 0; 1349 info.virt.hv_base_feat_hypercall_msrs = (regs.eax & BIT!(5)) != 0; 1350 info.virt.hv_base_feat_vp_id_msr = (regs.eax & BIT!(6)) != 0; 1351 info.virt.hv_base_feat_virt_sys_reset_msr = (regs.eax & BIT!(7)) != 0; 1352 info.virt.hv_base_feat_stat_pages_msr = (regs.eax & BIT!(8)) != 0; 1353 info.virt.hv_base_feat_part_ref_tsc_msr = (regs.eax & BIT!(9)) != 0; 1354 info.virt.hv_base_feat_guest_idle_state_msr = (regs.eax & BIT!(10)) != 0; 1355 info.virt.hv_base_feat_timer_freq_msrs = (regs.eax & BIT!(11)) != 0; 1356 info.virt.hv_base_feat_debug_msrs = (regs.eax & BIT!(12)) != 0; 1357 info.virt.hv_part_flags_create_part = (regs.ebx & BIT!(0)) != 0; 1358 info.virt.hv_part_flags_access_part_id = (regs.ebx & BIT!(1)) != 0; 1359 info.virt.hv_part_flags_access_memory_pool = (regs.ebx & BIT!(2)) != 0; 1360 info.virt.hv_part_flags_adjust_msg_buffers = (regs.ebx & BIT!(3)) != 0; 1361 info.virt.hv_part_flags_post_msgs = (regs.ebx & BIT!(4)) != 0; 1362 info.virt.hv_part_flags_signal_events = (regs.ebx & BIT!(5)) != 0; 1363 info.virt.hv_part_flags_create_port = (regs.ebx & BIT!(6)) != 0; 1364 info.virt.hv_part_flags_connect_port = (regs.ebx & BIT!(7)) != 0; 1365 info.virt.hv_part_flags_access_stats = (regs.ebx & BIT!(8)) != 0; 1366 info.virt.hv_part_flags_debugging = (regs.ebx & BIT!(11)) != 0; 1367 info.virt.hv_part_flags_cpu_mgmt = (regs.ebx & BIT!(12)) != 0; 1368 info.virt.hv_part_flags_cpu_profiler = (regs.ebx & BIT!(13)) != 0; 1369 info.virt.hv_part_flags_expanded_stack_walk = (regs.ebx & BIT!(14)) != 0; 1370 info.virt.hv_part_flags_access_vsm = (regs.ebx & BIT!(16)) != 0; 1371 info.virt.hv_part_flags_access_vp_regs = (regs.ebx & BIT!(17)) != 0; 1372 info.virt.hv_part_flags_extended_hypercalls = (regs.ebx & BIT!(20)) != 0; 1373 info.virt.hv_part_flags_start_vp = (regs.ebx & BIT!(21)) != 0; 1374 info.virt.hv_pm_max_cpu_power_state_c0 = (regs.ecx & BIT!(0)) != 0; 1375 info.virt.hv_pm_max_cpu_power_state_c1 = (regs.ecx & BIT!(1)) != 0; 1376 info.virt.hv_pm_max_cpu_power_state_c2 = (regs.ecx & BIT!(2)) != 0; 1377 info.virt.hv_pm_max_cpu_power_state_c3 = (regs.ecx & BIT!(3)) != 0; 1378 info.virt.hv_pm_hpet_reqd_for_c3 = (regs.ecx & BIT!(4)) != 0; 1379 info.virt.hv_misc_feat_mwait = (regs.eax & BIT!(0)) != 0; 1380 info.virt.hv_misc_feat_guest_debugging = (regs.eax & BIT!(1)) != 0; 1381 info.virt.hv_misc_feat_perf_mon = (regs.eax & BIT!(2)) != 0; 1382 info.virt.hv_misc_feat_pcpu_dyn_part_event = (regs.eax & BIT!(3)) != 0; 1383 info.virt.hv_misc_feat_xmm_hypercall_input = (regs.eax & BIT!(4)) != 0; 1384 info.virt.hv_misc_feat_guest_idle_state = (regs.eax & BIT!(5)) != 0; 1385 info.virt.hv_misc_feat_hypervisor_sleep_state = (regs.eax & BIT!(6)) != 0; 1386 info.virt.hv_misc_feat_query_numa_distance = (regs.eax & BIT!(7)) != 0; 1387 info.virt.hv_misc_feat_timer_freq = (regs.eax & BIT!(8)) != 0; 1388 info.virt.hv_misc_feat_inject_synmc_xcpt = (regs.eax & BIT!(9)) != 0; 1389 info.virt.hv_misc_feat_guest_crash_msrs = (regs.eax & BIT!(10)) != 0; 1390 info.virt.hv_misc_feat_debug_msrs = (regs.eax & BIT!(11)) != 0; 1391 info.virt.hv_misc_feat_npiep1 = (regs.eax & BIT!(12)) != 0; 1392 info.virt.hv_misc_feat_disable_hypervisor = (regs.eax & BIT!(13)) != 0; 1393 info.virt.hv_misc_feat_ext_gva_range_for_flush_va_list = (regs.eax & BIT!(14)) != 0; 1394 info.virt.hv_misc_feat_hypercall_output_xmm = (regs.eax & BIT!(15)) != 0; 1395 info.virt.hv_misc_feat_sint_polling_mode = (regs.eax & BIT!(17)) != 0; 1396 info.virt.hv_misc_feat_hypercall_msr_lock = (regs.eax & BIT!(18)) != 0; 1397 info.virt.hv_misc_feat_use_direct_synth_msrs = (regs.eax & BIT!(19)) != 0; 1398 break; 1399 default: 1400 } 1401 1402 if (info.max_virt_leaf < 0x4000_0004) goto L_EXTENDED; 1403 1404 // 1405 // Leaf 4000_0004H 1406 // 1407 1408 switch (info.virt.vendor_id) { 1409 case VirtVendor.HyperV: 1410 asmcpuid(regs, 0x4000_0004); 1411 info.virt.hv_hint_hypercall_for_process_switch = (regs.eax & BIT!(0)) != 0; 1412 info.virt.hv_hint_hypercall_for_tlb_flush = (regs.eax & BIT!(1)) != 0; 1413 info.virt.hv_hint_hypercall_for_tlb_shootdown = (regs.eax & BIT!(2)) != 0; 1414 info.virt.hv_hint_msr_for_apic_access = (regs.eax & BIT!(3)) != 0; 1415 info.virt.hv_hint_msr_for_sys_reset = (regs.eax & BIT!(4)) != 0; 1416 info.virt.hv_hint_relax_time_checks = (regs.eax & BIT!(5)) != 0; 1417 info.virt.hv_hint_dma_remapping = (regs.eax & BIT!(6)) != 0; 1418 info.virt.hv_hint_interrupt_remapping = (regs.eax & BIT!(7)) != 0; 1419 info.virt.hv_hint_x2apic_msrs = (regs.eax & BIT!(8)) != 0; 1420 info.virt.hv_hint_deprecate_auto_eoi = (regs.eax & BIT!(9)) != 0; 1421 info.virt.hv_hint_synth_cluster_ipi_hypercall = (regs.eax & BIT!(10)) != 0; 1422 info.virt.hv_hint_ex_proc_masks_interface = (regs.eax & BIT!(11)) != 0; 1423 info.virt.hv_hint_nested_hyperv = (regs.eax & BIT!(12)) != 0; 1424 info.virt.hv_hint_int_for_mbec_syscalls = (regs.eax & BIT!(13)) != 0; 1425 info.virt.hv_hint_nested_enlightened_vmcs_interface = (regs.eax & BIT!(14)) != 0; 1426 break; 1427 default: 1428 } 1429 1430 if (info.max_virt_leaf < 0x4000_0006) goto L_EXTENDED; 1431 1432 // 1433 // Leaf 4000_0006H 1434 // 1435 1436 switch (info.virt.vendor_id) { 1437 case VirtVendor.HyperV: 1438 asmcpuid(regs, 0x4000_0006); 1439 info.virt.hv_host_feat_avic = (regs.eax & BIT!(0)) != 0; 1440 info.virt.hv_host_feat_msr_bitmap = (regs.eax & BIT!(1)) != 0; 1441 info.virt.hv_host_feat_perf_counter = (regs.eax & BIT!(2)) != 0; 1442 info.virt.hv_host_feat_nested_paging = (regs.eax & BIT!(3)) != 0; 1443 info.virt.hv_host_feat_dma_remapping = (regs.eax & BIT!(4)) != 0; 1444 info.virt.hv_host_feat_interrupt_remapping = (regs.eax & BIT!(5)) != 0; 1445 info.virt.hv_host_feat_mem_patrol_scrubber = (regs.eax & BIT!(6)) != 0; 1446 info.virt.hv_host_feat_dma_prot_in_use = (regs.eax & BIT!(7)) != 0; 1447 info.virt.hv_host_feat_hpet_requested = (regs.eax & BIT!(8)) != 0; 1448 info.virt.hv_host_feat_stimer_volatile = (regs.eax & BIT!(9)) != 0; 1449 break; 1450 default: 1451 } 1452 1453 if (info.max_virt_leaf < 0x4000_0010) goto L_EXTENDED; 1454 1455 // 1456 // Leaf 4000_0010H 1457 // 1458 1459 switch (info.virt.vendor_id) { 1460 case VirtVendor.VBoxMin: // VBox Minimal 1461 asmcpuid(regs, 0x4000_0010); 1462 info.virt.vbox_tsc_freq_khz = regs.eax; 1463 info.virt.vbox_apic_freq_khz = regs.ebx; 1464 break; 1465 default: 1466 } 1467 1468 // 1469 // Leaf 8000_0001H 1470 // 1471 1472 L_EXTENDED: 1473 asmcpuid(regs, 0x8000_0001); 1474 1475 switch (info.vendor_id) { 1476 case Vendor.AMD: 1477 // ecx 1478 info.virt.available = (regs.ecx & BIT!(2)) != 0; 1479 info.acpi.x2apic = (regs.ecx & BIT!(3)) != 0; 1480 info.ext.sse4a = (regs.ecx & BIT!(6)) != 0; 1481 info.ext.xop = (regs.ecx & BIT!(11)) != 0; 1482 info.extras.skinit = (regs.ecx & BIT!(12)) != 0; 1483 info.ext.fma4 = (regs.ecx & BIT!(16)) != 0; 1484 info.ext.tbm = (regs.ecx & BIT!(21)) != 0; 1485 // edx 1486 info.ext.mmxext = (regs.edx & BIT!(22)) != 0; 1487 info.ext._3dnowext = (regs.edx & BIT!(30)) != 0; 1488 info.ext._3dnow = regs.edx >= BIT!(31); 1489 break; 1490 default: 1491 } 1492 1493 // ecx 1494 info.ext.lahf64 = (regs.ecx & BIT!(0)) != 0; 1495 info.extras.lzcnt = (regs.ecx & BIT!(5)) != 0; 1496 info.cache.prefetchw = (regs.ecx & BIT!(8)) != 0; 1497 info.extras.monitorx = (regs.ecx & BIT!(29)) != 0; 1498 // edx 1499 info.extras.syscall = (regs.edx & BIT!(11)) != 0; 1500 info.mem.nx = (regs.edx & BIT!(20)) != 0; 1501 info.mem.page1gb = (regs.edx & BIT!(26)) != 0; 1502 info.extras.rdtscp = (regs.edx & BIT!(27)) != 0; 1503 info.ext.x86_64 = (regs.edx & BIT!(29)) != 0; 1504 1505 if (info.max_ext_leaf < 0x8000_0007) goto L_CACHE_INFO; 1506 1507 // 1508 // Leaf 8000_0007H 1509 // 1510 1511 asmcpuid(regs, 0x8000_0007); 1512 1513 switch (info.vendor_id) { 1514 case Vendor.Intel: 1515 info.extras.rdseed = (regs.ebx & BIT!(28)) != 0; 1516 break; 1517 case Vendor.AMD: 1518 info.acpi.tm = (regs.edx & BIT!(4)) != 0; 1519 info.tech.turboboost = (regs.edx & BIT!(9)) != 0; 1520 break; 1521 default: 1522 } 1523 1524 info.extras.rdtsc_invariant = (regs.edx & BIT!(8)) != 0; 1525 1526 if (info.max_ext_leaf < 0x8000_0008) goto L_CACHE_INFO; 1527 1528 // 1529 // Leaf 8000_0008H 1530 // 1531 1532 asmcpuid(regs, 0x8000_0008); 1533 1534 switch (info.vendor_id) { 1535 case Vendor.Intel: 1536 info.cache.wbnoinvd = (regs.ebx & BIT!(9)) != 0; 1537 break; 1538 case Vendor.AMD: 1539 info.sec.ibpb = (regs.ebx & BIT!(12)) != 0; 1540 info.sec.ibrs = (regs.ebx & BIT!(14)) != 0; 1541 info.sec.stibp = (regs.ebx & BIT!(15)) != 0; 1542 info.sec.ibrs_on = (regs.ebx & BIT!(16)) != 0; 1543 info.sec.stibp_on = (regs.ebx & BIT!(17)) != 0; 1544 info.sec.ibrs_pref = (regs.ebx & BIT!(18)) != 0; 1545 info.sec.ssbd = (regs.ebx & BIT!(24)) != 0; 1546 info.cores.logical = (cast(ubyte)regs.ecx) + 1; 1547 break; 1548 default: 1549 } 1550 1551 info.mem.b_8000_0008_ax = cast(ushort)regs.eax; // info.addr_phys_bits, info.addr_line_bits 1552 1553 if (info.max_ext_leaf < 0x8000_000A) goto L_CACHE_INFO; 1554 1555 // 1556 // Leaf 8000_000AH 1557 // 1558 1559 asmcpuid(regs, 0x8000_000A); 1560 1561 switch (info.vendor_id) { 1562 case Vendor.AMD: 1563 info.virt.version_ = cast(ubyte)regs.eax; // EAX[7:0] 1564 info.virt.apivc = (regs.edx & BIT!(13)) != 0; 1565 break; 1566 default: 1567 } 1568 1569 //if (info.max_ext_leaf < ...) goto L_CACHE_INFO; 1570 1571 L_CACHE_INFO: 1572 // Cache information 1573 // - done at the very end since we may need prior information 1574 // - e.g. amd cpuid.8000_0008h 1575 // - maxleaf < 4 is too old/rare these days (es. for D programs) 1576 1577 //TODO: Maybe do physical cores 1578 1579 info.cache.levels = 0; 1580 CACHEINFO *ca = cast(CACHEINFO*)info.cache.level; 1581 1582 ushort sc = void; /// raw cores shared across cache level 1583 ushort crshrd = void; /// actual count of shared cores 1584 ubyte type = void; 1585 switch (info.vendor_id) { 1586 case Vendor.Intel: 1587 asmcpuid(regs, 4, info.cache.levels); 1588 1589 type = regs.eax & CACHE_MASK; // EAX[4:0] 1590 if (type == 0) break; 1591 if (info.cache.levels >= CACHE_MAX_LEVEL) break; 1592 1593 ca.type = CACHE_TYPE[type]; 1594 ca.level = cast(ubyte)((regs.eax >> 5) & 7); 1595 ca.linesize = cast(ubyte)((regs.ebx & 0x7FF) + 1); 1596 ca.partitions = cast(ubyte)(((regs.ebx >> 12) & 0x7FF) + 1); 1597 ca.ways = cast(ubyte)((regs.ebx >> 22) + 1); 1598 ca.sets = cast(ushort)(regs.ecx + 1); 1599 if (regs.eax & BIT!(8)) ca.feat = 1; 1600 if (regs.eax & BIT!(9)) ca.feat |= BIT!(1); 1601 if (regs.edx & BIT!(0)) ca.feat |= BIT!(2); 1602 if (regs.edx & BIT!(1)) ca.feat |= BIT!(3); 1603 if (regs.edx & BIT!(2)) ca.feat |= BIT!(4); 1604 ca.size = (ca.sets * ca.linesize * ca.partitions * ca.ways) >> 10; 1605 1606 info.cores.logical = (regs.eax >> 26) + 1; // EAX[31:26] 1607 crshrd = (((regs.eax >> 14) & 2047) + 1); // EAX[25:14] 1608 sc = cast(ushort)(info.cores.logical / crshrd); // cast for ldc 0.17.1 1609 ca.sharedCores = sc ? sc : 1; 1610 1611 ++info.cache.levels; ++ca; 1612 goto case Vendor.Intel; 1613 case Vendor.AMD: 1614 if (info.max_ext_leaf < 0x8000_001D) 1615 goto L_CACHE_AMD_LEGACY; 1616 1617 // 1618 // AMD newer cache method 1619 // 1620 1621 L_CACHE_AMD_EXT_1DH: // Almost the same as Intel's 1622 asmcpuid(regs, 0x8000_001D, info.cache.levels); 1623 1624 type = regs.eax & CACHE_MASK; // EAX[4:0] 1625 if (type == 0) break; 1626 if (info.cache.levels >= CACHE_MAX_LEVEL) break; 1627 1628 ca.type = CACHE_TYPE[type]; 1629 ca.level = cast(ubyte)((regs.eax >> 5) & 7); 1630 ca.linesize = cast(ubyte)((regs.ebx & 0x7FF) + 1); 1631 ca.partitions = cast(ubyte)(((regs.ebx >> 12) & 0x7FF) + 1); 1632 ca.ways = cast(ubyte)((regs.ebx >> 22) + 1); 1633 ca.sets = cast(ushort)(regs.ecx + 1); 1634 if (regs.eax & BIT!(8)) ca.feat = 1; 1635 if (regs.eax & BIT!(9)) ca.feat |= BIT!(1); 1636 if (regs.edx & BIT!(0)) ca.feat |= BIT!(2); 1637 if (regs.edx & BIT!(1)) ca.feat |= BIT!(3); 1638 ca.size = (ca.sets * ca.linesize * ca.partitions * ca.ways) >> 10; 1639 1640 crshrd = (((regs.eax >> 14) & 2047) + 1); // EAX[25:14] 1641 sc = cast(ushort)(info.cores.logical / crshrd); // cast for ldc 0.17.1 1642 ca.sharedCores = sc ? sc : 1; 1643 1644 ++info.cache.levels; ++ca; 1645 goto L_CACHE_AMD_EXT_1DH; 1646 1647 // 1648 // AMD legacy cache 1649 // 1650 1651 L_CACHE_AMD_LEGACY: 1652 asmcpuid(regs, 0x8000_0005); 1653 1654 info.cache.level[0].level = 1; // L1 1655 info.cache.level[0].type = 'D'; // data 1656 info.cache.level[0].__bundle1 = regs.ecx; 1657 info.cache.level[0].size = info.cache.level[0]._amdsize; 1658 info.cache.level[1].level = 1; // L1 1659 info.cache.level[1].type = 'I'; // instructions 1660 info.cache.level[1].__bundle1 = regs.edx; 1661 info.cache.level[1].size = info.cache.level[1]._amdsize; 1662 1663 info.cache.levels = 2; 1664 1665 if (info.max_ext_leaf < 0x8000_0006) 1666 break; // No L2/L3 1667 1668 // See Table E-4. L2/L3 Cache and TLB Associativity Field Encoding 1669 static immutable ubyte[16] _amd_cache_ways = [ 1670 // 7h is reserved 1671 // 9h mentions 8000_001D but that's already supported 1672 0, 1, 2, 3, 4, 6, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255 1673 ]; 1674 1675 asmcpuid(regs, 0x8000_0006); 1676 1677 ubyte _amd_ways_l2 = (regs.ecx >> 12) & 15; 1678 if (_amd_ways_l2) { 1679 info.cache.level[2].level = 2; // L2 1680 info.cache.level[2].type = 'U'; // unified 1681 info.cache.level[2].ways = _amd_cache_ways[_amd_ways_l2]; 1682 info.cache.level[2].size = regs.ecx >> 16; 1683 info.cache.level[2].sets = (regs.ecx >> 8) & 7; 1684 info.cache.level[2].linesize = cast(ubyte)regs.ecx; 1685 1686 info.cache.levels = 3; 1687 1688 ubyte _amd_ways_l3 = (regs.edx >> 12) & 15; 1689 if (_amd_ways_l3) { 1690 info.cache.level[3].level = 3; // L3 1691 info.cache.level[3].type = 'U'; // unified 1692 info.cache.level[3].ways = _amd_cache_ways[_amd_ways_l3]; 1693 info.cache.level[3].size = ((regs.edx >> 18) + 1) * 512; 1694 info.cache.level[3].sets = (regs.edx >> 8) & 7; 1695 info.cache.level[3].linesize = cast(ubyte)(regs.edx & 0x7F); 1696 1697 info.cache.levels = 4; 1698 } 1699 } 1700 break; 1701 default: 1702 } 1703 }