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