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 * getInfo(info); // Fill CPUINFO structure (optional) 11 * --- 12 * 13 * Then checking the corresponding field: 14 * --- 15 * if (info.extensions.amx.xfd) { 16 * // Intel AMX with AMX_XFD is available 17 * } else { 18 * // Feature unavailable 19 * } 20 * --- 21 * 22 * See the CPUINFO structure for available fields. 23 * 24 * To further understand these fields, it's encouraged to consult the technical manual. 25 * 26 * Authors: dd86k (dd@dax.moe) 27 * Copyright: © 2016-2022 dd86k 28 * License: MIT 29 */ 30 module ddcpuid; 31 32 // NOTE: GAS syntax reminder 33 // asm { "asm;\n\t" : "constraint" output : "constraint" input : clobbers } 34 35 @system: 36 extern (C): 37 38 //TODO: Consider ddcpuid_* function prefix since we extern to C 39 40 version (X86) 41 enum DDCPUID_PLATFORM = "i686"; /// Target platform 42 else version (X86_64) 43 enum DDCPUID_PLATFORM = "amd64"; /// Target platform 44 else static assert(0, "Unsupported platform"); 45 46 version (DigitalMars) { 47 version = DMD; // DMD compiler 48 version = DMDLDC; // DMD or LDC compilers 49 } else version (GNU) { 50 version = GDC; // GDC compiler 51 } else version (LDC) { 52 version = DMDLDC; // DMD or LDC compilers 53 } else static assert(0, "Unsupported compiler"); 54 55 enum DDCPUID_VERSION = "0.20.0"; /// Library version 56 private enum CACHE_LEVELS = 6; /// For buffer 57 private enum CACHE_MAX_LEVEL = CACHE_LEVELS - 1; 58 59 version (PrintInfo) { 60 pragma(msg, "CPUINFO.sizeof\t", CPUINFO.sizeof); 61 pragma(msg, "CACHE.sizeof\t", CACHEINFO.sizeof); 62 } 63 64 /// Make a bit mask of one bit at n position 65 private 66 template BIT(int n) if (n <= 31) { enum uint BIT = 1 << n; } 67 68 /// Vendor ID template 69 // Little-endian only, unless x86 gets any crazier 70 private 71 template ID(char[4] c) { 72 enum uint ID = c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24; 73 } 74 75 /// Vendor ID. 76 /// 77 /// The CPUINFO.vendor_id field is set according to the Vendor String. 78 /// They are validated in the getVendor function, so they are safe to use. 79 enum Vendor { 80 Other = 0, 81 Intel = ID!"Genu", /// `"GenuineIntel"`: Intel 82 AMD = ID!"Auth", /// `"AuthenticAMD"`: AMD 83 VIA = ID!"VIA ", /// `"VIA VIA VIA "`: VIA 84 } 85 86 /// Virtual Vendor ID, used as the interface type. 87 /// 88 /// The CPUINFO.virt.vendor_id field is set according to the Vendor String. 89 /// They are validated in the getVendor function, so they are safe to use. 90 /// The VBoxHyperV ID will be adjusted for HyperV since it's the same interface, 91 /// but simply a different implementation. 92 // NOTE: bhyve doesn't not emit cpuid bits within 0x40000000, so not supported 93 enum VirtVendor { 94 Other = 0, 95 KVM = ID!"KVMK", /// `"KVMKVMKVM\0\0\0"`: KVM 96 HyperV = ID!"Micr", /// `"Microsoft Hv"`: Hyper-V interface 97 VBoxHyperV = ID!"VBox", /// `"VBoxVBoxVBox"`: VirtualBox's Hyper-V interface 98 VBoxMin = 0, /// Unset: VirtualBox minimal interface 99 } 100 101 /// Registers structure used with the ddcpuid function. 102 struct REGISTERS { 103 union { 104 uint eax; 105 ushort ax; 106 struct { ubyte al, ah; } 107 } 108 union { 109 uint ebx; 110 ushort bx; 111 struct { ubyte bl, bh; } 112 } 113 union { 114 uint ecx; 115 ushort cx; 116 struct { ubyte cl, ch; } 117 } 118 union { 119 uint edx; 120 ushort dx; 121 struct { ubyte dl, dh; } 122 } 123 } 124 /// 125 @system unittest { 126 REGISTERS regs = void; 127 regs.eax = 0xaabbccdd; 128 assert(regs.eax == 0xaabbccdd); 129 assert(regs.ax == 0xccdd); 130 assert(regs.al == 0xdd); 131 assert(regs.ah == 0xcc); 132 } 133 134 /// CPU cache entry 135 struct CACHEINFO { align(1): 136 this(ubyte level_, char type_, uint kbsize_, ushort shared_, 137 ushort ways_, ushort parts_, ushort lineSize_, uint sets_) { 138 level = level_; 139 type = type_; 140 size = kbsize_; 141 sharedCores = shared_; 142 ways = ways_; 143 partitions = parts_; 144 lineSize = lineSize_; 145 sets = sets_; 146 features = 0; 147 } 148 //TODO: Sort fields (totalSize, coresShared, ways, partitions, lineSize, sets) 149 ushort lineSize; /// Size of the line in bytes. 150 union { 151 ushort partitions; /// Number of partitions. 152 ushort lines; /// Legacy name of partitions. 153 } 154 ushort ways; /// Number of ways per line. 155 uint sets; /// Number of cache sets. (Entries) 156 /// Cache size in kilobytes. 157 // (Ways + 1) * (Partitions + 1) * (LineSize + 1) * (Sets + 1) 158 // (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1) 159 uint size; 160 /// Number of CPU cores sharing this cache. 161 ushort sharedCores; 162 /// Cache feature, bit flags. 163 /// - Bit 0: Self Initializing cache 164 /// - Bit 1: Fully Associative cache 165 /// - Bit 2: No Write-Back Invalidation (toggle) 166 /// - Bit 3: Cache Inclusiveness (toggle) 167 /// - Bit 4: Complex Cache Indexing (toggle) 168 ushort features; 169 ubyte level; /// Cache level: L1, L2, etc. 170 char type = 0; /// Type entry character: 'D'=Data, 'I'=Instructions, 'U'=Unified 171 } 172 173 struct VendorString { align(1): 174 union { 175 struct { uint ebx, edx, ecx; } 176 char[12] string_; 177 } 178 Vendor id; /// Validated vendor ID 179 } 180 181 @system unittest { 182 VendorString s; 183 s.string_ = "AuthenticAMD"; 184 assert(s.ebx == ID!"Auth"); 185 assert(s.edx == ID!"enti"); 186 assert(s.ecx == ID!"cAMD"); 187 } 188 189 struct VirtVendorString { align(1): 190 union { 191 struct { uint ebx, ecx, edx; } 192 char[12] string_; 193 } 194 VirtVendor id; /// Validated vendor ID 195 } 196 197 @system unittest { 198 VirtVendorString s; 199 s.string_ = "AuthenticAMD"; 200 assert(s.ebx == ID!"Auth"); 201 assert(s.ecx == ID!"enti"); 202 assert(s.edx == ID!"cAMD"); 203 } 204 205 /// CPU information structure 206 struct CPUINFO { align(1): 207 uint maxLeaf; /// Highest cpuid leaf 208 uint maxLeafVirt; /// Highest cpuid virtualization leaf 209 uint maxLeafExtended; /// Highest cpuid extended leaf 210 211 // Vendor/brand strings 212 213 VendorString vendor; 214 215 union { 216 private uint[12] brand32; // For init only 217 char[48] brandString; /// Processor Brand String 218 } 219 ubyte brandIndex; /// Brand string index 220 221 // Core 222 223 /// Contains the information on the number of cores. 224 struct Cores { 225 ushort logical; /// Logical cores in this processor 226 ushort physical; /// Physical cores in this processor 227 } 228 align(2) Cores cores; /// Processor package cores 229 230 // Identifier 231 232 uint identifier; /// Raw identifier (CPUID.01h.EAX) 233 ushort family; /// Effective family identifier 234 ushort model; /// Effective model identifier 235 // const(char) *microArchitecture; /// Microarchitecture name string 236 ubyte familyBase; /// Base family identifier 237 ubyte familyExtended; /// Extended family identifier 238 ubyte modelBase; /// Base model identifier 239 ubyte modelExtended; /// Extended model identifier 240 ubyte stepping; /// Stepping revision 241 ubyte type; /// Processor type number 242 const(char) *typeString; /// Processor type string. 243 244 /// Contains processor extensions. 245 /// Extensions contain a variety of instructions to aid particular 246 /// tasks. 247 struct Extensions { 248 bool fpu; /// On-Chip x87 FPU 249 bool f16c; /// Float16 Conversions 250 bool mmx; /// MMX 251 bool mmxExtended; /// MMX Extended 252 bool _3DNow; /// 3DNow! 253 bool _3DNowExtended; /// 3DNow! Extended 254 bool aes_ni; /// Advanced Encryption Standard New Instructions 255 bool sha; /// SHA-1 256 bool fma3; /// Fused Multiply-Add 257 bool fma4; /// FMA4 258 bool bmi1; /// BMI1 259 bool bmi2; /// BMI2 260 bool x86_64; /// 64-bit mode (Long mode) 261 bool lahf64; /// LAHF+SAHF in 64-bit mode 262 bool waitpkg; /// User Level Monitor Wait (UMWAIT) 263 bool xop; /// AMD eXtended OPerations 264 bool tbm; /// Trailing Bit Manipulation 265 bool adx; /// Multi-precision Add-Carry (ADCX+ADOX) 266 } 267 align(2) Extensions extensions; /// Extensions 268 269 struct SSE { 270 bool sse; /// Streaming SIMD Extensions 271 bool sse2; /// SSE2 272 bool sse3; /// SSE3 273 bool ssse3; /// SSSE3 274 bool sse41; /// SSE4.1 275 bool sse42; /// SSE4.2 276 bool sse4a; /// SSE4a 277 } 278 align(2) SSE sse; /// Streaming SIMD Extensions 279 280 struct AVX { 281 bool avx; /// Advanced Vector eXtension 282 bool avx2; /// AVX2 283 bool avx512f; /// AVX512 284 bool avx512er; /// AVX512_ER 285 bool avx512pf; /// AVX512_PF 286 bool avx512cd; /// AVX512_CD 287 bool avx512dq; /// AVX512_DQ 288 bool avx512bw; /// AVX512_BW 289 bool avx512vl; /// AVX512_VL 290 bool avx512_ifma; /// AVX512_IFMA 291 bool avx512_vbmi; /// AVX512_VBMI 292 bool avx512_vbmi2; /// AVX512_VBMI2 293 bool avx512_gfni; /// AVX512_GFNI 294 bool avx512_vaes; /// AVX512_VAES 295 bool avx512_vnni; /// AVX512_VNNI 296 bool avx512_bitalg; /// AVX512_BITALG 297 bool avx512_vpopcntdq; /// AVX512_VPOPCNTDQ 298 bool avx512_4vnniw; /// AVX512_4VNNIW 299 bool avx512_4fmaps; /// AVX512_4FMAPS 300 bool avx512_bf16; /// AVX512_BF16 301 bool avx512_vp2intersect; /// AVX512_VP2INTERSECT 302 } 303 align(2) AVX avx; /// Advanced Vector eXtension 304 305 struct AMX { 306 bool enabled; /// Advanced Matrix eXtension 307 bool bf16; /// AMX_BF16 308 bool int8; /// AMX_INT8 309 bool xtilecfg; /// AMX_XTILECFG 310 bool xtiledata; /// AMX_XTILEDATA 311 bool xfd; /// AMX_XFD 312 } 313 align(2) AMX amx; /// Intel AMX 314 315 struct SGX { 316 bool supported; /// If SGX is supported (and enabled) 317 bool sgx1; /// SGX1 318 bool sgx2; /// SGX2 319 ubyte maxSize; /// 2^n maximum enclave size in non-64-bit 320 ubyte maxSize64; /// 2^n maximum enclave size in 64-bit 321 } 322 align(2) SGX sgx; /// Intel SGX 323 324 /// Additional instructions. Often not part of extensions. 325 struct Extras { 326 bool pclmulqdq; /// PCLMULQDQ instruction 327 bool monitor; /// MONITOR and MWAIT instructions 328 ushort mwaitMin; /// (With MONITOR+MWAIT) MWAIT minimum size in bytes 329 ushort mwaitMax; /// (With MONITOR+MWAIT) MWAIT maximum size in bytes 330 bool cmpxchg8b; /// CMPXCHG8B 331 bool cmpxchg16b; /// CMPXCHG16B instruction 332 bool movbe; /// MOVBE instruction 333 bool rdrand; /// RDRAND instruction 334 bool rdseed; /// RDSEED instruction 335 bool rdmsr; /// RDMSR instruction 336 bool sysenter; /// SYSENTER and SYSEXIT instructions 337 bool rdtsc; /// RDTSC instruction 338 bool rdtscDeadline; /// (With RDTSC) IA32_TSC_DEADLINE MSR 339 bool rdtscInvariant; /// (With RDTSC) Timestamp counter invariant of C/P/T-state 340 bool rdtscp; /// RDTSCP instruction 341 bool rdpid; /// RDPID instruction 342 bool cmov; /// CMOVcc instruction 343 bool lzcnt; /// LZCNT instruction 344 bool popcnt; /// POPCNT instruction 345 bool xsave; /// XSAVE and XRSTOR instructions 346 bool osxsave; /// OSXSAVE and XGETBV instructions 347 bool fxsr; /// FXSAVE and FXRSTOR instructions 348 bool pconfig; /// PCONFIG instruction 349 bool cldemote; /// CLDEMOTE instruction 350 bool movdiri; /// MOVDIRI instruction 351 bool movdir64b; /// MOVDIR64B instruction 352 bool enqcmd; /// ENQCMD instruction 353 bool syscall; /// SYSCALL and SYSRET instructions 354 bool monitorx; /// MONITORX and MWAITX instructions 355 bool skinit; /// SKINIT instruction 356 bool serialize; /// SERIALIZE instruction 357 } 358 align(2) Extras extras; /// Additional instructions 359 360 /// Processor technologies. 361 struct Technologies { 362 bool eist; /// Intel SpeedStep/AMD PowerNow/AMD Cool'n'Quiet 363 bool turboboost; /// Intel TurboBoost/AMD CorePerformanceBoost 364 bool turboboost30; /// Intel TurboBoost 3.0 365 bool smx; /// Intel TXT 366 bool htt; /// (HTT) HyperThreading Technology 367 } 368 align(2) Technologies tech; /// Processor technologies 369 370 /// Cache information. 371 struct CacheInfo { 372 uint levels; 373 CACHEINFO[CACHE_LEVELS] level; 374 bool clflush; /// CLFLUSH instruction 375 ubyte clflushLinesize; /// Linesize of CLFLUSH in bytes 376 bool clflushopt; /// CLFLUSH instruction 377 bool cnxtId; /// L1 Context ID 378 bool ss; /// SelfSnoop 379 bool prefetchw; /// PREFETCHW instruction 380 bool invpcid; /// INVPCID instruction 381 bool wbnoinvd; /// WBNOINVD instruction 382 } 383 align(2) CacheInfo cache; /// Cache information 384 385 /// ACPI information. 386 struct SysInfo { 387 bool available; /// ACPI 388 bool apic; /// APIC 389 bool x2apic; /// x2APIC 390 bool arat; /// Always-Running-APIC-Timer 391 bool tm; /// Thermal Monitor 392 bool tm2; /// Thermal Monitor 2 393 ubyte maxApicId; /// Maximum APIC ID 394 ubyte apicId; /// Initial APIC ID (running core where CPUID was called) 395 } 396 align(2) SysInfo sys; /// System features 397 398 /// Virtualization features. If a paravirtual interface is available, 399 /// its information will be found here. 400 struct Virtualization { 401 bool available; /// Intel VT-x/AMD-V 402 ubyte version_; /// (AMD) Virtualization platform version 403 bool vme; /// Enhanced vm8086 404 bool apicv; /// (AMD) APICv. Intel's is available via a MSR. 405 VirtVendorString vendor; 406 407 struct VBox { 408 uint tsc_freq_khz; /// (VBox) Timestamp counter frequency in KHz 409 uint apic_freq_khz; /// (VBox) Paravirtualization API KHz frequency 410 } 411 VBox vbox; 412 413 struct KVM { 414 bool feature_clocksource; /// (KVM) kvmclock interface 415 bool feature_nop_io_delay; /// (KVM) No delays required on I/O operations 416 bool feature_mmu_op; /// (KVM) Deprecated 417 bool feature_clocksource2; /// (KVM) Remapped kvmclock interface 418 bool feature_async_pf; /// (KVM) Asynchronous Page Fault 419 bool feature_steal_time; /// (KVM) Steal time 420 bool feature_pv_eoi; /// (KVM) Paravirtualized End Of the Interrupt handler 421 bool feature_pv_unhault; /// (KVM) Paravirtualized spinlock 422 bool feature_pv_tlb_flush; /// (KVM) Paravirtualized TLB flush 423 bool feature_async_pf_vmexit; /// (KVM) Asynchronous Page Fault at VM exit 424 bool feature_pv_send_ipi; /// (KVM) Paravirtualized SEBD inter-processor-interrupt 425 bool feature_pv_poll_control; /// (KVM) Host-side polling on HLT 426 bool feature_pv_sched_yield; /// (KVM) paravirtualized scheduler yield 427 bool feature_clocsource_stable_bit; /// (KVM) kvmclock warning 428 bool hint_realtime; /// (KVM) vCPUs are never preempted for an unlimited amount of time 429 } 430 KVM kvm; 431 432 struct HyperV { 433 ushort guest_vendor_id; /// (Hyper-V) Paravirtualization Guest Vendor ID 434 ushort guest_build; /// (Hyper-V) Paravirtualization Guest Build number 435 ubyte guest_os; /// (Hyper-V) Paravirtualization Guest OS ID 436 ubyte guest_major; /// (Hyper-V) Paravirtualization Guest OS Major version 437 ubyte guest_minor; /// (Hyper-V) Paravirtualization Guest OS Minor version 438 ubyte guest_service; /// (Hyper-V) Paravirtualization Guest Service ID 439 bool guest_opensource; /// (Hyper-V) Paravirtualization Guest additions open-source 440 bool base_feat_vp_runtime_msr; /// (Hyper-V) Virtual processor runtime MSR 441 bool base_feat_part_time_ref_count_msr; /// (Hyper-V) Partition reference counter MSR 442 bool base_feat_basic_synic_msrs; /// (Hyper-V) Basic Synthetic Interrupt Controller MSRs 443 bool base_feat_stimer_msrs; /// (Hyper-V) Synthetic Timer MSRs 444 bool base_feat_apic_access_msrs; /// (Hyper-V) APIC access MSRs (EOI, ICR, TPR) 445 bool base_feat_hypercall_msrs; /// (Hyper-V) Hypercalls API MSRs 446 bool base_feat_vp_id_msr; /// (Hyper-V) vCPU index MSR 447 bool base_feat_virt_sys_reset_msr; /// (Hyper-V) Virtual system reset MSR 448 bool base_feat_stat_pages_msr; /// (Hyper-V) Statistic pages MSRs 449 bool base_feat_part_ref_tsc_msr; /// (Hyper-V) Partition reference timestamp counter MSR 450 bool base_feat_guest_idle_state_msr; /// (Hyper-V) Virtual guest idle state MSR 451 bool base_feat_timer_freq_msrs; /// (Hyper-V) Timer frequency MSRs (TSC and APIC) 452 bool base_feat_debug_msrs; /// (Hyper-V) Debug MSRs 453 bool part_flags_create_part; /// (Hyper-V) Partitions can be created 454 bool part_flags_access_part_id; /// (Hyper-V) Partitions IDs can be accessed 455 bool part_flags_access_memory_pool; /// (Hyper-V) Memory pool can be accessed 456 bool part_flags_adjust_msg_buffers; /// (Hyper-V) Possible to adjust message buffers 457 bool part_flags_post_msgs; /// (Hyper-V) Possible to send messages 458 bool part_flags_signal_events; /// (Hyper-V) Possible to signal events 459 bool part_flags_create_port; /// (Hyper-V) Possible to create ports 460 bool part_flags_connect_port; /// (Hyper-V) Possible to connect to ports 461 bool part_flags_access_stats; /// (Hyper-V) Can access statistics 462 bool part_flags_debugging; /// (Hyper-V) Debugging features available 463 bool part_flags_cpu_mgmt; /// (Hyper-V) Processor management available 464 bool part_flags_cpu_profiler; /// (Hyper-V) Processor profiler available 465 bool part_flags_expanded_stack_walk; /// (Hyper-V) Extended stack walking available 466 bool part_flags_access_vsm; /// (Hyper-V) Virtual system monitor available 467 bool part_flags_access_vp_regs; /// (Hyper-V) Virtual private registers available 468 bool part_flags_extended_hypercalls; /// (Hyper-V) Extended hypercalls API available 469 bool part_flags_start_vp; /// (Hyper-V) Virtual processor has started 470 bool pm_max_cpu_power_state_c0; /// (Hyper-V) Processor C0 is maximum state 471 bool pm_max_cpu_power_state_c1; /// (Hyper-V) Processor C1 is maximum state 472 bool pm_max_cpu_power_state_c2; /// (Hyper-V) Processor C2 is maximum state 473 bool pm_max_cpu_power_state_c3; /// (Hyper-V) Processor C3 is maximum state 474 bool pm_hpet_reqd_for_c3; /// (Hyper-V) High-precision event timer required for C3 state 475 bool misc_feat_mwait; /// (Hyper-V) MWAIT instruction available for guest 476 bool misc_feat_guest_debugging; /// (Hyper-V) Guest supports debugging 477 bool misc_feat_perf_mon; /// (Hyper-V) Performance monitor support available 478 bool misc_feat_pcpu_dyn_part_event; /// (Hyper-V) Physicap CPU dynamic partitioning event available 479 bool misc_feat_xmm_hypercall_input; /// (Hyper-V) Hypercalls via XMM registers available 480 bool misc_feat_guest_idle_state; /// (Hyper-V) Virtual guest supports idle state 481 bool misc_feat_hypervisor_sleep_state; /// (Hyper-V) Hypervisor supports sleep 482 bool misc_feat_query_numa_distance; /// (Hyper-V) NUMA distance query available 483 bool misc_feat_timer_freq; /// (Hyper-V) Determining timer frequencies available 484 bool misc_feat_inject_synmc_xcpt; /// (Hyper-V) Support for injecting synthetic machine checks 485 bool misc_feat_guest_crash_msrs; /// (Hyper-V) Guest crash MSR available 486 bool misc_feat_debug_msrs; /// (Hyper-V) Debug MSR available 487 bool misc_feat_npiep1; /// (Hyper-V) Documentation unavailable 488 bool misc_feat_disable_hypervisor; /// (Hyper-V) Hypervisor can be disabled 489 bool misc_feat_ext_gva_range_for_flush_va_list; /// (Hyper-V) Extended guest virtual address (GVA) ranges for FlushVirtualAddressList available 490 bool misc_feat_hypercall_output_xmm; /// (Hyper-V) Returning hypercall output via XMM registers available 491 bool misc_feat_sint_polling_mode; /// (Hyper-V) Synthetic interrupt source polling mode available 492 bool misc_feat_hypercall_msr_lock; /// (Hyper-V) Hypercall MISR lock feature available 493 bool misc_feat_use_direct_synth_msrs; /// (Hyper-V) Possible to directly use synthetic MSRs 494 bool hint_hypercall_for_process_switch; /// (Hyper-V) Guest should use the Hypercall API for address space switches rather than MOV CR3 495 bool hint_hypercall_for_tlb_flush; /// (Hyper-V) Guest should use the Hypercall API for local TLB flushes rather than INVLPG/MOV CR3 496 bool hint_hypercall_for_tlb_shootdown; /// (Hyper-V) Guest should use the Hypercall API for inter-CPU TLB flushes rather than inter-processor-interrupts (IPI) 497 bool 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) 498 bool hint_msr_for_sys_reset; /// (Hyper-V) Guest should use the hypervisor-provided MSR for a system reset instead of traditional methods 499 bool hint_relax_time_checks; /// (Hyper-V) Guest should relax timer-related checks (watchdogs/deadman timeouts) that rely on timely deliver of external interrupts 500 bool hint_dma_remapping; /// (Hyper-V) Guest should use the direct memory access (DMA) remapping 501 bool hint_interrupt_remapping; /// (Hyper-V) Guest should use the interrupt remapping 502 bool hint_x2apic_msrs; /// (Hyper-V) Guest should use the X2APIC MSRs rather than memory mapped input/output (MMIO) 503 bool hint_deprecate_auto_eoi; /// (Hyper-V) Guest should deprecate Auto EOI (End Of Interrupt) features 504 bool hint_synth_cluster_ipi_hypercall; /// (Hyper-V) Guest should use the SyntheticClusterIpi Hypercall 505 bool hint_ex_proc_masks_interface; /// (Hyper-V) Guest should use the newer ExProcessMasks interface over ProcessMasks 506 bool hint_nested_hyperv; /// (Hyper-V) Hyper-V instance is nested within a Hyper-V partition 507 bool hint_int_for_mbec_syscalls; /// (Hyper-V) Guest should use the INT instruction for Mode Based Execution Control (MBEC) system calls 508 bool hint_nested_enlightened_vmcs_interface; /// (Hyper-V) Guest should use enlightened Virtual Machine Control Structure (VMCS) interfaces and nested enlightenment 509 bool host_feat_avic; /// (Hyper-V) Hypervisor is using the Advanced Virtual Interrupt Controller (AVIC) overlay 510 bool host_feat_msr_bitmap; /// (Hyper-V) Hypervisor is using MSR bitmaps 511 bool host_feat_perf_counter; /// (Hyper-V) Hypervisor supports the architectural performance counter 512 bool host_feat_nested_paging; /// (Hyper-V) Hypervisor is using nested paging 513 bool host_feat_dma_remapping; /// (Hyper-V) Hypervisor is using direct memory access (DMA) remapping 514 bool host_feat_interrupt_remapping; /// (Hyper-V) Hypervisor is using interrupt remapping 515 bool host_feat_mem_patrol_scrubber; /// (Hyper-V) Hypervisor's memory patrol scrubber is present 516 bool host_feat_dma_prot_in_use; /// (Hyper-V) Hypervisor is using direct memory access (DMA) protection 517 bool host_feat_hpet_requested; /// (Hyper-V) Hypervisor requires a High Precision Event Timer (HPET) 518 bool host_feat_stimer_volatile; /// (Hyper-V) Hypervisor's synthetic timers are volatile 519 } 520 HyperV hv; 521 } 522 align(2) Virtualization virt; /// Virtualization features 523 524 /// Memory features. 525 struct Memory { 526 bool pae; /// Physical Address Extension 527 bool pse; /// Page Size Extension 528 bool pse36; /// 36-bit PSE 529 bool page1gb; /// 1GiB pages in 4-level paging and higher 530 bool mtrr; /// Memory Type Range Registers 531 bool pat; /// Page Attribute Table 532 bool pge; /// Page Global Bit 533 bool dca; /// Direct Cache Access 534 bool nx; /// Intel XD (No eXecute bit) 535 union { 536 uint tsx; /// Intel TSX. If set, has one of HLE, RTM, or TSXLDTRK. 537 struct { 538 bool hle; /// (TSX) Hardware Lock Elision 539 bool rtm; /// (TSX) Restricted Transactional Memory 540 bool tsxldtrk; /// (TSX) Suspend Load Address Tracking 541 } 542 } 543 bool smep; /// Supervisor Mode Execution Protection 544 bool smap; /// Supervisor Mode Access Protection 545 bool pku; /// Protection Key Units 546 bool _5pl; /// 5-level paging 547 bool fsrepmov; /// Fast Short REP MOVSB optimization 548 bool lam; /// Linear Address Masking 549 ubyte physBits; /// Memory physical bits 550 ubyte lineBits; /// Memory linear bits 551 } 552 align (2) Memory memory; /// Memory features 553 554 /// Debugging features. 555 struct Debugging { 556 bool mca; /// Machine Check Architecture 557 bool mce; /// Machine Check Exception 558 bool de; /// Degging Extensions 559 bool ds; /// Debug Store 560 bool ds_cpl; /// Debug Store for Current Privilege Level 561 bool dtes64; /// 64-bit Debug Store area 562 bool pdcm; /// Perfmon And Debug Capability 563 bool sdbg; /// Silicon Debug 564 bool pbe; /// Pending Break Enable 565 } 566 align(2) Debugging debugging; /// Debugging feature 567 568 /// Security features and mitigations. 569 struct Security { 570 bool ia32_arch_capabilities; /// IA32_ARCH_CAPABILITIES MSR 571 // NOTE: IA32_CORE_CAPABILITIES is currently empty 572 bool ibpb; /// Indirect Branch Predictor Barrier 573 bool ibrs; /// Indirect Branch Restricted Speculation 574 bool ibrsAlwaysOn; /// IBRS always enabled 575 bool ibrsPreferred; /// IBRS preferred over software solution 576 bool stibp; /// Single Thread Indirect Branch Predictors 577 bool stibpAlwaysOn; /// STIBP always enabled 578 bool ssbd; /// Speculative Store Bypass Disable 579 bool l1dFlush; /// L1D Cache Flush 580 bool md_clear; /// MDS mitigation 581 bool cetIbt; /// (Control-flow Enforcement Technology) Indirect Branch Tracking 582 bool cetSs; /// (Control-flow Enforcement Technology) Shadow Stack 583 } 584 align(2) Security security; /// Security features 585 586 /// Miscellaneous features. 587 struct Miscellaneous { 588 bool psn; /// Processor Serial Number (Pentium III only) 589 bool pcid; /// PCID 590 bool xtpr; /// xTPR 591 bool fsgsbase; /// FS and GS register base 592 bool uintr; /// User Interrupts 593 } 594 align(2) Miscellaneous misc; /// Miscellaneous features 595 } 596 597 // EAX[4:0], 0-31, but there aren't that many 598 // So we limit it to 0-7 599 private enum CACHE_MASK = 7; // Max 31 600 private immutable const(char)* CACHE_TYPE = "?DIU????"; 601 602 private 603 immutable const(char)*[4] PROCESSOR_TYPE = [ "Original", "OverDrive", "Dual", "Reserved" ]; 604 605 version (Trace) { 606 import core.stdc.stdio; 607 import core.stdc.stdarg; 608 609 private extern (C) int putchar(int); 610 611 /// Trace application 612 void trace(string func = __FUNCTION__)(const(char) *fmt, ...) { 613 va_list va; 614 va_start(va, fmt); 615 printf("TRACE:%s: ", func.ptr); 616 vprintf(fmt, va); 617 putchar('\n'); 618 } 619 } 620 621 /// Test if a bit is set. 622 /// Params: 623 /// val = 32-bit content. 624 /// pos = Bit position 625 /// Returns: True if bit set. 626 pragma(inline, true) 627 private bool bit(uint val, int pos) pure @safe { 628 return (val & (1 << pos)) != 0; 629 } 630 631 @safe unittest { 632 assert(bit(2, 1)); // bit 1 of 2 is set (2[1], so 0b11[1]) 633 } 634 635 /// Query processor with CPUID. 636 /// Params: 637 /// regs = REGISTERS structure 638 /// level = Leaf (EAX) 639 /// sublevel = Sub-leaf (ECX) 640 pragma(inline, false) 641 void ddcpuid_id(ref REGISTERS regs, uint level, uint sublevel = 0) { 642 version (DMD) { 643 version (X86) asm { 644 mov EDI, regs; 645 mov EAX, level; 646 mov ECX, sublevel; 647 cpuid; 648 mov [EDI + regs.eax.offsetof], EAX; 649 mov [EDI + regs.ebx.offsetof], EBX; 650 mov [EDI + regs.ecx.offsetof], ECX; 651 mov [EDI + regs.edx.offsetof], EDX; 652 } else version (X86_64) asm { 653 mov RDI, regs; 654 mov EAX, level; 655 mov ECX, sublevel; 656 cpuid; 657 mov [RDI + regs.eax.offsetof], EAX; 658 mov [RDI + regs.ebx.offsetof], EBX; 659 mov [RDI + regs.ecx.offsetof], ECX; 660 mov [RDI + regs.edx.offsetof], EDX; 661 } 662 } else version (GDC) { 663 asm { 664 "cpuid" 665 : "=a" (regs.eax), "=b" (regs.ebx), "=c" (regs.ecx), "=d" (regs.edx) 666 : "a" (level), "c" (sublevel); 667 } 668 } else version (LDC) { 669 version (X86) asm { 670 lea EDI, regs; 671 mov EAX, level; 672 mov ECX, sublevel; 673 cpuid; 674 mov [EDI + regs.eax.offsetof], EAX; 675 mov [EDI + regs.ebx.offsetof], EBX; 676 mov [EDI + regs.ecx.offsetof], ECX; 677 mov [EDI + regs.edx.offsetof], EDX; 678 } else version (X86_64) asm { 679 lea RDI, regs; 680 mov EAX, level; 681 mov ECX, sublevel; 682 cpuid; 683 mov [RDI + regs.eax.offsetof], EAX; 684 mov [RDI + regs.ebx.offsetof], EBX; 685 mov [RDI + regs.ecx.offsetof], ECX; 686 mov [RDI + regs.edx.offsetof], EDX; 687 } 688 } 689 version (Trace) with (regs) trace( 690 "level=%x sub=%x -> eax=%x ebx=%x ecx=%x edx=%x", 691 level, sublevel, eax, ebx, ecx, edx); 692 } 693 /// Typically these tests are done on Pentium 4 and later processors 694 @system unittest { 695 REGISTERS regs; 696 ddcpuid_id(regs, 0); 697 assert(regs.eax > 0 && regs.eax < 0x4000_0000); 698 ddcpuid_id(regs, 0x8000_0000); 699 assert(regs.eax > 0x8000_0000); 700 } 701 702 private uint ddcpuid_max_leaf() { 703 version (DMDLDC) { 704 asm { 705 xor EAX,EAX; 706 cpuid; 707 } 708 } else version (GDC) { 709 asm { 710 "xor %eax,%eax\t\n"~ 711 "cpuid"; 712 } 713 } 714 } 715 716 private uint ddcpuid_max_leaf_virt() { 717 version (DMDLDC) { 718 asm { 719 mov EAX,0x4000_0000; 720 cpuid; 721 } 722 } else version (GDC) { 723 asm { 724 "mov 0x40000000,%eax\t\n"~ 725 "cpuid"; 726 } 727 } 728 } 729 730 private uint ddcpuid_max_leaf_ext() { 731 version (DMDLDC) { 732 asm { 733 mov EAX,0x8000_0000; 734 cpuid; 735 } 736 } else version (GDC) { 737 asm { 738 "mov 0x80000000,%eax\t\n"~ 739 "cpuid"; 740 } 741 } 742 } 743 744 /// Get CPU leaf levels. 745 /// Params: info = CPUINFO structure 746 pragma(inline, false) 747 void ddcpuid_leaves(ref CPUINFO info) { 748 info.maxLeaf = ddcpuid_max_leaf; 749 info.maxLeafVirt = ddcpuid_max_leaf_virt; 750 info.maxLeafExtended = ddcpuid_max_leaf_ext; 751 } 752 753 pragma(inline, false) 754 private 755 void ddcpuid_vendor(ref char[12] string_) { 756 version (DMD) { 757 version (X86) asm { 758 mov EDI, string_; 759 mov EAX, 0; 760 cpuid; 761 mov [EDI], EBX; 762 mov [EDI + 4], EDX; 763 mov [EDI + 8], ECX; 764 } else asm { // x86-64 765 mov RDI, string_; 766 mov EAX, 0; 767 cpuid; 768 mov [RDI], EBX; 769 mov [RDI + 4], EDX; 770 mov [RDI + 8], ECX; 771 } 772 } else version (GDC) { 773 version (X86) asm { 774 "lea %0, %%edi\n\t"~ 775 "mov $0, %%eax\n\t"~ 776 "cpuid\n"~ 777 "mov %%ebx, (%%edi)\n\t"~ 778 "mov %%edx, 4(%%edi)\n\t"~ 779 "mov %%ecx, 8(%%edi)" 780 : 781 : "m" (string_) 782 : "edi", "eax", "ebx", "ecx", "edx"; 783 } else asm { // x86-64 784 "lea %0, %%rdi\n\t"~ 785 "mov $0, %%eax\n\t"~ 786 "cpuid\n"~ 787 "mov %%ebx, (%%rdi)\n\t"~ 788 "mov %%edx, 4(%%rdi)\n\t"~ 789 "mov %%ecx, 8(%%rdi)" 790 : 791 : "m" (string_) 792 : "rdi", "rax", "rbx", "rcx", "rdx"; 793 } 794 } else version (LDC) { 795 version (X86) asm { 796 lea EDI, string_; 797 mov EAX, 0; 798 cpuid; 799 mov [EDI], EBX; 800 mov [EDI + 4], EDX; 801 mov [EDI + 8], ECX; 802 } else asm { // x86-64 803 lea RDI, string_; 804 mov EAX, 0; 805 cpuid; 806 mov [RDI], EBX; 807 mov [RDI + 4], EDX; 808 mov [RDI + 8], ECX; 809 } 810 } 811 } 812 813 private 814 Vendor ddcpuid_vendor_id(ref VendorString vendor) { 815 // Vendor string verification 816 // If the rest of the string doesn't correspond, the id is unset 817 switch (vendor.ebx) with (Vendor) { 818 case Intel: // "GenuineIntel" 819 if (vendor.edx != ID!("ineI")) break; 820 if (vendor.ecx != ID!("ntel")) break; 821 return Vendor.Intel; 822 case AMD: // "AuthenticAMD" 823 if (vendor.edx != ID!("enti")) break; 824 if (vendor.ecx != ID!("cAMD")) break; 825 return Vendor.AMD; 826 case VIA: // "VIA VIA VIA " 827 if (vendor.edx != ID!("VIA ")) break; 828 if (vendor.ecx != ID!("VIA ")) break; 829 return Vendor.VIA; 830 default: // Unknown 831 } 832 return Vendor.Other; 833 } 834 835 pragma(inline, false) 836 private 837 void ddcpuid_extended_brand(ref char[48] string_) { 838 version (DMD) { 839 version (X86) asm { 840 mov EDI, string_; 841 mov EAX, 0x8000_0002; 842 cpuid; 843 mov [EDI], EAX; 844 mov [EDI + 4], EBX; 845 mov [EDI + 8], ECX; 846 mov [EDI + 12], EDX; 847 mov EAX, 0x8000_0003; 848 cpuid; 849 mov [EDI + 16], EAX; 850 mov [EDI + 20], EBX; 851 mov [EDI + 24], ECX; 852 mov [EDI + 28], EDX; 853 mov EAX, 0x8000_0004; 854 cpuid; 855 mov [EDI + 32], EAX; 856 mov [EDI + 36], EBX; 857 mov [EDI + 40], ECX; 858 mov [EDI + 44], EDX; 859 } else version (X86_64) asm { 860 mov RDI, string_; 861 mov EAX, 0x8000_0002; 862 cpuid; 863 mov [RDI], EAX; 864 mov [RDI + 4], EBX; 865 mov [RDI + 8], ECX; 866 mov [RDI + 12], EDX; 867 mov EAX, 0x8000_0003; 868 cpuid; 869 mov [RDI + 16], EAX; 870 mov [RDI + 20], EBX; 871 mov [RDI + 24], ECX; 872 mov [RDI + 28], EDX; 873 mov EAX, 0x8000_0004; 874 cpuid; 875 mov [RDI + 32], EAX; 876 mov [RDI + 36], EBX; 877 mov [RDI + 40], ECX; 878 mov [RDI + 44], EDX; 879 } 880 } else version (GDC) { 881 version (X86) asm { 882 "lea %0, %%edi\n\t"~ 883 "mov $0x80000002, %%eax\n\t"~ 884 "cpuid\n\t"~ 885 "mov %%eax, (%%rdi)\n\t"~ 886 "mov %%ebx, 4(%%rdi)\n\t"~ 887 "mov %%ecx, 8(%%rdi)\n\t"~ 888 "mov %%edx, 12(%%rdi)\n\t"~ 889 "mov $0x80000003, %%eax\n\t"~ 890 "cpuid\n\t"~ 891 "mov %%eax, 16(%%rdi)\n\t"~ 892 "mov %%ebx, 20(%%rdi)\n\t"~ 893 "mov %%ecx, 24(%%rdi)\n\t"~ 894 "mov %%edx, 28(%%rdi)\n\t"~ 895 "mov $0x80000004, %%eax\n\t"~ 896 "cpuid\n\t"~ 897 "mov %%eax, 32(%%rdi)\n\t"~ 898 "mov %%ebx, 36(%%rdi)\n\t"~ 899 "mov %%ecx, 40(%%rdi)\n\t"~ 900 "mov %%edx, 44(%%rdi)" 901 : 902 : "m" (string_) 903 : "edi", "eax", "ebx", "ecx", "edx"; 904 } else version (X86_64) asm { 905 "lea %0, %%rdi\n\t"~ 906 "mov $0x80000002, %%eax\n\t"~ 907 "cpuid\n\t"~ 908 "mov %%eax, (%%rdi)\n\t"~ 909 "mov %%ebx, 4(%%rdi)\n\t"~ 910 "mov %%ecx, 8(%%rdi)\n\t"~ 911 "mov %%edx, 12(%%rdi)\n\t"~ 912 "mov $0x80000003, %%eax\n\t"~ 913 "cpuid\n\t"~ 914 "mov %%eax, 16(%%rdi)\n\t"~ 915 "mov %%ebx, 20(%%rdi)\n\t"~ 916 "mov %%ecx, 24(%%rdi)\n\t"~ 917 "mov %%edx, 28(%%rdi)\n\t"~ 918 "mov $0x80000004, %%eax\n\t"~ 919 "cpuid\n\t"~ 920 "mov %%eax, 32(%%rdi)\n\t"~ 921 "mov %%ebx, 36(%%rdi)\n\t"~ 922 "mov %%ecx, 40(%%rdi)\n\t"~ 923 "mov %%edx, 44(%%rdi)" 924 : 925 : "m" (string_) 926 : "rdi", "rax", "rbx", "rcx", "rdx"; 927 } 928 } else version (LDC) { 929 version (X86) asm { 930 lea EDI, string_; 931 mov EAX, 0x8000_0002; 932 cpuid; 933 mov [EDI], EAX; 934 mov [EDI + 4], EBX; 935 mov [EDI + 8], ECX; 936 mov [EDI + 12], EDX; 937 mov EAX, 0x8000_0003; 938 cpuid; 939 mov [EDI + 16], EAX; 940 mov [EDI + 20], EBX; 941 mov [EDI + 24], ECX; 942 mov [EDI + 28], EDX; 943 mov EAX, 0x8000_0004; 944 cpuid; 945 mov [EDI + 32], EAX; 946 mov [EDI + 36], EBX; 947 mov [EDI + 40], ECX; 948 mov [EDI + 44], EDX; 949 } else version (X86_64) asm { 950 lea RDI, string_; 951 mov EAX, 0x8000_0002; 952 cpuid; 953 mov [RDI], EAX; 954 mov [RDI + 4], EBX; 955 mov [RDI + 8], ECX; 956 mov [RDI + 12], EDX; 957 mov EAX, 0x8000_0003; 958 cpuid; 959 mov [RDI + 16], EAX; 960 mov [RDI + 20], EBX; 961 mov [RDI + 24], ECX; 962 mov [RDI + 28], EDX; 963 mov EAX, 0x8000_0004; 964 cpuid; 965 mov [RDI + 32], EAX; 966 mov [RDI + 36], EBX; 967 mov [RDI + 40], ECX; 968 mov [RDI + 44], EDX; 969 } 970 } 971 } 972 973 // Avoids depending on C runtime for library. 974 /// Copy brand string 975 /// Params: 976 /// dst = Destination buffer 977 /// src = Source constant string 978 pragma(inline, false) 979 private 980 void ddcpuid_strcpy48(ref char[48] dst, const(char) *src) { 981 for (size_t i; i < 48; ++i) { 982 char c = src[i]; 983 dst[i] = c; 984 if (c == 0) break; 985 } 986 } 987 private alias strcpy48 = ddcpuid_strcpy48; 988 989 @system unittest { 990 char[48] buffer = void; 991 strcpy48(buffer, "ea"); 992 assert(buffer[0] == 'e'); 993 assert(buffer[1] == 'a'); 994 assert(buffer[2] == 0); 995 } 996 997 /// Get the legacy processor brand string. 998 /// These indexes/tables were introduced in Intel's Pentium III. 999 /// AMD does not use them. 1000 /// Params: 1001 /// info = CPUINFO structure. 1002 /// index = CPUID.01h.BL value. 1003 pragma(inline, false) 1004 private 1005 void ddcpuid_intel_brand_index(ref CPUINFO info, ubyte index) { 1006 switch (index) { 1007 case 1, 0xA, 0xF, 0x14: 1008 strcpy48(info.brandString, "Intel(R) Celeron(R)"); 1009 return; 1010 case 2, 4: 1011 strcpy48(info.brandString, "Intel(R) Pentium(R) III"); 1012 return; 1013 case 3: 1014 if (info.identifier == 0x6b1) goto case 1; 1015 strcpy48(info.brandString, "Intel(R) Pentium(R) III Xeon(R)"); 1016 return; 1017 case 6: 1018 strcpy48(info.brandString, "Mobile Intel(R) Pentium(R) III"); 1019 return; 1020 case 7, 0x13, 0x17: // Same as Intel(R) Celeron(R) M? 1021 strcpy48(info.brandString, "Mobile Intel(R) Celeron(R)"); 1022 return; 1023 case 8, 9: 1024 strcpy48(info.brandString, "Intel(R) Pentium(R) 4"); 1025 return; 1026 case 0xB: 1027 if (info.identifier == 0xf13) goto case 0xC; 1028 L_XEON: // Needed to avoid loop 1029 strcpy48(info.brandString, "Intel(R) Xeon(R)"); 1030 return; 1031 case 0xC: 1032 strcpy48(info.brandString, "Intel(R) Xeon(R) MP"); 1033 return; 1034 case 0xE: 1035 if (info.identifier == 0xf13) goto L_XEON; 1036 strcpy48(info.brandString, "Mobile Intel(R) Pentium(R) 4"); 1037 return; 1038 case 0x11, 0x15: // Yes, really. 1039 strcpy48(info.brandString, "Mobile Genuine Intel(R)"); 1040 return; 1041 case 0x12: strcpy48(info.brandString, "Intel(R) Celeron(R) M"); return; 1042 case 0x16: strcpy48(info.brandString, "Intel(R) Pentium(R) M"); return; 1043 default: strcpy48(info.brandString, "Unknown"); return; 1044 } 1045 } 1046 1047 pragma(inline, false) 1048 private 1049 void ddcpuid_intel_brand_family(ref CPUINFO info) { 1050 // This function exist for processors that does not support the 1051 // brand name table. 1052 // At least do from Pentium to late Pentium II processors. 1053 switch (info.family) { 1054 case 5: // i586, Pentium 1055 if (info.model >= 4) { 1056 strcpy48(info.brandString, "Intel(R) Pentium(R) MMX"); 1057 return; 1058 } 1059 strcpy48(info.brandString, "Intel(R) Pentium(R)"); 1060 return; 1061 case 6: // i686, Pentium Pro 1062 if (info.model >= 3) { 1063 strcpy48(info.brandString, "Intel(R) Pentium(R) II"); 1064 return; 1065 } 1066 strcpy48(info.brandString, "Intel(R) Pentium(R) Pro"); 1067 return; 1068 default: 1069 strcpy48(info.brandString, "Unknown"); 1070 return; 1071 } 1072 } 1073 1074 pragma(inline, false) 1075 private 1076 void ddcpuid_amd_brand_family(ref CPUINFO info) { 1077 // This function exist for processors that does not support the 1078 // extended brand string which is the Am5x86 and AMD K-5 model 0. 1079 // K-5 model 1 has extended brand string so case 5 is only model 0. 1080 // AMD has no official names for these. 1081 switch (info.family) { 1082 case 4: strcpy48(info.brandString, "AMD Am5x86"); return; 1083 case 5: strcpy48(info.brandString, "AMD K5"); return; 1084 default: strcpy48(info.brandString, "Unknown"); return; 1085 } 1086 } 1087 1088 pragma(inline, false) 1089 private 1090 void ddcpuid_virt_vendor(ref char[12] string_) { 1091 version (DMD) { 1092 version (X86) asm { 1093 mov EDI, string_; 1094 mov EAX, 0x40000000; 1095 cpuid; 1096 mov [EDI], EBX; 1097 mov [EDI + 4], ECX; 1098 mov [EDI + 8], EDX; 1099 } else asm { // x86-64 1100 mov RDI, string_; 1101 mov EAX, 0x40000000; 1102 cpuid; 1103 mov [RDI], EBX; 1104 mov [RDI + 4], ECX; 1105 mov [RDI + 8], EDX; 1106 } 1107 } else version (GDC) { 1108 version (X86) asm { 1109 "lea %0, %%edi\n\t"~ 1110 "mov $0x40000000, %%eax\n\t"~ 1111 "cpuid\n"~ 1112 "mov %%ebx, (%%edi)\n\t"~ 1113 "mov %%ecx, 4(%%edi)\n\t"~ 1114 "mov %%edx, 8(%%edi)" 1115 : 1116 : "m" (string_) 1117 : "edi", "eax", "ebx", "ecx", "edx"; 1118 } else asm { // x86-64 1119 "lea %0, %%rdi\n\t"~ 1120 "mov $0x40000000, %%eax\n\t"~ 1121 "cpuid\n"~ 1122 "mov %%ebx, (%%rdi)\n\t"~ 1123 "mov %%ecx, 4(%%rdi)\n\t"~ 1124 "mov %%edx, 8(%%rdi)" 1125 : 1126 : "m" (string_) 1127 : "rdi", "rax", "rbx", "rcx", "rdx"; 1128 } 1129 } else version (LDC) { 1130 version (X86) asm { 1131 lea EDI, string_; 1132 mov EAX, 0x40000000; 1133 cpuid; 1134 mov [EDI], EBX; 1135 mov [EDI + 4], ECX; 1136 mov [EDI + 8], EDX; 1137 } else asm { // x86-64 1138 lea RDI, string_; 1139 mov EAX, 0x40000000; 1140 cpuid; 1141 mov [RDI], EBX; 1142 mov [RDI + 4], ECX; 1143 mov [RDI + 8], EDX; 1144 } 1145 } 1146 } 1147 1148 pragma(inline, false) 1149 private 1150 VirtVendor ddcpuid_virt_vendor_id(ref VirtVendorString vendor) { 1151 // Paravirtual vendor string verification 1152 // If the rest of the string doesn't correspond, the id is unset 1153 switch (vendor.ebx) { 1154 case VirtVendor.KVM: // "KVMKVMKVM\0\0\0" 1155 if (vendor.ecx != ID!("VMKV")) goto default; 1156 if (vendor.edx != ID!("M\0\0\0")) goto default; 1157 return VirtVendor.KVM; 1158 case VirtVendor.HyperV: // "Microsoft Hv" 1159 if (vendor.ecx != ID!("osof")) goto default; 1160 if (vendor.edx != ID!("t Hv")) goto default; 1161 return VirtVendor.HyperV; 1162 case VirtVendor.VBoxHyperV: // "VBoxVBoxVBox" 1163 if (vendor.ecx != ID!("VBox")) goto default; 1164 if (vendor.edx != ID!("VBox")) goto default; 1165 return VirtVendor.HyperV; // Bug according to VBox 1166 default: 1167 return VirtVendor.Other; 1168 } 1169 } 1170 1171 @system unittest { 1172 VirtVendorString vendor; 1173 vendor.string_ = "KVMKVMKVM\0\0\0"; 1174 assert(ddcpuid_virt_vendor_id(vendor) == VirtVendor.KVM); 1175 } 1176 1177 pragma(inline, false) 1178 private 1179 void ddcpuid_model_string(ref CPUINFO info) { 1180 switch (info.vendor.id) with (Vendor) { 1181 case Intel: 1182 // Brand string 1183 if (info.maxLeafExtended >= 0x8000_0004) 1184 ddcpuid_extended_brand(info.brandString); 1185 else if (info.brandIndex) 1186 ddcpuid_intel_brand_index(info, info.brandIndex); 1187 else 1188 ddcpuid_intel_brand_family(info); 1189 return; 1190 case AMD, VIA: 1191 // Brand string 1192 // NOTE: AMD processor never supported the string table. 1193 // The Am486DX4 and Am5x86 processors do not support the extended brand string. 1194 // The K5 model 0 does not support the extended brand string. 1195 // The K5 model 1, 2, and 3 support the extended brand string. 1196 if (info.maxLeafExtended >= 0x8000_0004) 1197 ddcpuid_extended_brand(info.brandString); 1198 else 1199 ddcpuid_amd_brand_family(info); 1200 return; 1201 default: 1202 strcpy48(info.brandString, "Unknown"); 1203 return; 1204 } 1205 } 1206 1207 pragma(inline, false) 1208 private 1209 void ddcpuid_leaf1(ref CPUINFO info, ref REGISTERS regs) { 1210 // EAX 1211 info.identifier = regs.eax; 1212 info.stepping = regs.eax & 15; // EAX[3:0] 1213 info.modelBase = regs.eax >> 4 & 15; // EAX[7:4] 1214 info.familyBase = regs.eax >> 8 & 15; // EAX[11:8] 1215 info.type = regs.eax >> 12 & 3; // EAX[13:12] 1216 info.typeString = PROCESSOR_TYPE[info.type]; 1217 info.modelExtended = regs.eax >> 16 & 15; // EAX[19:16] 1218 info.familyExtended = cast(ubyte)(regs.eax >> 20); // EAX[27:20] 1219 1220 switch (info.vendor.id) with (Vendor) { 1221 case Intel: 1222 info.family = info.familyBase != 15 ? 1223 cast(ushort)info.familyBase : 1224 cast(ushort)(info.familyExtended + info.familyBase); 1225 1226 info.model = info.familyBase == 6 || info.familyBase == 0 ? 1227 cast(ushort)((info.modelExtended << 4) + info.modelBase) : 1228 cast(ushort)info.modelBase; // DisplayModel = Model_ID; 1229 1230 // ECX 1231 info.debugging.dtes64 = bit(regs.ecx, 2); 1232 info.debugging.ds_cpl = bit(regs.ecx, 4); 1233 info.virt.available = bit(regs.ecx, 5); 1234 info.tech.smx = bit(regs.ecx, 6); 1235 info.tech.eist = bit(regs.ecx, 7); 1236 info.sys.tm2 = bit(regs.ecx, 8); 1237 info.cache.cnxtId = bit(regs.ecx, 10); 1238 info.debugging.sdbg = bit(regs.ecx, 11); 1239 info.misc.xtpr = bit(regs.ecx, 14); 1240 info.debugging.pdcm = bit(regs.ecx, 15); 1241 info.misc.pcid = bit(regs.ecx, 17); 1242 info.debugging.mca = bit(regs.ecx, 18); 1243 info.sys.x2apic = bit(regs.ecx, 21); 1244 info.extras.rdtscDeadline = bit(regs.ecx, 24); 1245 1246 // EDX 1247 info.misc.psn = bit(regs.edx, 18); 1248 info.debugging.ds = bit(regs.edx, 21); 1249 info.sys.available = bit(regs.edx, 22); 1250 info.cache.ss = bit(regs.edx, 27); 1251 info.sys.tm = bit(regs.edx, 29); 1252 info.debugging.pbe = regs.edx >= BIT!(31); 1253 break; 1254 case AMD: 1255 if (info.familyBase < 15) { 1256 info.family = info.familyBase; 1257 info.model = info.modelBase; 1258 } else { 1259 info.family = cast(ushort)(info.familyExtended + info.familyBase); 1260 info.model = cast(ushort)((info.modelExtended << 4) + info.modelBase); 1261 } 1262 break; 1263 default: 1264 } 1265 1266 // EBX 1267 info.sys.apicId = regs.ebx >> 24; 1268 info.sys.maxApicId = cast(ubyte)(regs.ebx >> 16); 1269 info.cache.clflushLinesize = regs.bh; 1270 info.brandIndex = regs.bl; 1271 1272 // ECX 1273 info.sse.sse3 = bit(regs.ecx, 0); 1274 info.extras.pclmulqdq = bit(regs.ecx, 1); 1275 info.extras.monitor = bit(regs.ecx, 3); 1276 info.sse.ssse3 = bit(regs.ecx, 9); 1277 info.extensions.fma3 = bit(regs.ecx, 12); 1278 info.extras.cmpxchg16b = bit(regs.ecx, 13); 1279 info.sse.sse41 = bit(regs.ecx, 15); 1280 info.sse.sse42 = bit(regs.ecx, 20); 1281 info.extras.movbe = bit(regs.ecx, 22); 1282 info.extras.popcnt = bit(regs.ecx, 23); 1283 info.extensions.aes_ni = bit(regs.ecx, 25); 1284 info.extras.xsave = bit(regs.ecx, 26); 1285 info.extras.osxsave = bit(regs.ecx, 27); 1286 info.avx.avx = bit(regs.ecx, 28); 1287 info.extensions.f16c = bit(regs.ecx, 29); 1288 info.extras.rdrand = bit(regs.ecx, 30); 1289 1290 // EDX 1291 info.extensions.fpu = bit(regs.edx, 0); 1292 info.virt.vme = bit(regs.edx, 1); 1293 info.debugging.de = bit(regs.edx, 2); 1294 info.memory.pse = bit(regs.edx, 3); 1295 info.extras.rdtsc = bit(regs.edx, 4); 1296 info.extras.rdmsr = bit(regs.edx, 5); 1297 info.memory.pae = bit(regs.edx, 6); 1298 info.debugging.mce = bit(regs.edx, 7); 1299 info.extras.cmpxchg8b = bit(regs.edx, 8); 1300 info.sys.apic = bit(regs.edx, 9); 1301 info.extras.sysenter = bit(regs.edx, 11); 1302 info.memory.mtrr = bit(regs.edx, 12); 1303 info.memory.pge = bit(regs.edx, 13); 1304 info.debugging.mca = bit(regs.edx, 14); 1305 info.extras.cmov = bit(regs.edx, 15); 1306 info.memory.pat = bit(regs.edx, 16); 1307 info.memory.pse36 = bit(regs.edx, 17); 1308 info.cache.clflush = bit(regs.edx, 19); 1309 info.extensions.mmx = bit(regs.edx, 23); 1310 info.extras.fxsr = bit(regs.edx, 24); 1311 info.sse.sse = bit(regs.edx, 25); 1312 info.sse.sse2 = bit(regs.edx, 26); 1313 info.tech.htt = bit(regs.edx, 28); 1314 } 1315 1316 //NOTE: Only Intel officially supports CPUID.02h 1317 // No dedicated functions to a cache descriptor to avoid a definition. 1318 pragma(inline, false) 1319 private 1320 void ddcpuid_leaf2(ref CPUINFO info, ref REGISTERS regs) { 1321 struct leaf2_t { 1322 union { 1323 REGISTERS registers; 1324 ubyte[16] values; 1325 } 1326 } 1327 leaf2_t data = void; 1328 1329 data.registers = regs; 1330 1331 enum L1I = 0; 1332 enum L1D = 1; 1333 enum L2 = 2; 1334 enum L3 = 3; 1335 // Skips value in AL 1336 with (info.cache) for (size_t index = 1; index < 16; ++index) { 1337 ubyte value = data.values[index]; 1338 1339 // Cache entries only, the rest is "don't care". 1340 // Unless if one day I support looking up TLB data, but AMD does not support this. 1341 // continue: Explicitly skip cache, this includes 0x00 (null), 0x40 (no L2 or L3). 1342 // break: Valid cache descriptor, increment cache level. 1343 //TODO: table + foreach loop 1344 switch (value) { 1345 case 0x06: // 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size 1346 level[L1I] = CACHEINFO(1, 'I', 8, 1, 4, 1, 32, 64); 1347 break; 1348 case 0x08: // 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size 1349 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 32, 128); 1350 break; 1351 case 0x09: // 1st-level instruction cache: 32 KBytes, 4-way set associative, 64 byte line size 1352 level[L1I] = CACHEINFO(1, 'I', 32, 1, 4, 1, 64, 128); 1353 break; 1354 case 0x0A: // 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size 1355 level[L1D] = CACHEINFO(1, 'D', 8, 1, 2, 1, 32, 128); 1356 break; 1357 case 0x0C: // 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size 1358 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 32, 128); 1359 break; 1360 case 0x0D: // 1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size (ECC?) 1361 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 64, 64); 1362 break; 1363 case 0x0E: // 1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size 1364 level[L1D] = CACHEINFO(1, 'D', 24, 1, 6, 1, 64, 64); 1365 break; 1366 case 0x10: // (sandpile) data L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64) 1367 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 32, 64); 1368 break; 1369 case 0x15: // (sandpile) code L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64) 1370 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 32, 64); 1371 break; 1372 case 0x1a: // (sandpile) code and data L2 cache, 96 KB, 6 ways, 64 byte lines (IA-64) 1373 level[L2] = CACHEINFO(2, 'I', 96, 1, 6, 1, 64, 256); 1374 break; 1375 case 0x1D: // 2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size 1376 level[L2] = CACHEINFO(2, 'U', 128, 1, 2, 1, 64, 1024); 1377 break; 1378 case 0x21: // 2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size 1379 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 64, 512); 1380 break; 1381 case 0x22: // 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector 1382 level[L3] = CACHEINFO(3, 'U', 512, 1, 4, 2, 64, 1024); 1383 break; 1384 case 0x23: // 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1385 level[L3] = CACHEINFO(3, 'U', 1024, 1, 8, 2, 64, 1024); 1386 break; 1387 case 0x24: // 2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size 1388 level[L2] = CACHEINFO(2, 'U', 1024, 1, 16, 1, 64, 1024); 1389 break; 1390 case 0x25: // 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1391 level[L3] = CACHEINFO(3, 'U', 2048, 1, 8, 2, 64, 2048); 1392 break; 1393 case 0x29: // 3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1394 level[L3] = CACHEINFO(3, 'U', 4096, 1, 8, 2, 64, 4096); 1395 break; 1396 case 0x2C: // 1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size 1397 level[L1D] = CACHEINFO(1, 'D', 32, 1, 8, 1, 64, 64); 1398 break; 1399 case 0x30: // 1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size 1400 level[L1I] = CACHEINFO(1, 'I', 32, 1, 8, 1, 64, 64); 1401 break; 1402 case 0x39: // (sandpile) code and data L2 cache, 128 KB, 4 ways, 64 byte lines, sectored (htt?) 1403 level[L2] = CACHEINFO(2, 'U', 128, 1, 4, 1, 64, 512); 1404 break; 1405 case 0x3A: // (sandpile) code and data L2 cache, 192 KB, 6 ways, 64 byte lines, sectored (htt?) 1406 level[L2] = CACHEINFO(2, 'U', 192, 1, 6, 1, 64, 512); 1407 break; 1408 case 0x3B: // (sandpile) code and data L2 cache, 128 KB, 2 ways, 64 byte lines, sectored (htt?) 1409 level[L2] = CACHEINFO(2, 'U', 128, 1, 2, 1, 64, 1024); 1410 break; 1411 case 0x3C: // (sandpile) code and data L2 cache, 256 KB, 4 ways, 64 byte lines, sectored 1412 level[L2] = CACHEINFO(2, 'U', 256, 1, 4, 1, 64, 1024); 1413 break; 1414 case 0x3D: // (sandpile) code and data L2 cache, 384 KB, 6 ways, 64 byte lines, sectored (htt?) 1415 level[L2] = CACHEINFO(2, 'U', 384, 1, 6, 1, 64, 1024); 1416 break; 1417 case 0x3E: // (sandpile) code and data L2 cache, 512 KB, 4 ways, 64 byte lines, sectored (htt?) 1418 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 64, 2048); 1419 break; 1420 case 0x41: // 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size 1421 level[L2] = CACHEINFO(2, 'U', 128, 1, 4, 1, 32, 1024); 1422 break; 1423 case 0x42: // 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size 1424 level[L2] = CACHEINFO(2, 'U', 256, 1, 4, 1, 32, 2048); 1425 break; 1426 case 0x43: // 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size 1427 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 32, 4096); 1428 break; 1429 case 0x44: // 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size 1430 level[L2] = CACHEINFO(2, 'U', 1024, 1, 4, 1, 32, 8192); 1431 break; 1432 case 0x45: // 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size 1433 level[L2] = CACHEINFO(2, 'U', 2048, 1, 4, 1, 32, 16384); 1434 break; 1435 case 0x46: // 3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size 1436 level[L2] = CACHEINFO(2, 'U', 4096, 1, 4, 1, 64, 16384); 1437 break; 1438 case 0x47: // 3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size 1439 level[L3] = CACHEINFO(3, 'U', 8192, 1, 8, 1, 64, 16384); 1440 break; 1441 case 0x48: // 2nd-level cache: 3 MByte, 12-way set associative, 64 byte line size 1442 level[L2] = CACHEINFO(2, 'U', 3072, 1, 12, 1, 64, 4096); 1443 break; 1444 // 3rd-level cache: 4 MByte, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 1445 // 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size 1446 case 0x49: 1447 if (info.family == 0xf && info.family == 6) 1448 level[L3] = CACHEINFO(3, 'U', 4096, 1, 16, 1, 64, 4096); 1449 else 1450 level[L2] = CACHEINFO(2, 'U', 4096, 1, 16, 1, 64, 4096); 1451 break; 1452 case 0x4A: // 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size 1453 level[L3] = CACHEINFO(3, 'U', 6144, 1, 12, 1, 64, 6144); 1454 break; 1455 case 0x4B: // 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size 1456 level[L3] = CACHEINFO(3, 'U', 8192, 1, 16, 1, 64, 8192); 1457 break; 1458 case 0x4C: // 3rd-level cache: 12 MByte, 12-way set associative, 64 byte line size 1459 level[L3] = CACHEINFO(3, 'U', 8192, 1, 12, 1, 64, 16384); 1460 break; 1461 case 0x4D: // 3rd-level cache: 16 MByte, 16-way set associative, 64 byte line size 1462 level[L3] = CACHEINFO(3, 'U', 16384, 1, 16, 1, 64, 16384); 1463 break; 1464 case 0x4E: // 2nd-level cache: 6MByte, 24-way set associative, 64 byte line size 1465 level[L2] = CACHEINFO(2, 'U', 6144, 1, 24, 1, 64, 4096); 1466 break; 1467 case 0x60: // 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size 1468 level[L1D] = CACHEINFO(1, 'D', 16, 1, 8, 1, 64, 32); 1469 break; 1470 case 0x66: // 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size 1471 level[L1D] = CACHEINFO(1, 'D', 8, 1, 4, 1, 64, 32); 1472 break; 1473 case 0x67: // 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size 1474 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 64, 64); 1475 break; 1476 case 0x68: // 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size 1477 level[L1D] = CACHEINFO(1, 'D', 32, 1, 4, 1, 64, 128); 1478 break; 1479 case 0x77: // (sandpile) code L1 cache, 16 KB, 4 ways, 64 byte lines, sectored (IA-64) 1480 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 64, 64); 1481 break; 1482 case 0x78: // 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size 1483 level[L2] = CACHEINFO(2, 'U', 1024, 1, 4, 1, 64, 4096); 1484 break; 1485 case 0x79: // 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1486 level[L2] = CACHEINFO(2, 'U', 128, 1, 8, 2, 64, 128); 1487 break; 1488 case 0x7A: // 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1489 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 2, 64, 256); 1490 break; 1491 case 0x7B: // 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1492 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 2, 64, 512); 1493 break; 1494 case 0x7C: // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector 1495 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 2, 64, 1024); 1496 break; 1497 case 0x7D: // 2nd-level cache: 2 MByte, 8-way set associative, 64 byte line size 1498 level[L2] = CACHEINFO(2, 'U', 2048, 1, 8, 1, 64, 4096); 1499 break; 1500 case 0x7E: // (sandpile) code and data L2 cache, 256 KB, 8 ways, 128 byte lines, sect. (IA-64) 1501 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 128, 256); 1502 break; 1503 case 0x7F: // 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size 1504 level[L2] = CACHEINFO(2, 'U', 512, 1, 2, 1, 64, 4096); 1505 break; 1506 case 0x80: // 2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size 1507 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 1, 64, 1024); 1508 break; 1509 case 0x81: // (sandpile) code and data L2 cache, 128 KB, 8 ways, 32 byte lines 1510 level[L2] = CACHEINFO(2, 'U', 128, 1, 8, 1, 32, 512); 1511 break; 1512 case 0x82: // 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size 1513 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 32, 1024); 1514 break; 1515 case 0x83: // 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size 1516 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 1, 32, 2048); 1517 break; 1518 case 0x84: // 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size 1519 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 1, 32, 4096); 1520 break; 1521 case 0x85: // 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size 1522 level[L2] = CACHEINFO(2, 'U', 2048, 1, 8, 1, 32, 8192); 1523 break; 1524 case 0x86: // 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size 1525 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 64, 2048); 1526 break; 1527 case 0x87: // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size 1528 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 1, 64, 2048); 1529 break; 1530 case 0xD0: // 3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size 1531 level[L3] = CACHEINFO(3, 'U', 512, 1, 4, 1, 64, 2048); 1532 break; 1533 case 0xD1: // 3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size 1534 level[L3] = CACHEINFO(3, 'U', 1024, 1, 4, 1, 64, 4096); 1535 break; 1536 case 0xD2: // 3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size 1537 level[L3] = CACHEINFO(3, 'U', 2048, 1, 4, 1, 64, 8192); 1538 break; 1539 case 0xD6: // 3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size 1540 level[L3] = CACHEINFO(3, 'U', 1024, 1, 8, 1, 64, 2048); 1541 break; 1542 case 0xD7: // 3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size 1543 level[L3] = CACHEINFO(3, 'U', 2048, 1, 8, 1, 64, 4096); 1544 break; 1545 case 0xD8: // 3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size 1546 level[L3] = CACHEINFO(3, 'U', 4096, 1, 8, 1, 64, 8192); 1547 break; 1548 case 0xDC: // 3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size 1549 level[L3] = CACHEINFO(3, 'U', 1536, 1, 12, 1, 64, 2048); 1550 break; 1551 case 0xDD: // 3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size 1552 level[L3] = CACHEINFO(3, 'U', 3072, 1, 12, 1, 64, 4096); 1553 break; 1554 case 0xDE: // 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size 1555 level[L3] = CACHEINFO(3, 'U', 6144, 1, 12, 1, 64, 8192); 1556 break; 1557 case 0xE2: // 3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size 1558 level[L3] = CACHEINFO(3, 'U', 2048, 1, 16, 1, 64, 2048); 1559 break; 1560 case 0xE3: // 3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size 1561 level[L3] = CACHEINFO(3, 'U', 4096, 1, 16, 1, 64, 4096); 1562 break; 1563 case 0xE4: // 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size 1564 level[L3] = CACHEINFO(3, 'U', 8192, 1, 16, 1, 64, 8192); 1565 break; 1566 case 0xEA: // 3rd-level cache: 12MByte, 24-way set associative, 64 byte line size 1567 level[L3] = CACHEINFO(3, 'U', 12288, 1, 24, 1, 64, 8192); 1568 break; 1569 case 0xEB: // 3rd-level cache: 18MByte, 24-way set associative, 64 byte line size 1570 level[L3] = CACHEINFO(3, 'U', 18432, 1, 24, 1, 64, 12288); 1571 break; 1572 case 0xEC: // 3rd-level cache: 24MByte, 24-way set associative, 64 byte line size 1573 level[L3] = CACHEINFO(3, 'U', 24576, 1, 24, 1, 64, 16384); 1574 break; 1575 default: continue; 1576 } 1577 1578 ++levels; 1579 } 1580 with (info.cache) { // Some do not have L1I 1581 if (level[0].level == 0) { 1582 for (size_t i; i < levels; ++i) { 1583 level[i] = level[i+1]; 1584 } 1585 level[levels] = CACHEINFO.init; 1586 } 1587 } 1588 } 1589 1590 version (TestCPUID02h) @system unittest { 1591 import std.stdio : write, writeln, writef; 1592 REGISTERS regs; // Celeron 0xf34 1593 regs.eax = 0x605b5101; 1594 regs.ebx = 0; 1595 regs.ecx = 0; 1596 regs.edx = 0x3c7040; 1597 1598 CPUINFO info; 1599 ddcpuid_leaf2(info, regs); 1600 1601 writeln("TEST: CPUID.02h"); 1602 CACHEINFO *cache = void; 1603 for (uint i; i < CACHE_MAX_LEVEL; ++i) { 1604 cache = &info.cache.level[i]; 1605 writef("Level %u-%c : %2ux %6u KiB, %u ways, %u parts, %u B, %u sets", 1606 cache.level, cache.type, cache.sharedCores, cache.size, 1607 cache.ways, cache.partitions, cache.lineSize, cache.sets 1608 ); 1609 if (cache.features) { 1610 write(','); 1611 if (cache.features & BIT!(0)) write(" si"); // Self Initiative 1612 if (cache.features & BIT!(1)) write(" fa"); // Fully Associative 1613 if (cache.features & BIT!(2)) write(" nwbv"); // No Write-Back Validation 1614 if (cache.features & BIT!(3)) write(" ci"); // Cache Inclusive 1615 if (cache.features & BIT!(4)) write(" cci"); // Complex Cache Indexing 1616 } 1617 writeln; 1618 } 1619 } 1620 1621 pragma(inline, false) 1622 private 1623 void ddcpuid_leaf5(ref CPUINFO info, ref REGISTERS regs) { 1624 info.extras.mwaitMin = regs.ax; 1625 info.extras.mwaitMax = regs.bx; 1626 } 1627 1628 pragma(inline, false) 1629 private 1630 void ddcpuid_leaf6(ref CPUINFO info, ref REGISTERS regs) { 1631 switch (info.vendor.id) with (Vendor) { 1632 case Intel: 1633 info.tech.turboboost = bit(regs.eax, 1); 1634 info.tech.turboboost30 = bit(regs.eax, 14); 1635 break; 1636 default: 1637 } 1638 1639 info.sys.arat = bit(regs.eax, 2); 1640 } 1641 1642 pragma(inline, false) 1643 private 1644 void ddcpuid_leaf7(ref CPUINFO info, ref REGISTERS regs) { 1645 switch (info.vendor.id) with (Vendor) { 1646 case Intel: 1647 // EBX 1648 info.sgx.supported = bit(regs.ebx, 2); 1649 info.memory.hle = bit(regs.ebx, 4); 1650 info.cache.invpcid = bit(regs.ebx, 10); 1651 info.memory.rtm = bit(regs.ebx, 11); 1652 info.avx.avx512f = bit(regs.ebx, 16); 1653 info.memory.smap = bit(regs.ebx, 20); 1654 info.avx.avx512er = bit(regs.ebx, 27); 1655 info.avx.avx512pf = bit(regs.ebx, 26); 1656 info.avx.avx512cd = bit(regs.ebx, 28); 1657 info.avx.avx512dq = bit(regs.ebx, 17); 1658 info.avx.avx512bw = bit(regs.ebx, 30); 1659 info.avx.avx512_ifma = bit(regs.ebx, 21); 1660 info.avx.avx512_vbmi = regs.ebx >= BIT!(31); 1661 // ECX 1662 info.avx.avx512vl = bit(regs.ecx, 1); 1663 info.memory.pku = bit(regs.ecx, 3); 1664 info.memory.fsrepmov = bit(regs.ecx, 4); 1665 info.extensions.waitpkg = bit(regs.ecx, 5); 1666 info.avx.avx512_vbmi2 = bit(regs.ecx, 6); 1667 info.security.cetSs = bit(regs.ecx, 7); 1668 info.avx.avx512_gfni = bit(regs.ecx, 8); 1669 info.avx.avx512_vaes = bit(regs.ecx, 9); 1670 info.avx.avx512_vnni = bit(regs.ecx, 11); 1671 info.avx.avx512_bitalg = bit(regs.ecx, 12); 1672 info.avx.avx512_vpopcntdq = bit(regs.ecx, 14); 1673 info.memory._5pl = bit(regs.ecx, 16); 1674 info.extras.cldemote = bit(regs.ecx, 25); 1675 info.extras.movdiri = bit(regs.ecx, 27); 1676 info.extras.movdir64b = bit(regs.ecx, 28); 1677 info.extras.enqcmd = bit(regs.ecx, 29); 1678 // EDX 1679 info.avx.avx512_4vnniw = bit(regs.edx, 2); 1680 info.avx.avx512_4fmaps = bit(regs.edx, 3); 1681 info.misc.uintr = bit(regs.edx, 5); 1682 info.avx.avx512_vp2intersect = bit(regs.edx, 8); 1683 info.security.md_clear = bit(regs.edx, 10); 1684 info.extras.serialize = bit(regs.edx, 14); 1685 info.memory.tsxldtrk = bit(regs.edx, 16); 1686 info.extras.pconfig = bit(regs.edx, 18); 1687 info.security.cetIbt = bit(regs.edx, 20); 1688 info.amx.bf16 = bit(regs.edx, 22); 1689 info.amx.enabled = bit(regs.edx, 24); 1690 info.amx.int8 = bit(regs.edx, 25); 1691 info.security.ibrs = bit(regs.edx, 26); 1692 info.security.stibp = bit(regs.edx, 27); 1693 info.security.l1dFlush = bit(regs.edx, 28); 1694 info.security.ia32_arch_capabilities = bit(regs.edx, 29); 1695 info.security.ssbd = regs.edx >= BIT!(31); 1696 break; 1697 default: 1698 } 1699 1700 // ebx 1701 info.misc.fsgsbase = bit(regs.ebx, 0); 1702 info.extensions.bmi1 = bit(regs.ebx, 3); 1703 info.avx.avx2 = bit(regs.ebx, 5); 1704 info.memory.smep = bit(regs.ebx, 7); 1705 info.extensions.bmi2 = bit(regs.ebx, 8); 1706 info.extras.rdseed = bit(regs.ebx, 18); 1707 info.extensions.adx = bit(regs.ebx, 19); 1708 info.cache.clflushopt = bit(regs.ebx, 23); 1709 info.extensions.sha = bit(regs.ebx, 29); 1710 // ecx 1711 info.extras.rdpid = bit(regs.ecx, 22); 1712 } 1713 1714 pragma(inline, false) 1715 private 1716 void ddcpuid_leaf7sub1(ref CPUINFO info, ref REGISTERS regs) { 1717 switch (info.vendor.id) with (Vendor) { 1718 case Intel: 1719 // a 1720 info.avx.avx512_bf16 = bit(regs.eax, 5); 1721 info.memory.lam = bit(regs.eax, 26); 1722 break; 1723 default: 1724 } 1725 } 1726 1727 pragma(inline, false) 1728 private 1729 void ddcpuid_leafD(ref CPUINFO info, ref REGISTERS regs) { 1730 switch (info.vendor.id) with (Vendor) { 1731 case Intel: 1732 info.amx.xtilecfg = bit(regs.eax, 17); 1733 info.amx.xtiledata = bit(regs.eax, 18); 1734 break; 1735 default: 1736 } 1737 } 1738 1739 pragma(inline, false) 1740 private 1741 void ddcpuid_leafDsub1(ref CPUINFO info, ref REGISTERS regs) { 1742 switch (info.vendor.id) with (Vendor) { 1743 case Intel: 1744 info.amx.xfd = bit(regs.eax, 18); 1745 break; 1746 default: 1747 } 1748 } 1749 1750 pragma(inline, false) 1751 private 1752 void ddcpuid_leaf12(ref CPUINFO info, ref REGISTERS regs) { 1753 switch (info.vendor.id) with (Vendor) { 1754 case Intel: 1755 info.sgx.sgx1 = bit(regs.al, 0); 1756 info.sgx.sgx2 = bit(regs.al, 1); 1757 info.sgx.maxSize = regs.dl; 1758 info.sgx.maxSize64 = regs.dh; 1759 break; 1760 default: 1761 } 1762 } 1763 1764 pragma(inline, false) 1765 private 1766 void ddcpuid_leaf4000_0001(ref CPUINFO info, ref REGISTERS regs) { 1767 // switch (info.virt.vendor.id) with (VirtVendor) { 1768 // case KVM: 1769 info.virt.kvm.feature_clocksource = bit(regs.eax, 0); 1770 info.virt.kvm.feature_nop_io_delay = bit(regs.eax, 1); 1771 info.virt.kvm.feature_mmu_op = bit(regs.eax, 2); 1772 info.virt.kvm.feature_clocksource2 = bit(regs.eax, 3); 1773 info.virt.kvm.feature_async_pf = bit(regs.eax, 4); 1774 info.virt.kvm.feature_steal_time = bit(regs.eax, 5); 1775 info.virt.kvm.feature_pv_eoi = bit(regs.eax, 6); 1776 info.virt.kvm.feature_pv_unhault = bit(regs.eax, 7); 1777 info.virt.kvm.feature_pv_tlb_flush = bit(regs.eax, 9); 1778 info.virt.kvm.feature_async_pf_vmexit = bit(regs.eax, 10); 1779 info.virt.kvm.feature_pv_send_ipi = bit(regs.eax, 11); 1780 info.virt.kvm.feature_pv_poll_control = bit(regs.eax, 12); 1781 info.virt.kvm.feature_pv_sched_yield = bit(regs.eax, 13); 1782 info.virt.kvm.feature_clocsource_stable_bit = bit(regs.eax, 24); 1783 info.virt.kvm.hint_realtime = bit(regs.edx, 0); 1784 // break; 1785 // default: 1786 // } 1787 } 1788 1789 pragma(inline, false) 1790 private 1791 void ddcpuid_leaf4000_0002(ref CPUINFO info, ref REGISTERS regs) { 1792 // switch (info.virt.vendor.id) with (VirtVendor) { 1793 // case HyperV: 1794 info.virt.hv.guest_minor = cast(ubyte)(regs.eax >> 24); 1795 info.virt.hv.guest_service = cast(ubyte)(regs.eax >> 16); 1796 info.virt.hv.guest_build = regs.ax; 1797 info.virt.hv.guest_opensource = regs.edx >= BIT!(31); 1798 info.virt.hv.guest_vendor_id = (regs.edx >> 16) & 0xFFF; 1799 info.virt.hv.guest_os = regs.dh; 1800 info.virt.hv.guest_major = regs.dl; 1801 // break; 1802 // default: 1803 // } 1804 } 1805 1806 pragma(inline, false) 1807 private 1808 void ddcpuid_leaf4000_0003(ref CPUINFO info, ref REGISTERS regs) { 1809 // switch (info.virt.vendor.id) with (VirtVendor) { 1810 // case HyperV: 1811 info.virt.hv.base_feat_vp_runtime_msr = bit(regs.eax, 0); 1812 info.virt.hv.base_feat_part_time_ref_count_msr = bit(regs.eax, 1); 1813 info.virt.hv.base_feat_basic_synic_msrs = bit(regs.eax, 2); 1814 info.virt.hv.base_feat_stimer_msrs = bit(regs.eax, 3); 1815 info.virt.hv.base_feat_apic_access_msrs = bit(regs.eax, 4); 1816 info.virt.hv.base_feat_hypercall_msrs = bit(regs.eax, 5); 1817 info.virt.hv.base_feat_vp_id_msr = bit(regs.eax, 6); 1818 info.virt.hv.base_feat_virt_sys_reset_msr = bit(regs.eax, 7); 1819 info.virt.hv.base_feat_stat_pages_msr = bit(regs.eax, 8); 1820 info.virt.hv.base_feat_part_ref_tsc_msr = bit(regs.eax, 9); 1821 info.virt.hv.base_feat_guest_idle_state_msr = bit(regs.eax, 10); 1822 info.virt.hv.base_feat_timer_freq_msrs = bit(regs.eax, 11); 1823 info.virt.hv.base_feat_debug_msrs = bit(regs.eax, 12); 1824 info.virt.hv.part_flags_create_part = bit(regs.ebx, 0); 1825 info.virt.hv.part_flags_access_part_id = bit(regs.ebx, 1); 1826 info.virt.hv.part_flags_access_memory_pool = bit(regs.ebx, 2); 1827 info.virt.hv.part_flags_adjust_msg_buffers = bit(regs.ebx, 3); 1828 info.virt.hv.part_flags_post_msgs = bit(regs.ebx, 4); 1829 info.virt.hv.part_flags_signal_events = bit(regs.ebx, 5); 1830 info.virt.hv.part_flags_create_port = bit(regs.ebx, 6); 1831 info.virt.hv.part_flags_connect_port = bit(regs.ebx, 7); 1832 info.virt.hv.part_flags_access_stats = bit(regs.ebx, 8); 1833 info.virt.hv.part_flags_debugging = bit(regs.ebx, 11); 1834 info.virt.hv.part_flags_cpu_mgmt = bit(regs.ebx, 12); 1835 info.virt.hv.part_flags_cpu_profiler = bit(regs.ebx, 13); 1836 info.virt.hv.part_flags_expanded_stack_walk = bit(regs.ebx, 14); 1837 info.virt.hv.part_flags_access_vsm = bit(regs.ebx, 16); 1838 info.virt.hv.part_flags_access_vp_regs = bit(regs.ebx, 17); 1839 info.virt.hv.part_flags_extended_hypercalls = bit(regs.ebx, 20); 1840 info.virt.hv.part_flags_start_vp = bit(regs.ebx, 21); 1841 info.virt.hv.pm_max_cpu_power_state_c0 = bit(regs.ecx, 0); 1842 info.virt.hv.pm_max_cpu_power_state_c1 = bit(regs.ecx, 1); 1843 info.virt.hv.pm_max_cpu_power_state_c2 = bit(regs.ecx, 2); 1844 info.virt.hv.pm_max_cpu_power_state_c3 = bit(regs.ecx, 3); 1845 info.virt.hv.pm_hpet_reqd_for_c3 = bit(regs.ecx, 4); 1846 info.virt.hv.misc_feat_mwait = bit(regs.eax, 0); 1847 info.virt.hv.misc_feat_guest_debugging = bit(regs.eax, 1); 1848 info.virt.hv.misc_feat_perf_mon = bit(regs.eax, 2); 1849 info.virt.hv.misc_feat_pcpu_dyn_part_event = bit(regs.eax, 3); 1850 info.virt.hv.misc_feat_xmm_hypercall_input = bit(regs.eax, 4); 1851 info.virt.hv.misc_feat_guest_idle_state = bit(regs.eax, 5); 1852 info.virt.hv.misc_feat_hypervisor_sleep_state = bit(regs.eax, 6); 1853 info.virt.hv.misc_feat_query_numa_distance = bit(regs.eax, 7); 1854 info.virt.hv.misc_feat_timer_freq = bit(regs.eax, 8); 1855 info.virt.hv.misc_feat_inject_synmc_xcpt = bit(regs.eax, 9); 1856 info.virt.hv.misc_feat_guest_crash_msrs = bit(regs.eax, 10); 1857 info.virt.hv.misc_feat_debug_msrs = bit(regs.eax, 11); 1858 info.virt.hv.misc_feat_npiep1 = bit(regs.eax, 12); 1859 info.virt.hv.misc_feat_disable_hypervisor = bit(regs.eax, 13); 1860 info.virt.hv.misc_feat_ext_gva_range_for_flush_va_list = bit(regs.eax, 14); 1861 info.virt.hv.misc_feat_hypercall_output_xmm = bit(regs.eax, 15); 1862 info.virt.hv.misc_feat_sint_polling_mode = bit(regs.eax, 17); 1863 info.virt.hv.misc_feat_hypercall_msr_lock = bit(regs.eax, 18); 1864 info.virt.hv.misc_feat_use_direct_synth_msrs = bit(regs.eax, 19); 1865 // break; 1866 // default: 1867 // } 1868 } 1869 1870 pragma(inline, false) 1871 private 1872 void ddcpuid_leaf4000_0004(ref CPUINFO info, ref REGISTERS regs) { 1873 // switch (info.virt.vendor.id) with (VirtVendor) { 1874 // case HyperV: 1875 info.virt.hv.hint_hypercall_for_process_switch = bit(regs.eax, 0); 1876 info.virt.hv.hint_hypercall_for_tlb_flush = bit(regs.eax, 1); 1877 info.virt.hv.hint_hypercall_for_tlb_shootdown = bit(regs.eax, 2); 1878 info.virt.hv.hint_msr_for_apic_access = bit(regs.eax, 3); 1879 info.virt.hv.hint_msr_for_sys_reset = bit(regs.eax, 4); 1880 info.virt.hv.hint_relax_time_checks = bit(regs.eax, 5); 1881 info.virt.hv.hint_dma_remapping = bit(regs.eax, 6); 1882 info.virt.hv.hint_interrupt_remapping = bit(regs.eax, 7); 1883 info.virt.hv.hint_x2apic_msrs = bit(regs.eax, 8); 1884 info.virt.hv.hint_deprecate_auto_eoi = bit(regs.eax, 9); 1885 info.virt.hv.hint_synth_cluster_ipi_hypercall = bit(regs.eax, 10); 1886 info.virt.hv.hint_ex_proc_masks_interface = bit(regs.eax, 11); 1887 info.virt.hv.hint_nested_hyperv = bit(regs.eax, 12); 1888 info.virt.hv.hint_int_for_mbec_syscalls = bit(regs.eax, 13); 1889 info.virt.hv.hint_nested_enlightened_vmcs_interface = bit(regs.eax, 14); 1890 // break; 1891 // default: 1892 // } 1893 } 1894 1895 pragma(inline, false) 1896 private 1897 void ddcpuid_leaf4000_0006(ref CPUINFO info, ref REGISTERS regs) { 1898 // switch (info.virt.vendor.id) with (VirtVendor) { 1899 // case HyperV: 1900 info.virt.hv.host_feat_avic = bit(regs.eax, 0); 1901 info.virt.hv.host_feat_msr_bitmap = bit(regs.eax, 1); 1902 info.virt.hv.host_feat_perf_counter = bit(regs.eax, 2); 1903 info.virt.hv.host_feat_nested_paging = bit(regs.eax, 3); 1904 info.virt.hv.host_feat_dma_remapping = bit(regs.eax, 4); 1905 info.virt.hv.host_feat_interrupt_remapping = bit(regs.eax, 5); 1906 info.virt.hv.host_feat_mem_patrol_scrubber = bit(regs.eax, 6); 1907 info.virt.hv.host_feat_dma_prot_in_use = bit(regs.eax, 7); 1908 info.virt.hv.host_feat_hpet_requested = bit(regs.eax, 8); 1909 info.virt.hv.host_feat_stimer_volatile = bit(regs.eax, 9); 1910 // break; 1911 // default: 1912 // } 1913 } 1914 1915 pragma(inline, false) 1916 private 1917 void ddcpuid_leaf4000_0010(ref CPUINFO info, ref REGISTERS regs) { 1918 // switch (info.virt.vendor.id) with (VirtVendor) { 1919 // case VBoxMin: // VBox Minimal 1920 info.virt.vbox.tsc_freq_khz = regs.eax; 1921 info.virt.vbox.apic_freq_khz = regs.ebx; 1922 // break; 1923 // default: 1924 // } 1925 } 1926 1927 pragma(inline, false) 1928 private 1929 void ddcpuid_leaf8000_0001(ref CPUINFO info, ref REGISTERS regs) { 1930 switch (info.vendor.id) with (Vendor) { 1931 case AMD: 1932 // ecx 1933 info.virt.available = bit(regs.ecx, 2); 1934 info.sys.x2apic = bit(regs.ecx, 3); 1935 info.sse.sse4a = bit(regs.ecx, 6); 1936 info.extensions.xop = bit(regs.ecx, 11); 1937 info.extras.skinit = bit(regs.ecx, 12); 1938 info.extensions.fma4 = bit(regs.ecx, 16); 1939 info.extensions.tbm = bit(regs.ecx, 21); 1940 // edx 1941 info.extensions.mmxExtended = bit(regs.edx, 22); 1942 info.extensions._3DNowExtended = bit(regs.edx, 30); 1943 info.extensions._3DNow = regs.edx >= BIT!(31); 1944 break; 1945 default: 1946 } 1947 1948 // ecx 1949 info.extensions.lahf64 = bit(regs.ecx, 0); 1950 info.extras.lzcnt = bit(regs.ecx, 5); 1951 info.cache.prefetchw = bit(regs.ecx, 8); 1952 info.extras.monitorx = bit(regs.ecx, 29); 1953 // edx 1954 info.extras.syscall = bit(regs.edx, 11); 1955 info.memory.nx = bit(regs.edx, 20); 1956 info.memory.page1gb = bit(regs.edx, 26); 1957 info.extras.rdtscp = bit(regs.edx, 27); 1958 info.extensions.x86_64 = bit(regs.edx, 29); 1959 } 1960 1961 pragma(inline, false) 1962 private 1963 void ddcpuid_leaf8000_0007(ref CPUINFO info, ref REGISTERS regs) { 1964 switch (info.vendor.id) with (Vendor) { 1965 case Intel: 1966 info.extras.rdseed = bit(regs.ebx, 28); 1967 break; 1968 case AMD: 1969 info.sys.tm = bit(regs.edx, 4); 1970 info.tech.turboboost = bit(regs.edx, 9); 1971 break; 1972 default: 1973 } 1974 1975 info.extras.rdtscInvariant = bit(regs.edx, 8); 1976 } 1977 1978 pragma(inline, false) 1979 private 1980 void ddcpuid_leaf8000_0008(ref CPUINFO info, ref REGISTERS regs) { 1981 switch (info.vendor.id) with (Vendor) { 1982 case Intel: 1983 info.cache.wbnoinvd = bit(regs.ebx, 9); 1984 break; 1985 case AMD: 1986 info.security.ibpb = bit(regs.ebx, 12); 1987 info.security.ibrs = bit(regs.ebx, 14); 1988 info.security.stibp = bit(regs.ebx, 15); 1989 info.security.ibrsAlwaysOn = bit(regs.ebx, 16); 1990 info.security.stibpAlwaysOn = bit(regs.ebx, 17); 1991 info.security.ibrsPreferred = bit(regs.ebx, 18); 1992 info.security.ssbd = bit(regs.ebx, 24); 1993 break; 1994 default: 1995 } 1996 1997 info.memory.physBits = regs.al; 1998 info.memory.lineBits = regs.ah; 1999 } 2000 2001 pragma(inline, false) 2002 private 2003 void ddcpuid_leaf8000_000A(ref CPUINFO info, ref REGISTERS regs) { 2004 switch (info.vendor.id) { 2005 case Vendor.AMD: 2006 info.virt.version_ = regs.al; // EAX[7:0] 2007 info.virt.apicv = bit(regs.edx, 13); 2008 break; 2009 default: 2010 } 2011 } 2012 2013 pragma(inline, false) 2014 private 2015 void ddcpuid_topology(ref CPUINFO info) { 2016 ushort sc = void; /// raw cores shared across cache level 2017 ushort crshrd = void; /// actual count of shared cores 2018 ubyte type = void; /// cache type 2019 ubyte mids = void; /// maximum IDs to this cache 2020 REGISTERS regs = void; /// registers 2021 2022 info.cache.levels = 0; 2023 CACHEINFO *ca = cast(CACHEINFO*)info.cache.level; 2024 2025 //TODO: Make 1FH/BH/4H/etc. functions. 2026 switch (info.vendor.id) with (Vendor) { 2027 case Intel: 2028 if (info.maxLeaf >= 0x1f) goto L_CACHE_INTEL_1FH; 2029 if (info.maxLeaf >= 0xb) goto L_CACHE_INTEL_BH; 2030 if (info.maxLeaf >= 4) goto L_CACHE_INTEL_4H; 2031 // Celeron 0xf34 has maxLeaf=03h and ext=8000_0008h 2032 if (info.maxLeaf >= 2) goto L_CACHE_INTEL_2H; 2033 if (info.maxLeafExtended >= 0x8000_0005) goto L_CACHE_AMD_EXT_5H; 2034 break; 2035 2036 L_CACHE_INTEL_1FH: 2037 //TODO: Support levels 3,4,5 in CPUID.1FH 2038 // (Module, Tile, and Die) 2039 ddcpuid_id(regs, 0x1f, 1); // Cores (logical) 2040 info.cores.logical = regs.bx; 2041 2042 ddcpuid_id(regs, 0x1f, 0); // SMT (architectural states per core) 2043 info.cores.physical = cast(ushort)(info.cores.logical / regs.bx); 2044 2045 goto L_CACHE_INTEL_4H; 2046 2047 L_CACHE_INTEL_BH: 2048 ddcpuid_id(regs, 0xb, 1); // Cores (logical) 2049 info.cores.logical = regs.bx; 2050 2051 ddcpuid_id(regs, 0xb, 0); // SMT (architectural states per core) 2052 info.cores.physical = cast(ushort)(info.cores.logical / regs.bx); 2053 2054 L_CACHE_INTEL_4H: 2055 ddcpuid_id(regs, 4, info.cache.levels); 2056 2057 type = regs.eax & CACHE_MASK; // EAX[4:0] 2058 if (type == 0 || info.cache.levels >= CACHE_MAX_LEVEL) return; 2059 2060 ca.type = CACHE_TYPE[type]; 2061 ca.level = regs.al >> 5; 2062 ca.lineSize = (regs.bx & 0xfff) + 1; // bits 11-0 2063 ca.partitions = ((regs.ebx >> 12) & 0x3ff) + 1; // bits 21-12 2064 ca.ways = ((regs.ebx >> 22) + 1); // bits 31-22 2065 ca.sets = regs.ecx + 1; 2066 if (regs.eax & BIT!(8)) ca.features = 1; 2067 if (regs.eax & BIT!(9)) ca.features |= BIT!(1); 2068 if (regs.edx & BIT!(0)) ca.features |= BIT!(2); 2069 if (regs.edx & BIT!(1)) ca.features |= BIT!(3); 2070 if (regs.edx & BIT!(2)) ca.features |= BIT!(4); 2071 ca.size = (ca.sets * ca.lineSize * ca.partitions * ca.ways) >> 10; 2072 2073 mids = (regs.eax >> 26) + 1; // EAX[31:26] 2074 2075 if (info.cores.logical == 0) { // skip if already populated 2076 info.cores.logical = mids; 2077 info.cores.physical = info.tech.htt ? mids >> 1 : mids; 2078 } 2079 2080 crshrd = (((regs.eax >> 14) & 2047) + 1); // EAX[25:14] 2081 sc = cast(ushort)(info.cores.logical / crshrd); // cast for ldc 0.17.1 2082 ca.sharedCores = sc ? sc : 1; 2083 version (Trace) trace("intel.4h mids=%u shared=%u crshrd=%u sc=%u", 2084 mids, ca.sharedCores, crshrd, sc); 2085 2086 ++info.cache.levels; ++ca; 2087 goto L_CACHE_INTEL_4H; 2088 2089 L_CACHE_INTEL_2H: 2090 ddcpuid_id(regs, 2); 2091 ddcpuid_leaf2(info, regs); 2092 break; 2093 case AMD: 2094 if (info.maxLeafExtended >= 0x8000_001D) goto L_CACHE_AMD_EXT_1DH; 2095 if (info.maxLeafExtended >= 0x8000_0005) goto L_CACHE_AMD_EXT_5H; 2096 break; 2097 2098 /*if (info.maxLeafExtended < 0x8000_001e) goto L_AMD_TOPOLOGY_EXT_8H; 2099 2100 ddcpuid_id(regs, 0x8000_0001); 2101 2102 if (regs.ecx & BIT!(22)) { // Topology extensions support 2103 ddcpuid_id(regs, 0x8000_001e); 2104 2105 info.cores.logical = regs.ch + 1; 2106 info.cores.physical = regs.dh & 7; 2107 goto L_AMD_CACHE; 2108 }*/ 2109 2110 /*L_AMD_TOPOLOGY_EXT_8H: 2111 // See APM Volume 3 Appendix E.5 2112 // For some reason, CPUID Fn8000_001E_EBX is not mentioned there 2113 ddcpuid_id(regs, 0x8000_0008); 2114 2115 type = regs.cx >> 12; // ApicIdSize 2116 2117 if (type) { // Extended 2118 info.cores.physical = regs.cl + 1; 2119 info.cores.logical = cast(ushort)(1 << type); 2120 } else { // Legacy 2121 info.cores.logical = info.cores.physical = regs.cl + 1; 2122 }*/ 2123 2124 // 2125 // AMD newer cache method 2126 // 2127 2128 L_CACHE_AMD_EXT_1DH: // Almost the same as Intel's 2129 ddcpuid_id(regs, 0x8000_001d, info.cache.levels); 2130 2131 type = regs.eax & CACHE_MASK; // EAX[4:0] 2132 if (type == 0 || info.cache.levels >= CACHE_MAX_LEVEL) return; 2133 2134 ca.type = CACHE_TYPE[type]; 2135 ca.level = (regs.eax >> 5) & 7; 2136 ca.lineSize = (regs.ebx & 0xfff) + 1; 2137 ca.partitions = ((regs.ebx >> 12) & 0x3ff) + 1; 2138 ca.ways = (regs.ebx >> 22) + 1; 2139 ca.sets = regs.ecx + 1; 2140 if (regs.eax & BIT!(8)) ca.features = 1; 2141 if (regs.eax & BIT!(9)) ca.features |= BIT!(1); 2142 if (regs.edx & BIT!(0)) ca.features |= BIT!(2); 2143 if (regs.edx & BIT!(1)) ca.features |= BIT!(3); 2144 ca.size = (ca.sets * ca.lineSize * ca.partitions * ca.ways) >> 10; 2145 2146 crshrd = (((regs.eax >> 14) & 0xfff) + 1); // bits 25-14 2147 sc = cast(ushort)(info.sys.maxApicId / crshrd); // cast for ldc 0.17.1 2148 ca.sharedCores = sc ? sc : 1; 2149 2150 if (info.cores.logical == 0) with (info.cores) { // skip if already populated 2151 logical = info.sys.maxApicId; 2152 physical = info.tech.htt ? logical >> 1 : info.sys.maxApicId; 2153 } 2154 2155 version (Trace) trace("amd.8000_001Dh mids=%u shared=%u crshrd=%u sc=%u", 2156 mids, ca.sharedCores, crshrd, sc); 2157 2158 ++info.cache.levels; ++ca; 2159 goto L_CACHE_AMD_EXT_1DH; 2160 2161 // 2162 // AMD legacy cache 2163 // 2164 2165 L_CACHE_AMD_EXT_5H: 2166 ddcpuid_id(regs, 0x8000_0005); 2167 2168 info.cache.level[0].level = 1; // L1-D 2169 info.cache.level[0].type = 'D'; // data 2170 info.cache.level[0].size = regs.ecx >> 24; 2171 info.cache.level[0].ways = cast(ubyte)(regs.ecx >> 16); 2172 info.cache.level[0].lines = regs.ch; 2173 info.cache.level[0].lineSize = regs.cl; 2174 info.cache.level[0].sets = 1; 2175 2176 info.cache.level[1].level = 1; // L1-I 2177 info.cache.level[1].type = 'I'; // instructions 2178 info.cache.level[1].size = regs.edx >> 24; 2179 info.cache.level[1].ways = cast(ubyte)(regs.edx >> 16); 2180 info.cache.level[1].lines = regs.dh; 2181 info.cache.level[1].lineSize = regs.dl; 2182 info.cache.level[1].sets = 1; 2183 2184 info.cache.levels = 2; 2185 2186 if (info.maxLeafExtended < 0x8000_0006) 2187 return; // No L2/L3 2188 2189 // See Table E-4. L2/L3 Cache and TLB Associativity Field Encoding 2190 static immutable ubyte[16] _amd_cache_ways = [ 2191 // 7h is reserved 2192 // 9h mentions 8000_001D but that's already supported 2193 0, 1, 2, 3, 4, 6, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255 2194 ]; 2195 2196 ddcpuid_id(regs, 0x8000_0006); 2197 2198 type = regs.cx >> 12; // amd_ways_l2 2199 if (type) { 2200 info.cache.level[2].level = 2; // L2 2201 info.cache.level[2].type = 'U'; // unified 2202 info.cache.level[2].size = regs.ecx >> 16; 2203 info.cache.level[2].ways = _amd_cache_ways[type]; 2204 info.cache.level[2].lines = regs.ch & 0xf; 2205 info.cache.level[2].lineSize = regs.cl; 2206 info.cache.level[2].sets = 1; 2207 info.cache.levels = 3; 2208 2209 type = regs.dx >> 12; // amd_ways_l3 2210 if (type) { 2211 info.cache.level[3].level = 3; // L3 2212 info.cache.level[3].type = 'U'; // unified 2213 info.cache.level[3].size = ((regs.edx >> 18) + 1) << 9; 2214 info.cache.level[3].ways = _amd_cache_ways[type]; 2215 info.cache.level[3].lines = regs.dh & 0xf; 2216 info.cache.level[3].lineSize = regs.dl & 0x7F; 2217 info.cache.level[3].sets = 1; 2218 info.cache.levels = 4; 2219 } 2220 } 2221 return; 2222 default: 2223 } 2224 2225 with (info) cores.physical = cores.logical = 1; 2226 } 2227 2228 private struct LeafInfo { 2229 uint leaf; 2230 uint sub; 2231 void function(ref CPUINFO, ref REGISTERS) func; 2232 } 2233 private struct LeafExtInfo { 2234 uint leaf; 2235 void function(ref CPUINFO, ref REGISTERS) func; 2236 } 2237 2238 /// Fetch CPU information. 2239 /// Params: info = CPUINFO structure 2240 pragma(inline, false) 2241 void ddcpuid_cpuinfo(ref CPUINFO info) { 2242 static immutable LeafInfo[] regulars = [ 2243 { 0x1, 0, &ddcpuid_leaf1 }, // Sets brand index 2244 { 0x5, 0, &ddcpuid_leaf5 }, 2245 { 0x6, 0, &ddcpuid_leaf6 }, 2246 { 0x7, 0, &ddcpuid_leaf7 }, 2247 { 0x7, 1, &ddcpuid_leaf7sub1 }, 2248 { 0xd, 0, &ddcpuid_leafD }, 2249 { 0xd, 1, &ddcpuid_leafDsub1 }, 2250 { 0x12, 0, &ddcpuid_leaf12 }, 2251 ]; 2252 static immutable LeafExtInfo[] extended = [ 2253 { 0x8000_0001, &ddcpuid_leaf8000_0001 }, 2254 { 0x8000_0007, &ddcpuid_leaf8000_0007 }, 2255 { 0x8000_0008, &ddcpuid_leaf8000_0008 }, 2256 { 0x8000_000a, &ddcpuid_leaf8000_000A }, 2257 ]; 2258 REGISTERS regs = void; /// registers 2259 2260 ddcpuid_vendor(info.vendor.string_); 2261 info.vendor.id = ddcpuid_vendor_id(info.vendor); 2262 2263 foreach (ref immutable(LeafInfo) l; regulars) { 2264 if (l.leaf > info.maxLeaf) break; 2265 2266 ddcpuid_id(regs, l.leaf, l.sub); 2267 l.func(info, regs); 2268 } 2269 2270 // Paravirtualization leaves 2271 if (info.maxLeafVirt >= 0x4000_0000) { 2272 ddcpuid_virt_vendor(info.virt.vendor.string_); 2273 info.virt.vendor.id = ddcpuid_virt_vendor_id(info.virt.vendor); 2274 2275 switch (info.virt.vendor.id) with (VirtVendor) { 2276 case KVM: 2277 ddcpuid_id(regs, 0x4000_0001); 2278 ddcpuid_leaf4000_0001(info, regs); 2279 break; 2280 case HyperV: 2281 ddcpuid_id(regs, 0x4000_0002); 2282 ddcpuid_leaf4000_0002(info, regs); 2283 ddcpuid_id(regs, 0x4000_0003); 2284 ddcpuid_leaf4000_0003(info, regs); 2285 ddcpuid_id(regs, 0x4000_0004); 2286 ddcpuid_leaf4000_0004(info, regs); 2287 ddcpuid_id(regs, 0x4000_0006); 2288 ddcpuid_leaf4000_0006(info, regs); 2289 break; 2290 case VBoxMin: 2291 ddcpuid_id(regs, 0x4000_0010); 2292 ddcpuid_leaf4000_0010(info, regs); 2293 break; 2294 default: 2295 } 2296 } 2297 2298 // Extended leaves 2299 if (info.maxLeafExtended >= 0x8000_0000) { 2300 foreach (ref immutable(LeafExtInfo) l; extended) { 2301 if (l.leaf > info.maxLeafExtended) break; 2302 2303 ddcpuid_id(regs, l.leaf); 2304 l.func(info, regs); 2305 } 2306 } 2307 2308 ddcpuid_model_string(info); // Sets brand string 2309 ddcpuid_topology(info); // Sets core/thread/cache topology 2310 } 2311 2312 const(char) *ddcpuid_baseline(ref CPUINFO info) { 2313 if (info.extensions.x86_64 == false) { 2314 if (info.family >= 6) // Pentium Pro / II 2315 return "i686"; 2316 // NOTE: K7 is still family 5 and didn't have SSE2. 2317 return info.family == 5 ? "i586" : "i486"; // Pentium / MMX 2318 } 2319 2320 // v4 2321 if (info.avx.avx512f && info.avx.avx512bw && 2322 info.avx.avx512cd && info.avx.avx512dq && 2323 info.avx.avx512vl) { 2324 return "x86-64-v4"; 2325 } 2326 2327 // v3 2328 if (info.avx.avx2 && info.avx.avx && 2329 info.extensions.bmi2 && info.extensions.bmi1 && 2330 info.extensions.f16c && info.extensions.fma3 && 2331 info.extras.lzcnt && info.extras.movbe && 2332 info.extras.osxsave) { 2333 return "x86-64-v3"; 2334 } 2335 2336 // v2 2337 if (info.sse.sse42 && info.sse.sse41 && 2338 info.sse.ssse3 && info.sse.sse3 && 2339 info.extensions.lahf64 && info.extras.popcnt && 2340 info.extras.cmpxchg16b) { 2341 return "x86-64-v2"; 2342 } 2343 2344 // baseline (v1) 2345 /*if (info.sse.sse2 && info.sse.sse && 2346 info.extensions.mmx && info.extras.fxsr && 2347 info.extras.cmpxchg8b && info.extras.cmov && 2348 info.extensions.fpu && info.extras.syscall) { 2349 return "x86-64"; 2350 }*/ 2351 2352 return "x86-64"; // v1 anyway 2353 }