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-rc"; /// 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 pragma(inline, false) 1172 private 1173 void ddcpuid_model_string(ref CPUINFO info) { 1174 switch (info.vendor.id) with (Vendor) { 1175 case Intel: 1176 // Brand string 1177 if (info.maxLeafExtended >= 0x8000_0004) 1178 ddcpuid_extended_brand(info.brandString); 1179 else if (info.brandIndex) 1180 ddcpuid_intel_brand_index(info, info.brandIndex); 1181 else 1182 ddcpuid_intel_brand_family(info); 1183 return; 1184 case AMD, VIA: 1185 // Brand string 1186 // NOTE: AMD processor never supported the string table. 1187 // The Am486DX4 and Am5x86 processors do not support the extended brand string. 1188 // The K5 model 0 does not support the extended brand string. 1189 // The K5 model 1, 2, and 3 support the extended brand string. 1190 if (info.maxLeafExtended >= 0x8000_0004) 1191 ddcpuid_extended_brand(info.brandString); 1192 else 1193 ddcpuid_amd_brand_family(info); 1194 return; 1195 default: 1196 strcpy48(info.brandString, "Unknown"); 1197 return; 1198 } 1199 } 1200 1201 pragma(inline, false) 1202 private 1203 void ddcpuid_leaf1(ref CPUINFO info, ref REGISTERS regs) { 1204 // EAX 1205 info.identifier = regs.eax; 1206 info.stepping = regs.eax & 15; // EAX[3:0] 1207 info.modelBase = regs.eax >> 4 & 15; // EAX[7:4] 1208 info.familyBase = regs.eax >> 8 & 15; // EAX[11:8] 1209 info.type = regs.eax >> 12 & 3; // EAX[13:12] 1210 info.typeString = PROCESSOR_TYPE[info.type]; 1211 info.modelExtended = regs.eax >> 16 & 15; // EAX[19:16] 1212 info.familyExtended = cast(ubyte)(regs.eax >> 20); // EAX[27:20] 1213 1214 switch (info.vendor.id) with (Vendor) { 1215 case Intel: 1216 info.family = info.familyBase != 15 ? 1217 cast(ushort)info.familyBase : 1218 cast(ushort)(info.familyExtended + info.familyBase); 1219 1220 info.model = info.familyBase == 6 || info.familyBase == 0 ? 1221 cast(ushort)((info.modelExtended << 4) + info.modelBase) : 1222 cast(ushort)info.modelBase; // DisplayModel = Model_ID; 1223 1224 // ECX 1225 info.debugging.dtes64 = bit(regs.ecx, 2); 1226 info.debugging.ds_cpl = bit(regs.ecx, 4); 1227 info.virt.available = bit(regs.ecx, 5); 1228 info.tech.smx = bit(regs.ecx, 6); 1229 info.tech.eist = bit(regs.ecx, 7); 1230 info.sys.tm2 = bit(regs.ecx, 8); 1231 info.cache.cnxtId = bit(regs.ecx, 10); 1232 info.debugging.sdbg = bit(regs.ecx, 11); 1233 info.misc.xtpr = bit(regs.ecx, 14); 1234 info.debugging.pdcm = bit(regs.ecx, 15); 1235 info.misc.pcid = bit(regs.ecx, 17); 1236 info.debugging.mca = bit(regs.ecx, 18); 1237 info.sys.x2apic = bit(regs.ecx, 21); 1238 info.extras.rdtscDeadline = bit(regs.ecx, 24); 1239 1240 // EDX 1241 info.misc.psn = bit(regs.edx, 18); 1242 info.debugging.ds = bit(regs.edx, 21); 1243 info.sys.available = bit(regs.edx, 22); 1244 info.cache.ss = bit(regs.edx, 27); 1245 info.sys.tm = bit(regs.edx, 29); 1246 info.debugging.pbe = regs.edx >= BIT!(31); 1247 break; 1248 case AMD: 1249 if (info.familyBase < 15) { 1250 info.family = info.familyBase; 1251 info.model = info.modelBase; 1252 } else { 1253 info.family = cast(ushort)(info.familyExtended + info.familyBase); 1254 info.model = cast(ushort)((info.modelExtended << 4) + info.modelBase); 1255 } 1256 break; 1257 default: 1258 } 1259 1260 // EBX 1261 info.sys.apicId = regs.ebx >> 24; 1262 info.sys.maxApicId = cast(ubyte)(regs.ebx >> 16); 1263 info.cache.clflushLinesize = regs.bh; 1264 info.brandIndex = regs.bl; 1265 1266 // ECX 1267 info.sse.sse3 = bit(regs.ecx, 0); 1268 info.extras.pclmulqdq = bit(regs.ecx, 1); 1269 info.extras.monitor = bit(regs.ecx, 3); 1270 info.sse.ssse3 = bit(regs.ecx, 9); 1271 info.extensions.fma3 = bit(regs.ecx, 12); 1272 info.extras.cmpxchg16b = bit(regs.ecx, 13); 1273 info.sse.sse41 = bit(regs.ecx, 15); 1274 info.sse.sse42 = bit(regs.ecx, 20); 1275 info.extras.movbe = bit(regs.ecx, 22); 1276 info.extras.popcnt = bit(regs.ecx, 23); 1277 info.extensions.aes_ni = bit(regs.ecx, 25); 1278 info.extras.xsave = bit(regs.ecx, 26); 1279 info.extras.osxsave = bit(regs.ecx, 27); 1280 info.avx.avx = bit(regs.ecx, 28); 1281 info.extensions.f16c = bit(regs.ecx, 29); 1282 info.extras.rdrand = bit(regs.ecx, 30); 1283 1284 // EDX 1285 info.extensions.fpu = bit(regs.edx, 0); 1286 info.virt.vme = bit(regs.edx, 1); 1287 info.debugging.de = bit(regs.edx, 2); 1288 info.memory.pse = bit(regs.edx, 3); 1289 info.extras.rdtsc = bit(regs.edx, 4); 1290 info.extras.rdmsr = bit(regs.edx, 5); 1291 info.memory.pae = bit(regs.edx, 6); 1292 info.debugging.mce = bit(regs.edx, 7); 1293 info.extras.cmpxchg8b = bit(regs.edx, 8); 1294 info.sys.apic = bit(regs.edx, 9); 1295 info.extras.sysenter = bit(regs.edx, 11); 1296 info.memory.mtrr = bit(regs.edx, 12); 1297 info.memory.pge = bit(regs.edx, 13); 1298 info.debugging.mca = bit(regs.edx, 14); 1299 info.extras.cmov = bit(regs.edx, 15); 1300 info.memory.pat = bit(regs.edx, 16); 1301 info.memory.pse36 = bit(regs.edx, 17); 1302 info.cache.clflush = bit(regs.edx, 19); 1303 info.extensions.mmx = bit(regs.edx, 23); 1304 info.extras.fxsr = bit(regs.edx, 24); 1305 info.sse.sse = bit(regs.edx, 25); 1306 info.sse.sse2 = bit(regs.edx, 26); 1307 info.tech.htt = bit(regs.edx, 28); 1308 } 1309 1310 //NOTE: Only Intel officially supports CPUID.02h 1311 // No dedicated functions to a cache descriptor to avoid a definition. 1312 pragma(inline, false) 1313 private 1314 void ddcpuid_leaf2(ref CPUINFO info, ref REGISTERS regs) { 1315 struct leaf2_t { 1316 union { 1317 REGISTERS registers; 1318 ubyte[16] values; 1319 } 1320 } 1321 leaf2_t data = void; 1322 1323 if (regs.eax < 0x8000_0000) { // valid bit, adjust byte positions 1324 data.values[3] = data.values[2]; 1325 data.values[2] = data.values[1]; 1326 data.values[1] = data.values[0]; 1327 } 1328 1329 // Simulate CPUID.04h 1330 enum L1I = 0; 1331 enum L1D = 1; 1332 enum L2 = 2; 1333 enum L3 = 3; 1334 for (size_t index = 1; index < 16; ++index) { 1335 ubyte value = data.values[index]; 1336 1337 // Cache entries only, the rest is "don't care". 1338 // Unless if one day I support looking up TLB data, but AMD does not support this. 1339 // continue: Explicitly skip cache, this includes 0x00 (null), 0x40 (no L2 or L3). 1340 // break: Valid cache descriptor, increment cache level. 1341 //TODO: table + foreach loop 1342 with (info.cache) switch (value) { 1343 case 0x06: // 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size 1344 level[L1I] = CACHEINFO(1, 'I', 8, 1, 4, 1, 32, 64); 1345 break; 1346 case 0x08: // 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size 1347 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 32, 128); 1348 break; 1349 case 0x09: // 1st-level instruction cache: 32 KBytes, 4-way set associative, 64 byte line size 1350 level[L1I] = CACHEINFO(1, 'I', 32, 1, 4, 1, 64, 128); 1351 break; 1352 case 0x0A: // 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size 1353 level[L1D] = CACHEINFO(1, 'D', 8, 1, 2, 1, 32, 128); 1354 break; 1355 case 0x0C: // 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size 1356 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 32, 128); 1357 break; 1358 case 0x0D: // 1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size (ECC?) 1359 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 64, 64); 1360 break; 1361 case 0x0E: // 1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size 1362 level[L1D] = CACHEINFO(1, 'D', 24, 1, 6, 1, 64, 64); 1363 break; 1364 case 0x10: // (sandpile) data L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64) 1365 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 32, 64); 1366 break; 1367 case 0x15: // (sandpile) code L1 cache, 16 KB, 4 ways, 32 byte lines (IA-64) 1368 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 32, 64); 1369 break; 1370 case 0x1a: // (sandpile) code and data L2 cache, 96 KB, 6 ways, 64 byte lines (IA-64) 1371 level[L2] = CACHEINFO(2, 'I', 96, 1, 6, 1, 64, 256); 1372 break; 1373 case 0x1D: // 2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size 1374 level[L2] = CACHEINFO(2, 'U', 128, 1, 2, 1, 64, 1024); 1375 break; 1376 case 0x21: // 2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size 1377 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 64, 512); 1378 break; 1379 case 0x22: // 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector 1380 level[L3] = CACHEINFO(3, 'U', 512, 1, 4, 2, 64, 1024); 1381 break; 1382 case 0x23: // 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1383 level[L3] = CACHEINFO(3, 'U', 1024, 1, 8, 2, 64, 1024); 1384 break; 1385 case 0x24: // 2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size 1386 level[L2] = CACHEINFO(2, 'U', 1024, 1, 16, 1, 64, 1024); 1387 break; 1388 case 0x25: // 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1389 level[L3] = CACHEINFO(3, 'U', 2048, 1, 8, 2, 64, 2048); 1390 break; 1391 case 0x29: // 3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector 1392 level[L3] = CACHEINFO(3, 'U', 4096, 1, 8, 2, 64, 4096); 1393 break; 1394 case 0x2C: // 1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size 1395 level[L1D] = CACHEINFO(1, 'D', 32, 1, 8, 1, 64, 64); 1396 break; 1397 case 0x30: // 1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size 1398 level[L1I] = CACHEINFO(1, 'I', 32, 1, 8, 1, 64, 64); 1399 break; 1400 case 0x39: // (sandpile) code and data L2 cache, 128 KB, 4 ways, 64 byte lines, sectored (htt?) 1401 level[L2] = CACHEINFO(2, 'U', 128, 1, 4, 1, 64, 512); 1402 break; 1403 case 0x3A: // (sandpile) code and data L2 cache, 192 KB, 6 ways, 64 byte lines, sectored (htt?) 1404 level[L2] = CACHEINFO(2, 'U', 192, 1, 6, 1, 64, 512); 1405 break; 1406 case 0x3B: // (sandpile) code and data L2 cache, 128 KB, 2 ways, 64 byte lines, sectored (htt?) 1407 level[L2] = CACHEINFO(2, 'U', 128, 1, 2, 1, 64, 1024); 1408 break; 1409 case 0x3C: // (sandpile) code and data L2 cache, 256 KB, 4 ways, 64 byte lines, sectored 1410 level[L2] = CACHEINFO(2, 'U', 256, 1, 4, 1, 64, 1024); 1411 break; 1412 case 0x3D: // (sandpile) code and data L2 cache, 384 KB, 6 ways, 64 byte lines, sectored (htt?) 1413 level[L2] = CACHEINFO(2, 'U', 384, 1, 6, 1, 64, 1024); 1414 break; 1415 case 0x3E: // (sandpile) code and data L2 cache, 512 KB, 4 ways, 64 byte lines, sectored (htt?) 1416 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 64, 2048); 1417 break; 1418 case 0x41: // 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size 1419 level[L2] = CACHEINFO(2, 'U', 128, 1, 4, 1, 32, 1024); 1420 break; 1421 case 0x42: // 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size 1422 level[L2] = CACHEINFO(2, 'U', 256, 1, 4, 1, 32, 2048); 1423 break; 1424 case 0x43: // 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size 1425 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 32, 4096); 1426 break; 1427 case 0x44: // 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size 1428 level[L2] = CACHEINFO(2, 'U', 1024, 1, 4, 1, 32, 8192); 1429 break; 1430 case 0x45: // 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size 1431 level[L2] = CACHEINFO(2, 'U', 2048, 1, 4, 1, 32, 16384); 1432 break; 1433 case 0x46: // 3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size 1434 level[L2] = CACHEINFO(2, 'U', 4096, 1, 4, 1, 64, 16384); 1435 break; 1436 case 0x47: // 3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size 1437 level[L3] = CACHEINFO(3, 'U', 8192, 1, 8, 1, 64, 16384); 1438 break; 1439 case 0x48: // 2nd-level cache: 3 MByte, 12-way set associative, 64 byte line size 1440 level[L2] = CACHEINFO(2, 'U', 3072, 1, 12, 1, 64, 4096); 1441 break; 1442 // 3rd-level cache: 4 MByte, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 1443 // 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size 1444 case 0x49: 1445 if (info.family == 0xf && info.family == 6) 1446 level[L3] = CACHEINFO(3, 'U', 4096, 1, 16, 1, 64, 4096); 1447 else 1448 level[L2] = CACHEINFO(2, 'U', 4096, 1, 16, 1, 64, 4096); 1449 break; 1450 case 0x4A: // 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size 1451 level[L3] = CACHEINFO(3, 'U', 6144, 1, 12, 1, 64, 6144); 1452 break; 1453 case 0x4B: // 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size 1454 level[L3] = CACHEINFO(3, 'U', 8192, 1, 16, 1, 64, 8192); 1455 break; 1456 case 0x4C: // 3rd-level cache: 12 MByte, 12-way set associative, 64 byte line size 1457 level[L3] = CACHEINFO(3, 'U', 8192, 1, 12, 1, 64, 16384); 1458 break; 1459 case 0x4D: // 3rd-level cache: 16 MByte, 16-way set associative, 64 byte line size 1460 level[L3] = CACHEINFO(3, 'U', 16384, 1, 16, 1, 64, 16384); 1461 break; 1462 case 0x4E: // 2nd-level cache: 6MByte, 24-way set associative, 64 byte line size 1463 level[L2] = CACHEINFO(2, 'U', 6144, 1, 24, 1, 64, 4096); 1464 break; 1465 case 0x60: // 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size 1466 level[L1D] = CACHEINFO(1, 'D', 16, 1, 8, 1, 64, 32); 1467 break; 1468 case 0x66: // 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size 1469 level[L1D] = CACHEINFO(1, 'D', 8, 1, 4, 1, 64, 32); 1470 break; 1471 case 0x67: // 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size 1472 level[L1D] = CACHEINFO(1, 'D', 16, 1, 4, 1, 64, 64); 1473 break; 1474 case 0x68: // 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size 1475 level[L1D] = CACHEINFO(1, 'D', 32, 1, 4, 1, 64, 128); 1476 break; 1477 case 0x77: // (sandpile) code L1 cache, 16 KB, 4 ways, 64 byte lines, sectored (IA-64) 1478 level[L1I] = CACHEINFO(1, 'I', 16, 1, 4, 1, 64, 64); 1479 break; 1480 case 0x78: // 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size 1481 level[L2] = CACHEINFO(2, 'U', 1024, 1, 4, 1, 64, 4096); 1482 break; 1483 case 0x79: // 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1484 level[L2] = CACHEINFO(2, 'U', 128, 1, 8, 2, 64, 128); 1485 break; 1486 case 0x7A: // 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1487 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 2, 64, 256); 1488 break; 1489 case 0x7B: // 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector 1490 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 2, 64, 512); 1491 break; 1492 case 0x7C: // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector 1493 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 2, 64, 1024); 1494 break; 1495 case 0x7D: // 2nd-level cache: 2 MByte, 8-way set associative, 64 byte line size 1496 level[L2] = CACHEINFO(2, 'U', 2048, 1, 8, 1, 64, 4096); 1497 break; 1498 case 0x7E: // (sandpile) code and data L2 cache, 256 KB, 8 ways, 128 byte lines, sect. (IA-64) 1499 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 128, 256); 1500 break; 1501 case 0x7F: // 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size 1502 level[L2] = CACHEINFO(2, 'U', 512, 1, 2, 1, 64, 4096); 1503 break; 1504 case 0x80: // 2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size 1505 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 1, 64, 1024); 1506 break; 1507 case 0x81: // (sandpile) code and data L2 cache, 128 KB, 8 ways, 32 byte lines 1508 level[L2] = CACHEINFO(2, 'U', 128, 1, 8, 1, 32, 512); 1509 break; 1510 case 0x82: // 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size 1511 level[L2] = CACHEINFO(2, 'U', 256, 1, 8, 1, 32, 1024); 1512 break; 1513 case 0x83: // 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size 1514 level[L2] = CACHEINFO(2, 'U', 512, 1, 8, 1, 32, 2048); 1515 break; 1516 case 0x84: // 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size 1517 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 1, 32, 4096); 1518 break; 1519 case 0x85: // 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size 1520 level[L2] = CACHEINFO(2, 'U', 2048, 1, 8, 1, 32, 8192); 1521 break; 1522 case 0x86: // 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size 1523 level[L2] = CACHEINFO(2, 'U', 512, 1, 4, 1, 64, 2048); 1524 break; 1525 case 0x87: // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size 1526 level[L2] = CACHEINFO(2, 'U', 1024, 1, 8, 1, 64, 2048); 1527 break; 1528 case 0xD0: // 3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size 1529 level[L3] = CACHEINFO(3, 'U', 512, 1, 4, 1, 64, 2048); 1530 break; 1531 case 0xD1: // 3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size 1532 level[L3] = CACHEINFO(3, 'U', 1024, 1, 4, 1, 64, 4096); 1533 break; 1534 case 0xD2: // 3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size 1535 level[L3] = CACHEINFO(3, 'U', 2048, 1, 4, 1, 64, 8192); 1536 break; 1537 case 0xD6: // 3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size 1538 level[L3] = CACHEINFO(3, 'U', 1024, 1, 8, 1, 64, 2048); 1539 break; 1540 case 0xD7: // 3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size 1541 level[L3] = CACHEINFO(3, 'U', 2048, 1, 8, 1, 64, 4096); 1542 break; 1543 case 0xD8: // 3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size 1544 level[L3] = CACHEINFO(3, 'U', 4096, 1, 8, 1, 64, 8192); 1545 break; 1546 case 0xDC: // 3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size 1547 level[L3] = CACHEINFO(3, 'U', 1536, 1, 12, 1, 64, 2048); 1548 break; 1549 case 0xDD: // 3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size 1550 level[L3] = CACHEINFO(3, 'U', 3072, 1, 12, 1, 64, 4096); 1551 break; 1552 case 0xDE: // 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size 1553 level[L3] = CACHEINFO(3, 'U', 6144, 1, 12, 1, 64, 8192); 1554 break; 1555 case 0xE2: // 3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size 1556 level[L3] = CACHEINFO(3, 'U', 2048, 1, 16, 1, 64, 2048); 1557 break; 1558 case 0xE3: // 3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size 1559 level[L3] = CACHEINFO(3, 'U', 4096, 1, 16, 1, 64, 4096); 1560 break; 1561 case 0xE4: // 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size 1562 level[L3] = CACHEINFO(3, 'U', 8192, 1, 16, 1, 64, 8192); 1563 break; 1564 case 0xEA: // 3rd-level cache: 12MByte, 24-way set associative, 64 byte line size 1565 level[L3] = CACHEINFO(3, 'U', 12288, 1, 24, 1, 64, 8192); 1566 break; 1567 case 0xEB: // 3rd-level cache: 18MByte, 24-way set associative, 64 byte line size 1568 level[L3] = CACHEINFO(3, 'U', 18432, 1, 24, 1, 64, 12288); 1569 break; 1570 case 0xEC: // 3rd-level cache: 24MByte, 24-way set associative, 64 byte line size 1571 level[L3] = CACHEINFO(3, 'U', 24576, 1, 24, 1, 64, 16384); 1572 break; 1573 default: continue; 1574 } 1575 1576 ++info.cache.levels; 1577 } 1578 } 1579 1580 pragma(inline, false) 1581 private 1582 void ddcpuid_leaf5(ref CPUINFO info, ref REGISTERS regs) { 1583 info.extras.mwaitMin = regs.ax; 1584 info.extras.mwaitMax = regs.bx; 1585 } 1586 1587 pragma(inline, false) 1588 private 1589 void ddcpuid_leaf6(ref CPUINFO info, ref REGISTERS regs) { 1590 switch (info.vendor.id) with (Vendor) { 1591 case Intel: 1592 info.tech.turboboost = bit(regs.eax, 1); 1593 info.tech.turboboost30 = bit(regs.eax, 14); 1594 break; 1595 default: 1596 } 1597 1598 info.sys.arat = bit(regs.eax, 2); 1599 } 1600 1601 pragma(inline, false) 1602 private 1603 void ddcpuid_leaf7(ref CPUINFO info, ref REGISTERS regs) { 1604 switch (info.vendor.id) with (Vendor) { 1605 case Intel: 1606 // EBX 1607 info.sgx.supported = bit(regs.ebx, 2); 1608 info.memory.hle = bit(regs.ebx, 4); 1609 info.cache.invpcid = bit(regs.ebx, 10); 1610 info.memory.rtm = bit(regs.ebx, 11); 1611 info.avx.avx512f = bit(regs.ebx, 16); 1612 info.memory.smap = bit(regs.ebx, 20); 1613 info.avx.avx512er = bit(regs.ebx, 27); 1614 info.avx.avx512pf = bit(regs.ebx, 26); 1615 info.avx.avx512cd = bit(regs.ebx, 28); 1616 info.avx.avx512dq = bit(regs.ebx, 17); 1617 info.avx.avx512bw = bit(regs.ebx, 30); 1618 info.avx.avx512_ifma = bit(regs.ebx, 21); 1619 info.avx.avx512_vbmi = regs.ebx >= BIT!(31); 1620 // ECX 1621 info.avx.avx512vl = bit(regs.ecx, 1); 1622 info.memory.pku = bit(regs.ecx, 3); 1623 info.memory.fsrepmov = bit(regs.ecx, 4); 1624 info.extensions.waitpkg = bit(regs.ecx, 5); 1625 info.avx.avx512_vbmi2 = bit(regs.ecx, 6); 1626 info.security.cetSs = bit(regs.ecx, 7); 1627 info.avx.avx512_gfni = bit(regs.ecx, 8); 1628 info.avx.avx512_vaes = bit(regs.ecx, 9); 1629 info.avx.avx512_vnni = bit(regs.ecx, 11); 1630 info.avx.avx512_bitalg = bit(regs.ecx, 12); 1631 info.avx.avx512_vpopcntdq = bit(regs.ecx, 14); 1632 info.memory._5pl = bit(regs.ecx, 16); 1633 info.extras.cldemote = bit(regs.ecx, 25); 1634 info.extras.movdiri = bit(regs.ecx, 27); 1635 info.extras.movdir64b = bit(regs.ecx, 28); 1636 info.extras.enqcmd = bit(regs.ecx, 29); 1637 // EDX 1638 info.avx.avx512_4vnniw = bit(regs.edx, 2); 1639 info.avx.avx512_4fmaps = bit(regs.edx, 3); 1640 info.misc.uintr = bit(regs.edx, 5); 1641 info.avx.avx512_vp2intersect = bit(regs.edx, 8); 1642 info.security.md_clear = bit(regs.edx, 10); 1643 info.extras.serialize = bit(regs.edx, 14); 1644 info.memory.tsxldtrk = bit(regs.edx, 16); 1645 info.extras.pconfig = bit(regs.edx, 18); 1646 info.security.cetIbt = bit(regs.edx, 20); 1647 info.amx.bf16 = bit(regs.edx, 22); 1648 info.amx.enabled = bit(regs.edx, 24); 1649 info.amx.int8 = bit(regs.edx, 25); 1650 info.security.ibrs = bit(regs.edx, 26); 1651 info.security.stibp = bit(regs.edx, 27); 1652 info.security.l1dFlush = bit(regs.edx, 28); 1653 info.security.ia32_arch_capabilities = bit(regs.edx, 29); 1654 info.security.ssbd = regs.edx >= BIT!(31); 1655 break; 1656 default: 1657 } 1658 1659 // ebx 1660 info.misc.fsgsbase = bit(regs.ebx, 0); 1661 info.extensions.bmi1 = bit(regs.ebx, 3); 1662 info.avx.avx2 = bit(regs.ebx, 5); 1663 info.memory.smep = bit(regs.ebx, 7); 1664 info.extensions.bmi2 = bit(regs.ebx, 8); 1665 info.extras.rdseed = bit(regs.ebx, 18); 1666 info.extensions.adx = bit(regs.ebx, 19); 1667 info.cache.clflushopt = bit(regs.ebx, 23); 1668 info.extensions.sha = bit(regs.ebx, 29); 1669 // ecx 1670 info.extras.rdpid = bit(regs.ecx, 22); 1671 } 1672 1673 pragma(inline, false) 1674 private 1675 void ddcpuid_leaf7sub1(ref CPUINFO info, ref REGISTERS regs) { 1676 switch (info.vendor.id) with (Vendor) { 1677 case Intel: 1678 // a 1679 info.avx.avx512_bf16 = bit(regs.eax, 5); 1680 info.memory.lam = bit(regs.eax, 26); 1681 break; 1682 default: 1683 } 1684 } 1685 1686 pragma(inline, false) 1687 private 1688 void ddcpuid_leafD(ref CPUINFO info, ref REGISTERS regs) { 1689 switch (info.vendor.id) with (Vendor) { 1690 case Intel: 1691 info.amx.xtilecfg = bit(regs.eax, 17); 1692 info.amx.xtiledata = bit(regs.eax, 18); 1693 break; 1694 default: 1695 } 1696 } 1697 1698 pragma(inline, false) 1699 private 1700 void ddcpuid_leafDsub1(ref CPUINFO info, ref REGISTERS regs) { 1701 switch (info.vendor.id) with (Vendor) { 1702 case Intel: 1703 info.amx.xfd = bit(regs.eax, 18); 1704 break; 1705 default: 1706 } 1707 } 1708 1709 pragma(inline, false) 1710 private 1711 void ddcpuid_leaf12(ref CPUINFO info, ref REGISTERS regs) { 1712 switch (info.vendor.id) with (Vendor) { 1713 case Intel: 1714 info.sgx.sgx1 = bit(regs.al, 0); 1715 info.sgx.sgx2 = bit(regs.al, 1); 1716 info.sgx.maxSize = regs.dl; 1717 info.sgx.maxSize64 = regs.dh; 1718 break; 1719 default: 1720 } 1721 } 1722 1723 pragma(inline, false) 1724 private 1725 void ddcpuid_leaf4000_0001(ref CPUINFO info, ref REGISTERS regs) { 1726 // switch (info.virt.vendor.id) with (VirtVendor) { 1727 // case KVM: 1728 info.virt.kvm.feature_clocksource = bit(regs.eax, 0); 1729 info.virt.kvm.feature_nop_io_delay = bit(regs.eax, 1); 1730 info.virt.kvm.feature_mmu_op = bit(regs.eax, 2); 1731 info.virt.kvm.feature_clocksource2 = bit(regs.eax, 3); 1732 info.virt.kvm.feature_async_pf = bit(regs.eax, 4); 1733 info.virt.kvm.feature_steal_time = bit(regs.eax, 5); 1734 info.virt.kvm.feature_pv_eoi = bit(regs.eax, 6); 1735 info.virt.kvm.feature_pv_unhault = bit(regs.eax, 7); 1736 info.virt.kvm.feature_pv_tlb_flush = bit(regs.eax, 9); 1737 info.virt.kvm.feature_async_pf_vmexit = bit(regs.eax, 10); 1738 info.virt.kvm.feature_pv_send_ipi = bit(regs.eax, 11); 1739 info.virt.kvm.feature_pv_poll_control = bit(regs.eax, 12); 1740 info.virt.kvm.feature_pv_sched_yield = bit(regs.eax, 13); 1741 info.virt.kvm.feature_clocsource_stable_bit = bit(regs.eax, 24); 1742 info.virt.kvm.hint_realtime = bit(regs.edx, 0); 1743 // break; 1744 // default: 1745 // } 1746 } 1747 1748 pragma(inline, false) 1749 private 1750 void ddcpuid_leaf4000_0002(ref CPUINFO info, ref REGISTERS regs) { 1751 // switch (info.virt.vendor.id) with (VirtVendor) { 1752 // case HyperV: 1753 info.virt.hv.guest_minor = cast(ubyte)(regs.eax >> 24); 1754 info.virt.hv.guest_service = cast(ubyte)(regs.eax >> 16); 1755 info.virt.hv.guest_build = regs.ax; 1756 info.virt.hv.guest_opensource = regs.edx >= BIT!(31); 1757 info.virt.hv.guest_vendor_id = (regs.edx >> 16) & 0xFFF; 1758 info.virt.hv.guest_os = regs.dh; 1759 info.virt.hv.guest_major = regs.dl; 1760 // break; 1761 // default: 1762 // } 1763 } 1764 1765 pragma(inline, false) 1766 private 1767 void ddcpuid_leaf4000_0003(ref CPUINFO info, ref REGISTERS regs) { 1768 // switch (info.virt.vendor.id) with (VirtVendor) { 1769 // case HyperV: 1770 info.virt.hv.base_feat_vp_runtime_msr = bit(regs.eax, 0); 1771 info.virt.hv.base_feat_part_time_ref_count_msr = bit(regs.eax, 1); 1772 info.virt.hv.base_feat_basic_synic_msrs = bit(regs.eax, 2); 1773 info.virt.hv.base_feat_stimer_msrs = bit(regs.eax, 3); 1774 info.virt.hv.base_feat_apic_access_msrs = bit(regs.eax, 4); 1775 info.virt.hv.base_feat_hypercall_msrs = bit(regs.eax, 5); 1776 info.virt.hv.base_feat_vp_id_msr = bit(regs.eax, 6); 1777 info.virt.hv.base_feat_virt_sys_reset_msr = bit(regs.eax, 7); 1778 info.virt.hv.base_feat_stat_pages_msr = bit(regs.eax, 8); 1779 info.virt.hv.base_feat_part_ref_tsc_msr = bit(regs.eax, 9); 1780 info.virt.hv.base_feat_guest_idle_state_msr = bit(regs.eax, 10); 1781 info.virt.hv.base_feat_timer_freq_msrs = bit(regs.eax, 11); 1782 info.virt.hv.base_feat_debug_msrs = bit(regs.eax, 12); 1783 info.virt.hv.part_flags_create_part = bit(regs.ebx, 0); 1784 info.virt.hv.part_flags_access_part_id = bit(regs.ebx, 1); 1785 info.virt.hv.part_flags_access_memory_pool = bit(regs.ebx, 2); 1786 info.virt.hv.part_flags_adjust_msg_buffers = bit(regs.ebx, 3); 1787 info.virt.hv.part_flags_post_msgs = bit(regs.ebx, 4); 1788 info.virt.hv.part_flags_signal_events = bit(regs.ebx, 5); 1789 info.virt.hv.part_flags_create_port = bit(regs.ebx, 6); 1790 info.virt.hv.part_flags_connect_port = bit(regs.ebx, 7); 1791 info.virt.hv.part_flags_access_stats = bit(regs.ebx, 8); 1792 info.virt.hv.part_flags_debugging = bit(regs.ebx, 11); 1793 info.virt.hv.part_flags_cpu_mgmt = bit(regs.ebx, 12); 1794 info.virt.hv.part_flags_cpu_profiler = bit(regs.ebx, 13); 1795 info.virt.hv.part_flags_expanded_stack_walk = bit(regs.ebx, 14); 1796 info.virt.hv.part_flags_access_vsm = bit(regs.ebx, 16); 1797 info.virt.hv.part_flags_access_vp_regs = bit(regs.ebx, 17); 1798 info.virt.hv.part_flags_extended_hypercalls = bit(regs.ebx, 20); 1799 info.virt.hv.part_flags_start_vp = bit(regs.ebx, 21); 1800 info.virt.hv.pm_max_cpu_power_state_c0 = bit(regs.ecx, 0); 1801 info.virt.hv.pm_max_cpu_power_state_c1 = bit(regs.ecx, 1); 1802 info.virt.hv.pm_max_cpu_power_state_c2 = bit(regs.ecx, 2); 1803 info.virt.hv.pm_max_cpu_power_state_c3 = bit(regs.ecx, 3); 1804 info.virt.hv.pm_hpet_reqd_for_c3 = bit(regs.ecx, 4); 1805 info.virt.hv.misc_feat_mwait = bit(regs.eax, 0); 1806 info.virt.hv.misc_feat_guest_debugging = bit(regs.eax, 1); 1807 info.virt.hv.misc_feat_perf_mon = bit(regs.eax, 2); 1808 info.virt.hv.misc_feat_pcpu_dyn_part_event = bit(regs.eax, 3); 1809 info.virt.hv.misc_feat_xmm_hypercall_input = bit(regs.eax, 4); 1810 info.virt.hv.misc_feat_guest_idle_state = bit(regs.eax, 5); 1811 info.virt.hv.misc_feat_hypervisor_sleep_state = bit(regs.eax, 6); 1812 info.virt.hv.misc_feat_query_numa_distance = bit(regs.eax, 7); 1813 info.virt.hv.misc_feat_timer_freq = bit(regs.eax, 8); 1814 info.virt.hv.misc_feat_inject_synmc_xcpt = bit(regs.eax, 9); 1815 info.virt.hv.misc_feat_guest_crash_msrs = bit(regs.eax, 10); 1816 info.virt.hv.misc_feat_debug_msrs = bit(regs.eax, 11); 1817 info.virt.hv.misc_feat_npiep1 = bit(regs.eax, 12); 1818 info.virt.hv.misc_feat_disable_hypervisor = bit(regs.eax, 13); 1819 info.virt.hv.misc_feat_ext_gva_range_for_flush_va_list = bit(regs.eax, 14); 1820 info.virt.hv.misc_feat_hypercall_output_xmm = bit(regs.eax, 15); 1821 info.virt.hv.misc_feat_sint_polling_mode = bit(regs.eax, 17); 1822 info.virt.hv.misc_feat_hypercall_msr_lock = bit(regs.eax, 18); 1823 info.virt.hv.misc_feat_use_direct_synth_msrs = bit(regs.eax, 19); 1824 // break; 1825 // default: 1826 // } 1827 } 1828 1829 pragma(inline, false) 1830 private 1831 void ddcpuid_leaf4000_0004(ref CPUINFO info, ref REGISTERS regs) { 1832 // switch (info.virt.vendor.id) with (VirtVendor) { 1833 // case HyperV: 1834 info.virt.hv.hint_hypercall_for_process_switch = bit(regs.eax, 0); 1835 info.virt.hv.hint_hypercall_for_tlb_flush = bit(regs.eax, 1); 1836 info.virt.hv.hint_hypercall_for_tlb_shootdown = bit(regs.eax, 2); 1837 info.virt.hv.hint_msr_for_apic_access = bit(regs.eax, 3); 1838 info.virt.hv.hint_msr_for_sys_reset = bit(regs.eax, 4); 1839 info.virt.hv.hint_relax_time_checks = bit(regs.eax, 5); 1840 info.virt.hv.hint_dma_remapping = bit(regs.eax, 6); 1841 info.virt.hv.hint_interrupt_remapping = bit(regs.eax, 7); 1842 info.virt.hv.hint_x2apic_msrs = bit(regs.eax, 8); 1843 info.virt.hv.hint_deprecate_auto_eoi = bit(regs.eax, 9); 1844 info.virt.hv.hint_synth_cluster_ipi_hypercall = bit(regs.eax, 10); 1845 info.virt.hv.hint_ex_proc_masks_interface = bit(regs.eax, 11); 1846 info.virt.hv.hint_nested_hyperv = bit(regs.eax, 12); 1847 info.virt.hv.hint_int_for_mbec_syscalls = bit(regs.eax, 13); 1848 info.virt.hv.hint_nested_enlightened_vmcs_interface = bit(regs.eax, 14); 1849 // break; 1850 // default: 1851 // } 1852 } 1853 1854 pragma(inline, false) 1855 private 1856 void ddcpuid_leaf4000_0006(ref CPUINFO info, ref REGISTERS regs) { 1857 // switch (info.virt.vendor.id) with (VirtVendor) { 1858 // case HyperV: 1859 info.virt.hv.host_feat_avic = bit(regs.eax, 0); 1860 info.virt.hv.host_feat_msr_bitmap = bit(regs.eax, 1); 1861 info.virt.hv.host_feat_perf_counter = bit(regs.eax, 2); 1862 info.virt.hv.host_feat_nested_paging = bit(regs.eax, 3); 1863 info.virt.hv.host_feat_dma_remapping = bit(regs.eax, 4); 1864 info.virt.hv.host_feat_interrupt_remapping = bit(regs.eax, 5); 1865 info.virt.hv.host_feat_mem_patrol_scrubber = bit(regs.eax, 6); 1866 info.virt.hv.host_feat_dma_prot_in_use = bit(regs.eax, 7); 1867 info.virt.hv.host_feat_hpet_requested = bit(regs.eax, 8); 1868 info.virt.hv.host_feat_stimer_volatile = bit(regs.eax, 9); 1869 // break; 1870 // default: 1871 // } 1872 } 1873 1874 pragma(inline, false) 1875 private 1876 void ddcpuid_leaf4000_0010(ref CPUINFO info, ref REGISTERS regs) { 1877 // switch (info.virt.vendor.id) with (VirtVendor) { 1878 // case VBoxMin: // VBox Minimal 1879 info.virt.vbox.tsc_freq_khz = regs.eax; 1880 info.virt.vbox.apic_freq_khz = regs.ebx; 1881 // break; 1882 // default: 1883 // } 1884 } 1885 1886 pragma(inline, false) 1887 private 1888 void ddcpuid_leaf8000_0001(ref CPUINFO info, ref REGISTERS regs) { 1889 switch (info.vendor.id) with (Vendor) { 1890 case AMD: 1891 // ecx 1892 info.virt.available = bit(regs.ecx, 2); 1893 info.sys.x2apic = bit(regs.ecx, 3); 1894 info.sse.sse4a = bit(regs.ecx, 6); 1895 info.extensions.xop = bit(regs.ecx, 11); 1896 info.extras.skinit = bit(regs.ecx, 12); 1897 info.extensions.fma4 = bit(regs.ecx, 16); 1898 info.extensions.tbm = bit(regs.ecx, 21); 1899 // edx 1900 info.extensions.mmxExtended = bit(regs.edx, 22); 1901 info.extensions._3DNowExtended = bit(regs.edx, 30); 1902 info.extensions._3DNow = regs.edx >= BIT!(31); 1903 break; 1904 default: 1905 } 1906 1907 // ecx 1908 info.extensions.lahf64 = bit(regs.ecx, 0); 1909 info.extras.lzcnt = bit(regs.ecx, 5); 1910 info.cache.prefetchw = bit(regs.ecx, 8); 1911 info.extras.monitorx = bit(regs.ecx, 29); 1912 // edx 1913 info.extras.syscall = bit(regs.edx, 11); 1914 info.memory.nx = bit(regs.edx, 20); 1915 info.memory.page1gb = bit(regs.edx, 26); 1916 info.extras.rdtscp = bit(regs.edx, 27); 1917 info.extensions.x86_64 = bit(regs.edx, 29); 1918 } 1919 1920 pragma(inline, false) 1921 private 1922 void ddcpuid_leaf8000_0007(ref CPUINFO info, ref REGISTERS regs) { 1923 switch (info.vendor.id) with (Vendor) { 1924 case Intel: 1925 info.extras.rdseed = bit(regs.ebx, 28); 1926 break; 1927 case AMD: 1928 info.sys.tm = bit(regs.edx, 4); 1929 info.tech.turboboost = bit(regs.edx, 9); 1930 break; 1931 default: 1932 } 1933 1934 info.extras.rdtscInvariant = bit(regs.edx, 8); 1935 } 1936 1937 pragma(inline, false) 1938 private 1939 void ddcpuid_leaf8000_0008(ref CPUINFO info, ref REGISTERS regs) { 1940 switch (info.vendor.id) with (Vendor) { 1941 case Intel: 1942 info.cache.wbnoinvd = bit(regs.ebx, 9); 1943 break; 1944 case AMD: 1945 info.security.ibpb = bit(regs.ebx, 12); 1946 info.security.ibrs = bit(regs.ebx, 14); 1947 info.security.stibp = bit(regs.ebx, 15); 1948 info.security.ibrsAlwaysOn = bit(regs.ebx, 16); 1949 info.security.stibpAlwaysOn = bit(regs.ebx, 17); 1950 info.security.ibrsPreferred = bit(regs.ebx, 18); 1951 info.security.ssbd = bit(regs.ebx, 24); 1952 break; 1953 default: 1954 } 1955 1956 info.memory.physBits = regs.al; 1957 info.memory.lineBits = regs.ah; 1958 } 1959 1960 pragma(inline, false) 1961 private 1962 void ddcpuid_leaf8000_000A(ref CPUINFO info, ref REGISTERS regs) { 1963 switch (info.vendor.id) { 1964 case Vendor.AMD: 1965 info.virt.version_ = regs.al; // EAX[7:0] 1966 info.virt.apicv = bit(regs.edx, 13); 1967 break; 1968 default: 1969 } 1970 } 1971 1972 pragma(inline, false) 1973 private 1974 void ddcpuid_topology(ref CPUINFO info) { 1975 ushort sc = void; /// raw cores shared across cache level 1976 ushort crshrd = void; /// actual count of shared cores 1977 ubyte type = void; /// cache type 1978 ubyte mids = void; /// maximum IDs to this cache 1979 REGISTERS regs = void; /// registers 1980 1981 info.cache.levels = 0; 1982 CACHEINFO *ca = cast(CACHEINFO*)info.cache.level; 1983 1984 //TODO: Make 1FH/BH/4H/etc. functions. 1985 switch (info.vendor.id) with (Vendor) { 1986 case Intel: 1987 if (info.maxLeaf >= 0x1f) goto L_CACHE_INTEL_1FH; 1988 if (info.maxLeaf >= 0xb) goto L_CACHE_INTEL_BH; 1989 if (info.maxLeaf >= 4) goto L_CACHE_INTEL_4H; 1990 // Celeron 0xf34 has maxLeaf=03h and ext=8000_0008h 1991 if (info.maxLeaf >= 2) goto L_CACHE_INTEL_2H; 1992 if (info.maxLeafExtended >= 0x8000_0005) goto L_CACHE_AMD_EXT_5H; 1993 break; 1994 1995 L_CACHE_INTEL_1FH: 1996 //TODO: Support levels 3,4,5 in CPUID.1FH 1997 // (Module, Tile, and Die) 1998 ddcpuid_id(regs, 0x1f, 1); // Cores (logical) 1999 info.cores.logical = regs.bx; 2000 2001 ddcpuid_id(regs, 0x1f, 0); // SMT (architectural states per core) 2002 info.cores.physical = cast(ushort)(info.cores.logical / regs.bx); 2003 2004 goto L_CACHE_INTEL_4H; 2005 2006 L_CACHE_INTEL_BH: 2007 ddcpuid_id(regs, 0xb, 1); // Cores (logical) 2008 info.cores.logical = regs.bx; 2009 2010 ddcpuid_id(regs, 0xb, 0); // SMT (architectural states per core) 2011 info.cores.physical = cast(ushort)(info.cores.logical / regs.bx); 2012 2013 L_CACHE_INTEL_4H: 2014 ddcpuid_id(regs, 4, info.cache.levels); 2015 2016 type = regs.eax & CACHE_MASK; // EAX[4:0] 2017 if (type == 0 || info.cache.levels >= CACHE_MAX_LEVEL) return; 2018 2019 ca.type = CACHE_TYPE[type]; 2020 ca.level = regs.al >> 5; 2021 ca.lineSize = (regs.bx & 0xfff) + 1; // bits 11-0 2022 ca.partitions = ((regs.ebx >> 12) & 0x3ff) + 1; // bits 21-12 2023 ca.ways = ((regs.ebx >> 22) + 1); // bits 31-22 2024 ca.sets = regs.ecx + 1; 2025 if (regs.eax & BIT!(8)) ca.features = 1; 2026 if (regs.eax & BIT!(9)) ca.features |= BIT!(1); 2027 if (regs.edx & BIT!(0)) ca.features |= BIT!(2); 2028 if (regs.edx & BIT!(1)) ca.features |= BIT!(3); 2029 if (regs.edx & BIT!(2)) ca.features |= BIT!(4); 2030 ca.size = (ca.sets * ca.lineSize * ca.partitions * ca.ways) >> 10; 2031 2032 mids = (regs.eax >> 26) + 1; // EAX[31:26] 2033 2034 if (info.cores.logical == 0) { // skip if already populated 2035 info.cores.logical = mids; 2036 info.cores.physical = info.tech.htt ? mids >> 1 : mids; 2037 } 2038 2039 crshrd = (((regs.eax >> 14) & 2047) + 1); // EAX[25:14] 2040 sc = cast(ushort)(info.cores.logical / crshrd); // cast for ldc 0.17.1 2041 ca.sharedCores = sc ? sc : 1; 2042 version (Trace) trace("intel.4h mids=%u shared=%u crshrd=%u sc=%u", 2043 mids, ca.sharedCores, crshrd, sc); 2044 2045 ++info.cache.levels; ++ca; 2046 goto L_CACHE_INTEL_4H; 2047 2048 L_CACHE_INTEL_2H: 2049 ddcpuid_id(regs, 2); 2050 ddcpuid_leaf2(info, regs); 2051 break; 2052 case AMD: 2053 if (info.maxLeafExtended >= 0x8000_001D) goto L_CACHE_AMD_EXT_1DH; 2054 if (info.maxLeafExtended >= 0x8000_0005) goto L_CACHE_AMD_EXT_5H; 2055 break; 2056 2057 /*if (info.maxLeafExtended < 0x8000_001e) goto L_AMD_TOPOLOGY_EXT_8H; 2058 2059 ddcpuid_id(regs, 0x8000_0001); 2060 2061 if (regs.ecx & BIT!(22)) { // Topology extensions support 2062 ddcpuid_id(regs, 0x8000_001e); 2063 2064 info.cores.logical = regs.ch + 1; 2065 info.cores.physical = regs.dh & 7; 2066 goto L_AMD_CACHE; 2067 }*/ 2068 2069 /*L_AMD_TOPOLOGY_EXT_8H: 2070 // See APM Volume 3 Appendix E.5 2071 // For some reason, CPUID Fn8000_001E_EBX is not mentioned there 2072 ddcpuid_id(regs, 0x8000_0008); 2073 2074 type = regs.cx >> 12; // ApicIdSize 2075 2076 if (type) { // Extended 2077 info.cores.physical = regs.cl + 1; 2078 info.cores.logical = cast(ushort)(1 << type); 2079 } else { // Legacy 2080 info.cores.logical = info.cores.physical = regs.cl + 1; 2081 }*/ 2082 2083 // 2084 // AMD newer cache method 2085 // 2086 2087 L_CACHE_AMD_EXT_1DH: // Almost the same as Intel's 2088 ddcpuid_id(regs, 0x8000_001d, info.cache.levels); 2089 2090 type = regs.eax & CACHE_MASK; // EAX[4:0] 2091 if (type == 0 || info.cache.levels >= CACHE_MAX_LEVEL) return; 2092 2093 ca.type = CACHE_TYPE[type]; 2094 ca.level = (regs.eax >> 5) & 7; 2095 ca.lineSize = (regs.ebx & 0xfff) + 1; 2096 ca.partitions = ((regs.ebx >> 12) & 0x3ff) + 1; 2097 ca.ways = (regs.ebx >> 22) + 1; 2098 ca.sets = regs.ecx + 1; 2099 if (regs.eax & BIT!(8)) ca.features = 1; 2100 if (regs.eax & BIT!(9)) ca.features |= BIT!(1); 2101 if (regs.edx & BIT!(0)) ca.features |= BIT!(2); 2102 if (regs.edx & BIT!(1)) ca.features |= BIT!(3); 2103 ca.size = (ca.sets * ca.lineSize * ca.partitions * ca.ways) >> 10; 2104 2105 crshrd = (((regs.eax >> 14) & 0xfff) + 1); // bits 25-14 2106 sc = cast(ushort)(info.sys.maxApicId / crshrd); // cast for ldc 0.17.1 2107 ca.sharedCores = sc ? sc : 1; 2108 2109 if (info.cores.logical == 0) with (info.cores) { // skip if already populated 2110 logical = info.sys.maxApicId; 2111 physical = info.tech.htt ? logical >> 1 : info.sys.maxApicId; 2112 } 2113 2114 version (Trace) trace("amd.8000_001Dh mids=%u shared=%u crshrd=%u sc=%u", 2115 mids, ca.sharedCores, crshrd, sc); 2116 2117 ++info.cache.levels; ++ca; 2118 goto L_CACHE_AMD_EXT_1DH; 2119 2120 // 2121 // AMD legacy cache 2122 // 2123 2124 L_CACHE_AMD_EXT_5H: 2125 ddcpuid_id(regs, 0x8000_0005); 2126 2127 info.cache.level[0].level = 1; // L1-D 2128 info.cache.level[0].type = 'D'; // data 2129 info.cache.level[0].size = regs.ecx >> 24; 2130 info.cache.level[0].ways = cast(ubyte)(regs.ecx >> 16); 2131 info.cache.level[0].lines = regs.ch; 2132 info.cache.level[0].lineSize = regs.cl; 2133 info.cache.level[0].sets = 1; 2134 2135 info.cache.level[1].level = 1; // L1-I 2136 info.cache.level[1].type = 'I'; // instructions 2137 info.cache.level[1].size = regs.edx >> 24; 2138 info.cache.level[1].ways = cast(ubyte)(regs.edx >> 16); 2139 info.cache.level[1].lines = regs.dh; 2140 info.cache.level[1].lineSize = regs.dl; 2141 info.cache.level[1].sets = 1; 2142 2143 info.cache.levels = 2; 2144 2145 if (info.maxLeafExtended < 0x8000_0006) 2146 return; // No L2/L3 2147 2148 // See Table E-4. L2/L3 Cache and TLB Associativity Field Encoding 2149 static immutable ubyte[16] _amd_cache_ways = [ 2150 // 7h is reserved 2151 // 9h mentions 8000_001D but that's already supported 2152 0, 1, 2, 3, 4, 6, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255 2153 ]; 2154 2155 ddcpuid_id(regs, 0x8000_0006); 2156 2157 type = regs.cx >> 12; // amd_ways_l2 2158 if (type) { 2159 info.cache.level[2].level = 2; // L2 2160 info.cache.level[2].type = 'U'; // unified 2161 info.cache.level[2].size = regs.ecx >> 16; 2162 info.cache.level[2].ways = _amd_cache_ways[type]; 2163 info.cache.level[2].lines = regs.ch & 0xf; 2164 info.cache.level[2].lineSize = regs.cl; 2165 info.cache.level[2].sets = 1; 2166 info.cache.levels = 3; 2167 2168 type = regs.dx >> 12; // amd_ways_l3 2169 if (type) { 2170 info.cache.level[3].level = 3; // L3 2171 info.cache.level[3].type = 'U'; // unified 2172 info.cache.level[3].size = ((regs.edx >> 18) + 1) << 9; 2173 info.cache.level[3].ways = _amd_cache_ways[type]; 2174 info.cache.level[3].lines = regs.dh & 0xf; 2175 info.cache.level[3].lineSize = regs.dl & 0x7F; 2176 info.cache.level[3].sets = 1; 2177 info.cache.levels = 4; 2178 } 2179 } 2180 return; 2181 default: 2182 } 2183 2184 with (info) cores.physical = cores.logical = 1; 2185 } 2186 2187 private struct LeafInfo { 2188 uint leaf; 2189 uint sub; 2190 void function(ref CPUINFO, ref REGISTERS) func; 2191 } 2192 private struct LeafExtInfo { 2193 uint leaf; 2194 void function(ref CPUINFO, ref REGISTERS) func; 2195 } 2196 2197 /// Fetch CPU information. 2198 /// Params: info = CPUINFO structure 2199 pragma(inline, false) 2200 void ddcpuid_cpuinfo(ref CPUINFO info) { 2201 static immutable LeafInfo[] regulars = [ 2202 { 0x1, 0, &ddcpuid_leaf1 }, // Sets brand index 2203 { 0x5, 0, &ddcpuid_leaf5 }, 2204 { 0x6, 0, &ddcpuid_leaf6 }, 2205 { 0x7, 0, &ddcpuid_leaf7 }, 2206 { 0x7, 1, &ddcpuid_leaf7sub1 }, 2207 { 0xd, 0, &ddcpuid_leafD }, 2208 { 0xd, 1, &ddcpuid_leafDsub1 }, 2209 { 0x12, 0, &ddcpuid_leaf12 }, 2210 ]; 2211 static immutable LeafExtInfo[] extended = [ 2212 { 0x8000_0001, &ddcpuid_leaf8000_0001 }, 2213 { 0x8000_0007, &ddcpuid_leaf8000_0007 }, 2214 { 0x8000_0008, &ddcpuid_leaf8000_0008 }, 2215 { 0x8000_000a, &ddcpuid_leaf8000_000A }, 2216 ]; 2217 REGISTERS regs = void; /// registers 2218 2219 ddcpuid_vendor(info.vendor.string_); 2220 info.vendor.id = ddcpuid_vendor_id(info.vendor); 2221 2222 foreach (ref immutable(LeafInfo) l; regulars) { 2223 if (l.leaf > info.maxLeaf) break; 2224 2225 ddcpuid_id(regs, l.leaf, l.sub); 2226 l.func(info, regs); 2227 } 2228 2229 // Paravirtualization leaves 2230 if (info.maxLeafVirt >= 0x4000_0000) { 2231 ddcpuid_virt_vendor(info.virt.vendor.string_); 2232 info.virt.vendor.id = ddcpuid_virt_vendor_id(info.virt.vendor); 2233 2234 switch (info.virt.vendor.id) with (VirtVendor) { 2235 case KVM: 2236 ddcpuid_id(regs, 0x4000_0001); 2237 ddcpuid_leaf4000_0001(info, regs); 2238 break; 2239 case HyperV: 2240 ddcpuid_id(regs, 0x4000_0002); 2241 ddcpuid_leaf4000_0002(info, regs); 2242 ddcpuid_id(regs, 0x4000_0003); 2243 ddcpuid_leaf4000_0003(info, regs); 2244 ddcpuid_id(regs, 0x4000_0004); 2245 ddcpuid_leaf4000_0004(info, regs); 2246 ddcpuid_id(regs, 0x4000_0006); 2247 ddcpuid_leaf4000_0006(info, regs); 2248 break; 2249 case VBoxMin: 2250 ddcpuid_id(regs, 0x4000_0010); 2251 ddcpuid_leaf4000_0010(info, regs); 2252 break; 2253 default: 2254 } 2255 } 2256 2257 // Extended leaves 2258 if (info.maxLeafExtended >= 0x8000_0000) { 2259 foreach (ref immutable(LeafExtInfo) l; extended) { 2260 if (l.leaf > info.maxLeafExtended) break; 2261 2262 ddcpuid_id(regs, l.leaf); 2263 l.func(info, regs); 2264 } 2265 } 2266 2267 ddcpuid_model_string(info); // Sets brand string 2268 ddcpuid_topology(info); // Sets core/thread/cache topology 2269 } 2270 2271 const(char) *ddcpuid_baseline(ref CPUINFO info) { 2272 if (info.extensions.x86_64 == false) { 2273 if (info.family >= 6) // Pentium Pro / II 2274 return "i686"; 2275 // NOTE: K7 is still family 5 and didn't have SSE2. 2276 return info.family == 5 ? "i586" : "i486"; // Pentium / MMX 2277 } 2278 2279 // v4 2280 if (info.avx.avx512f && info.avx.avx512bw && 2281 info.avx.avx512cd && info.avx.avx512dq && 2282 info.avx.avx512vl) { 2283 return "x86-64-v4"; 2284 } 2285 2286 // v3 2287 if (info.avx.avx2 && info.avx.avx && 2288 info.extensions.bmi2 && info.extensions.bmi1 && 2289 info.extensions.f16c && info.extensions.fma3 && 2290 info.extras.lzcnt && info.extras.movbe && 2291 info.extras.osxsave) { 2292 return "x86-64-v3"; 2293 } 2294 2295 // v2 2296 if (info.sse.sse42 && info.sse.sse41 && 2297 info.sse.ssse3 && info.sse.sse3 && 2298 info.extensions.lahf64 && info.extras.popcnt && 2299 info.extras.cmpxchg16b) { 2300 return "x86-64-v2"; 2301 } 2302 2303 // baseline (v1) 2304 /*if (info.sse.sse2 && info.sse.sse && 2305 info.extensions.mmx && info.extras.fxsr && 2306 info.extras.cmpxchg8b && info.extras.cmov && 2307 info.extensions.fpu && info.extras.syscall) { 2308 return "x86-64"; 2309 }*/ 2310 2311 return "x86-64"; // v1 anyway 2312 }