1 /** 2 * Program entry point. 3 * 4 * Authors: dd86k (dd@dax.moe) 5 * Copyright: © 2016-2022 dd86k 6 * License: MIT 7 */ 8 module main; 9 10 import core.stdc.stdio : printf; // sscanf 11 import core.stdc.string : strcmp, strtok, strncpy; 12 import ddcpuid; 13 14 // NOTE: printf is used for a few reasons: 15 // - fputs with stdout crashes on Windows due to improper externs. 16 // - line buffering is used by default, which can be an advantage. 17 //TODO: Consider using WriteFile+STD_OUTPUT_HANDLE and write(2)+STDOUT_FILENO? 18 // No real benefit than maybe save some instructions 19 20 private: 21 @system: 22 extern (C): 23 24 // because wrong extern 25 int putchar(int); 26 // because wrong extern 27 int puts(scope const char* s); 28 // because GDC's pragma(scanf) whinning about %i and int* 29 int sscanf(scope const char* s, scope const char* format, scope ...); 30 31 /// Compiler version template for betterC usage 32 template CVER(int v) { 33 enum CVER = 34 cast(char)((v / 1000) + '0') ~ 35 "." ~ 36 cast(char)(((v % 1000) / 100) + '0') ~ 37 cast(char)(((v % 100) / 10) + '0') ~ 38 cast(char)((v % 10) + '0'); 39 } 40 41 /// Make a bit mask of one bit at n position 42 template BIT(int n) if (n <= 31) { enum uint BIT = 1 << n; } 43 44 enum : uint { 45 MAX_LEAF = 0x40, /// Maximum leaf override 46 MAX_VLEAF = 0x4000_0000 + MAX_LEAF, /// Maximum virt leaf override 47 MAX_ELEAF = 0x8000_0000 + MAX_LEAF, /// Maximum extended leaf override 48 } 49 50 /// Command-line options 51 struct options_t { 52 int maxLevel; /// Maximum leaf for -r (-S) 53 int maxSubLevel; /// Maximum subleaf for -r (-s) 54 bool hasLevel; /// If -S has been used 55 bool override_; /// Override leaves (-o) 56 bool baseline; /// Get x86-64 optimization feature level or baseline for processor 57 bool platform; /// Get x86-64 optimization feature level or baseline for platform 58 bool list; /// Get processor details in a list 59 bool raw; /// Raw CPUID value table (-r/--raw) 60 bool rawInput; /// Raw values were supplied, avoid fetching 61 } 62 63 // One day I'll make this italics. 64 immutable const(char) *secret = r" 65 ############ 66 ###################### 67 ########################### 68 ################# 69 ############ ####### 70 ######### _ _ ### R ##### 71 ####### | | | | ########### 72 ####### __| | __| | ######## 73 ##### / _ | / _ | ###### 74 ##### | (_| || (_| | ##### 75 #### \____| \____| #### 76 ### _ ### 77 ### [_] [_] | | ## 78 ## _ _ __ ___ _ __| | ____ ### 79 ### | || '_ \/ __/| | / _ |/ __ \ ### 80 ### | || | | |\__ \| || (_| || __/ #### 81 ### |_||_| |_||___/|_| \____|\____| ##### 82 ##### ##### 83 ###### ###### 84 ####### ####### 85 ######### ########### 86 ############################### 87 ###################### 88 "; 89 90 /// print help page 91 void clih() { 92 puts( 93 "x86/AMD64 CPUID information tool\n"~ 94 "\n"~ 95 "USAGE\n"~ 96 " ddcpuid [OPTIONS...]\n"~ 97 "\n"~ 98 "OPTIONS\n"~ 99 " -b, --baseline Print the processor's feature level\n"~ 100 " -l, --list Show all processor information in a list\n"~ 101 " -o Override max leaves to 0x40 for each sections\n"~ 102 " -p, --platform Print the processor's feature level, context-aware\n"~ 103 " -r, --raw [leaf,[sub]] Display CPUID values\n"~ 104 "\n"~ 105 "PAGES\n"~ 106 " -h, --help Print this help screen and quit\n"~ 107 " --version Print version screen and quit\n"~ 108 " --ver Print only version string and quit\n" 109 ); 110 } 111 112 /// print version page 113 void cliv() { 114 puts( 115 "ddcpuid-"~DDCPUID_PLATFORM~" "~DDCPUID_VERSION~" (built: "~__TIMESTAMP__~")\n"~ 116 "Copyright (c) 2016-2022 dd86k <dd@dax.moe>\n"~ 117 "License: MIT License <http://opensource.org/licenses/MIT>\n"~ 118 "Homepage: <https://github.com/dd86k/ddcpuid>\n"~ 119 "Compiler: "~__VENDOR__~" "~CVER!(__VERSION__) 120 ); 121 } 122 123 void outcpuid(uint leaf, uint sub) { 124 REGISTERS regs = void; 125 ddcpuid_id(regs, leaf, sub); 126 printcpuid(regs, leaf, sub); 127 } 128 129 /// Print cpuid table entry into stdout. 130 /// Params: 131 /// leaf = EAX input 132 /// sub = ECX input 133 pragma(inline, false) // ldc optimization thing 134 void printcpuid(ref REGISTERS regs, uint leaf, uint sub) { 135 with (regs) 136 printf("| %8x | %8x | %8x | %8x | %8x | %8x |\n", 137 leaf, sub, eax, ebx, ecx, edx); 138 } 139 140 char adjust(ref float size) { 141 version (Trace) trace("size=%u", size); 142 if (size >= 1024.0) { 143 size /= 1024; 144 return 'M'; 145 } 146 return 'K'; 147 } 148 /// adjust 149 @system unittest { 150 uint size = 1; 151 assert(adjust(size) == 'K'); 152 assert(size == 1); 153 size = 1024; 154 assert(adjust(size) == 'M'); 155 assert(size == 1); 156 size = 4096; 157 assert(adjust(size) == 'M'); 158 assert(size == 4); 159 } 160 // Adjust binary size (IEC) 161 const(char)* adjustBits(ref uint size, int bitpos) { 162 version (Trace) trace("size=%u bit=%d", size, bitpos); 163 static immutable const(char)*[8] SIZES = [ 164 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB" 165 ]; 166 size_t s; 167 while (bitpos >= 10) { bitpos -= 10; ++s; } 168 size = 1 << bitpos; 169 return SIZES[s]; 170 } 171 //TODO: Make DUB to include this main, somehow 172 /// adjustBits 173 @system unittest { 174 float size; 175 assert(adjustBits(size, 0) == "B"); 176 assert(size == 1); 177 assert(adjustBits(size, 1) == "B"); 178 assert(size == 2); 179 assert(adjustBits(size, 10) == "KiB"); 180 assert(size == 1); 181 assert(adjustBits(size, 11) == "KiB"); 182 assert(size == 2); 183 assert(adjustBits(size, 20) == "MiB"); 184 assert(size == 1); 185 assert(adjustBits(size, 36) == "GiB"); 186 assert(size == 64); 187 assert(adjustBits(size, 48) == "TiB"); 188 assert(size == 256); 189 } 190 191 const(char)* platform(ref CPUINFO cpu) { 192 if (cpu.x86_64) return "x86-64"; 193 switch (cpu.family) { 194 case 3: return "i386"; // 80386 195 case 4: return "i486"; // 80486 196 case 5: return "i586"; // Pentium / MMX 197 default: return "i686"; // Pentium Pro / II 198 } 199 } 200 201 void printLegacy(ref CPUINFO cpu) { 202 if (cpu.fpu) { 203 printf(" x87/fpu"); 204 if (cpu.f16c) printf(" +f16c"); 205 } 206 if (cpu.mmx) { 207 printf(" mmx"); 208 if (cpu.mmxExtended) printf(" extmmx"); 209 } 210 if (cpu._3DNow) { 211 printf(" 3dnow!"); 212 if (cpu._3DNowExtended) printf(" ext3dnow!"); 213 } 214 } 215 void printFeatures(ref CPUINFO cpu) { 216 switch (cpu.vendor.id) with (Vendor) { 217 case Intel: 218 if (cpu.eist) printf(" eist"); 219 if (cpu.turboboost) { 220 printf(" turboboost"); 221 if (cpu.turboboost30) printf("-3.0"); 222 } 223 if (cpu.tsx) { 224 printf(" tsx"); 225 if (cpu.hle) 226 printf(" +hle"); 227 if (cpu.rtm) 228 printf(" +rtm"); 229 if (cpu.tsxldtrk) 230 printf(" +tsxldtrk"); 231 } 232 if (cpu.smx) printf(" intel-txt/smx"); 233 if (cpu.sgx) { 234 // NOTE: SGX system configuration 235 // "enabled" in BIOS: only CPUID.7h.EBX[2] 236 // "user controlled" in BIOS: SGX1/SGX2/size bits 237 if (cpu.sgx1 || cpu.sgx2) { 238 if (cpu.sgx1) printf(" sgx1"); 239 if (cpu.sgx2) printf(" sgx2"); 240 } else printf(" sgx"); // Fallback per-say 241 if (cpu.sgxMaxSize) { 242 uint s32 = void, s64 = void; 243 const(char) *m32 = adjustBits(s32, cpu.sgxMaxSize); 244 const(char) *m64 = adjustBits(s64, cpu.sgxMaxSize64); 245 printf(" +maxsize=%u%s +maxsize64=%u%s", s32, m32, s64, m64); 246 } 247 } 248 break; 249 case AMD: 250 if (cpu.turboboost) printf(" core-performance-boost"); 251 break; 252 default: 253 } 254 if (cpu.htt) printf(" htt"); 255 } 256 void printSSE(ref CPUINFO cpu) { 257 printf(" sse"); 258 if (cpu.sse2) printf(" sse2"); 259 if (cpu.sse3) printf(" sse3"); 260 if (cpu.ssse3) printf(" ssse3"); 261 if (cpu.sse41) printf(" sse4.1"); 262 if (cpu.sse42) printf(" sse4.2"); 263 if (cpu.sse4a) printf(" sse4a"); 264 } 265 void printAVX(ref CPUINFO cpu) { 266 printf(" avx"); 267 if (cpu.avx2) printf(" avx2"); 268 if (cpu.avx512f) { 269 printf(" avx512f"); 270 if (cpu.avx512er) printf(" +er"); 271 if (cpu.avx512pf) printf(" +pf"); 272 if (cpu.avx512cd) printf(" +cd"); 273 if (cpu.avx512dq) printf(" +dq"); 274 if (cpu.avx512bw) printf(" +bw"); 275 if (cpu.avx512vl) printf(" +vl"); 276 if (cpu.avx512_ifma) printf(" +ifma"); 277 if (cpu.avx512_vbmi) printf(" +vbmi"); 278 if (cpu.avx512_4vnniw) printf(" +4vnniw"); 279 if (cpu.avx512_4fmaps) printf(" +4fmaps"); 280 if (cpu.avx512_vbmi2) printf(" +vbmi2"); 281 if (cpu.avx512_gfni) printf(" +gfni"); 282 if (cpu.avx512_vaes) printf(" +vaes"); 283 if (cpu.avx512_vnni) printf(" +vnni"); 284 if (cpu.avx512_bitalg) printf(" +bitalg"); 285 if (cpu.avx512_bf16) printf(" +bf16"); 286 if (cpu.avx512_vp2intersect) printf(" +vp2intersect"); 287 } 288 if (cpu.xop) printf(" xop"); 289 } 290 void printFMA(ref CPUINFO cpu) { 291 if (cpu.fma) printf(" fma"); 292 if (cpu.fma4) printf(" fma4"); 293 } 294 void printAMX(ref CPUINFO cpu) { 295 printf(" amx"); 296 if (cpu.amx_bf16) printf(" +bf16"); 297 if (cpu.amx_int8) printf(" +int8"); 298 if (cpu.amx_xtilecfg) printf(" +xtilecfg"); 299 if (cpu.amx_xtiledata) printf(" +xtiledata"); 300 if (cpu.amx_xfd) printf(" +xfd"); 301 } 302 void printOthers(ref CPUINFO cpu) { 303 const(char) *tstr = void; 304 if (cpu.x86_64) { 305 switch (cpu.vendor.id) with (Vendor) { 306 case Intel: tstr = " intel64/x86-64"; break; 307 case AMD: tstr = " amd64/x86-64"; break; 308 default: tstr = " x86-64"; 309 } 310 printf(tstr); 311 if (cpu.lahf64) 312 printf(" +lahf64"); 313 } 314 if (cpu.virtualization) 315 switch (cpu.vendor.id) with (Vendor) { 316 case Intel: printf(" vt-x/vmx"); break; 317 case AMD: // SVM 318 printf(" amd-v/vmx"); 319 if (cpu.virtVersion) 320 printf(" +svm=v%u", cpu.virtVersion); 321 break; 322 case VIA: printf(" via-vt/vmx"); break; 323 default: printf(" vmx"); 324 } 325 if (cpu.aes_ni) printf(" aes-ni"); 326 if (cpu.adx) printf(" adx"); 327 if (cpu.sha) printf(" sha"); 328 if (cpu.tbm) printf(" tbm"); 329 if (cpu.bmi1) printf(" bmi1"); 330 if (cpu.bmi2) printf(" bmi2"); 331 if (cpu.waitpkg) printf(" waitpkg"); 332 } 333 void printSecurity(ref CPUINFO cpu) { 334 if (cpu.ibpb) printf(" ibpb"); 335 if (cpu.ibrs) printf(" ibrs"); 336 if (cpu.ibrsAlwaysOn) printf(" ibrs_on"); // AMD 337 if (cpu.ibrsPreferred) printf(" ibrs_pref"); // AMD 338 if (cpu.stibp) printf(" stibp"); 339 if (cpu.stibpAlwaysOn) printf(" stibp_on"); // AMD 340 if (cpu.ssbd) printf(" ssbd"); 341 if (cpu.l1dFlush) printf(" l1d_flush"); // Intel 342 if (cpu.md_clear) printf(" md_clear"); // Intel 343 if (cpu.cetIbt) printf(" cet_ibt"); // Intel 344 if (cpu.cetSs) printf(" cet_ss"); // Intel 345 } 346 void printCacheFeats(ushort feats) { 347 if (feats == 0) return; 348 putchar(','); 349 if (feats & BIT!(0)) printf(" si"); // Self Initiative 350 if (feats & BIT!(1)) printf(" fa"); // Fully Associative 351 if (feats & BIT!(2)) printf(" nwbv"); // No Write-Back Validation 352 if (feats & BIT!(3)) printf(" ci"); // Cache Inclusive 353 if (feats & BIT!(4)) printf(" cci"); // Complex Cache Indexing 354 } 355 356 int optionRaw(ref options_t options, const(char) *arg) { 357 enum MAX = 16; 358 char[MAX] buf = void; 359 360 version (Trace) trace("arg=%s", arg); 361 362 options.raw = true; 363 if (arg == null) return 0; 364 365 options.rawInput = true; 366 strncpy(buf.ptr, arg, MAX); 367 arg = strtok(buf.ptr, ","); 368 version (Trace) trace("token=%s", arg); 369 if (arg == null) { 370 puts("Empty value for leaf"); 371 return 1; 372 } 373 sscanf(arg, "%i", &options.maxLevel); 374 arg = strtok(null, ","); 375 version (Trace) trace("token=%s", arg); 376 if (arg) 377 sscanf(arg, "%i", &options.maxSubLevel); 378 return 0; 379 } 380 381 version (unittest) {} else 382 int main(int argc, const(char) **argv) { 383 options_t options; /// Command-line options 384 int error = void; 385 386 const(char) *arg = void; /// Temp argument holder 387 const(char) *val = void; /// Temp value holder 388 for (int argi = 1; argi < argc; ++argi) { 389 if (argv[argi][1] == '-') { // Long arguments 390 arg = argv[argi] + 2; 391 if (strcmp(arg, "raw") == 0) { 392 val = argi + 1 >= argc ? null : argv[argi + 1]; 393 if (val && val[0] == '-') val = null; 394 error = optionRaw(options, val); 395 if (error) return error; 396 continue; 397 } 398 if (strcmp(arg, "platform") == 0) { 399 options.platform = true; 400 continue; 401 } 402 if (strcmp(arg, "baseline") == 0) { 403 options.baseline = true; 404 continue; 405 } 406 if (strcmp(arg, "list") == 0) { 407 options.list = true; 408 continue; 409 } 410 if (strcmp(arg, "version") == 0) { 411 cliv; 412 return 0; 413 } 414 if (strcmp(arg, "ver") == 0) { 415 puts(DDCPUID_VERSION); 416 return 0; 417 } 418 if (strcmp(arg, "help") == 0) { 419 clih; 420 return 0; 421 } 422 if (strcmp(arg, "inside") == 0) { 423 puts(secret); 424 return 0; 425 } 426 printf("Unknown parameter: '%s'\n", arg); 427 return 1; 428 } else if (argv[argi][0] == '-') { // Short arguments 429 arg = argv[argi] + 1; 430 char o = void; 431 while ((o = *arg) != 0) { 432 ++arg; 433 switch (o) { 434 case 'l': options.list = true; continue; 435 case 'p': options.platform = true; continue; 436 case 'b': options.baseline = true; continue; 437 case 'o': options.override_ = true; continue; 438 case 'r': 439 val = argi + 1 >= argc ? null : argv[argi + 1]; 440 if (val && val[0] == '-') val = null; 441 error = optionRaw(options, val); 442 if (error) return error; 443 continue; 444 case 'h': clih; return 0; 445 case 'V': cliv; return 0; 446 default: 447 printf("Unknown parameter: '-%c'\n", o); 448 return 1; 449 } 450 } // while 451 } // else if 452 } // for 453 454 if (options.raw) { 455 uint l = void, s = void; 456 457 puts( 458 "| Leaf | Sub-leaf | EAX | EBX | ECX | EDX |\n"~ 459 "|----------|----------|----------|----------|----------|----------|" 460 ); 461 462 if (options.rawInput) { 463 outcpuid(options.maxLevel, options.maxSubLevel); 464 return 0; 465 } 466 467 for (uint leaf; leaf != 0xf000_0000; leaf += 0x1000_0000) { 468 REGISTERS regs = void; 469 ddcpuid_id(regs, leaf, 0); 470 471 if (regs.eax < leaf) continue; 472 473 const uint maxleaf = options.override_ ? leaf + MAX_LEAF : regs.eax; 474 475 for (l = leaf; l <= maxleaf; ++l) 476 for (s = 0; s <= options.maxSubLevel; ++s) 477 outcpuid(l, s); 478 } 479 480 return 0; 481 } 482 483 CPUINFO cpu; 484 485 if (options.override_) { 486 cpu.maxLeaf = MAX_LEAF; 487 cpu.maxLeafVirt = MAX_VLEAF; 488 cpu.maxLeafExtended = MAX_ELEAF; 489 } else { 490 ddcpuid_leaves(cpu); 491 } 492 493 ddcpuid_cpuinfo(cpu); 494 495 if (options.baseline) { 496 puts(ddcpuid_baseline(cpu)); 497 return 0; 498 } 499 if (options.platform) { 500 puts(platform(cpu)); 501 return 0; 502 } 503 504 // NOTE: .ptr crash with GDC -O3 505 // glibc!__strlen_sse2 (in printf) 506 version (GNU) { 507 char *vendorstr = cast(char*)cpu.vendor.string_; 508 char *brandstr = cast(char*)cpu.brandString; 509 } else { 510 char *vendorstr = cpu.vendor.string_.ptr; 511 char *brandstr = cpu.brandString.ptr; 512 } 513 514 // Brand string left space trimming 515 // While very common in Intel, let's also do it for others (in case of) 516 while (*brandstr == ' ') ++brandstr; 517 518 CACHEINFO *cache = void; /// Current cache level 519 520 // 521 // ANCHOR Summary 522 // 523 524 if (options.list == false) { 525 const(char) *s_cores = cpu.physicalCores == 1 ? "core" : "cores"; 526 const(char) *s_threads = cpu.logicalCores == 1 ? "thread" : "threads"; 527 with (cpu) printf( 528 "Name: %.12s %.48s\n"~ 529 "Identifier: Family 0x%x Model 0x%x Stepping 0x%x\n"~ 530 "Cores: %u %s, %u %s\n", 531 vendorstr, brandstr, 532 family, model, stepping, 533 physicalCores, s_cores, logicalCores, s_threads 534 ); 535 536 if (cpu.physicalBits || cpu.linearBits) { 537 uint maxPhys = void, maxLine = void; 538 const(char) *cphys = adjustBits(maxPhys, cpu.physicalBits); 539 const(char) *cline = adjustBits(maxLine, cpu.linearBits); 540 with (cpu) printf( 541 "Max. Memory: %u %s physical, %u %s virtual\n", 542 maxPhys, cphys, maxLine, cline, 543 ); 544 } 545 546 with (cpu) printf( 547 "Platform: %s\n"~ 548 "Baseline: %s\n"~ 549 "Features: ", 550 platform(cpu), 551 ddcpuid_baseline(cpu) 552 ); 553 554 printFeatures(cpu); 555 556 printf("\nExtensions: "); 557 printLegacy(cpu); 558 printOthers(cpu); 559 560 printf("\nSSE: "); 561 if (cpu.sse) 562 printSSE(cpu); 563 printFMA(cpu); 564 putchar('\n'); 565 566 printf("AVX: "); 567 if (cpu.avx) 568 printAVX(cpu); 569 putchar('\n'); 570 571 printf("AMX: "); 572 if (cpu.amx) 573 printAMX(cpu); 574 putchar('\n'); 575 576 printf("Mitigations:"); 577 printSecurity(cpu); 578 putchar('\n'); 579 580 if (cpu.maxLeafVirt >= 0x4000_0000) { 581 const(char) *vv = void; 582 switch (cpu.virtVendor.id) with (VirtVendor) { 583 case KVM: vv = "KVM"; break; 584 case HyperV: vv = "Hyper-V"; break; 585 case VBoxHyperV: vv = "VirtualBox Hyper-V"; break; 586 case VBoxMin: vv = "VirtualBox Minimal"; break; 587 default: vv = "Unknown"; 588 } 589 printf("ParaVirt.: %s\n", vv); 590 } 591 592 for (size_t i; i < cpu.cacheLevels; ++i) { 593 cache = &cpu.cache[i]; 594 float csize = cache.size; 595 float tsize = csize * cache.sharedCores; 596 char cc = adjust(csize); 597 char ct = adjust(tsize); 598 with (cache) 599 printf("Cache L%u-%c: %3ux %4g %ciB, %4g %ciB total", 600 level, type, sharedCores, csize, cc, tsize, ct); 601 printCacheFeats(cache.features); 602 putchar('\n'); 603 } 604 605 return 0; 606 } 607 608 // 609 // ANCHOR Detailed view 610 // 611 612 with (cpu) printf( 613 "Vendor : %.12s\n"~ 614 "Brand : %.48s\n"~ 615 "Identifier : 0x%x\n"~ 616 "Family : 0x%x\n"~ 617 "BaseFamily : 0x%x\n"~ 618 "ExtFamily : 0x%x\n"~ 619 "Model : 0x%x\n"~ 620 "BaseModel : 0x%x\n"~ 621 "ExtModel : 0x%x\n"~ 622 "Stepping : 0x%x\n"~ 623 "Cores : %u\n"~ 624 "Threads : %u\n"~ 625 "Extensions :", 626 vendorstr, brandstr, 627 identifier, 628 family, familyBase, familyExtended, 629 model, modelBase, modelExtended, 630 stepping, 631 physicalCores, logicalCores 632 ); 633 634 // Extensions 635 636 const(char) *tstr = void; 637 printLegacy(cpu); 638 if (cpu.sse) printSSE(cpu); 639 if (cpu.avx) printAVX(cpu); 640 printFMA(cpu); 641 printOthers(cpu); 642 if (cpu.amx) printAMX(cpu); 643 644 // 645 // ANCHOR Extra/lone instructions 646 // 647 648 printf("\nExtra :"); 649 if (cpu.monitor) { 650 printf(" monitor+mwait"); 651 if (cpu.mwaitMin) 652 printf(" +min=%u +max=%u", 653 cpu.mwaitMin, cpu.mwaitMax); 654 if (cpu.monitorx) printf(" monitorx+mwaitx"); 655 } 656 if (cpu.pclmulqdq) printf(" pclmulqdq"); 657 if (cpu.cmpxchg8b) printf(" cmpxchg8b"); 658 if (cpu.cmpxchg16b) printf(" cmpxchg16b"); 659 if (cpu.movbe) printf(" movbe"); 660 if (cpu.rdrand) printf(" rdrand"); 661 if (cpu.rdseed) printf(" rdseed"); 662 if (cpu.rdmsr) printf(" rdmsr+wrmsr"); 663 if (cpu.sysenter) printf(" sysenter+sysexit"); 664 if (cpu.syscall) printf(" syscall+sysret"); 665 if (cpu.rdtsc) { 666 printf(" rdtsc"); 667 if (cpu.rdtscDeadline) 668 printf(" +tsc-deadline"); 669 if (cpu.rdtscInvariant) 670 printf(" +tsc-invariant"); 671 } 672 if (cpu.rdtscp) printf(" rdtscp"); 673 if (cpu.rdpid) printf(" rdpid"); 674 if (cpu.cmov) { 675 printf(" cmov"); 676 if (cpu.fpu) printf(" fcomi+fcmov"); 677 } 678 if (cpu.lzcnt) printf(" lzcnt"); 679 if (cpu.popcnt) printf(" popcnt"); 680 if (cpu.xsave) printf(" xsave+xrstor"); 681 if (cpu.osxsave) printf(" xsetbv+xgetbv"); 682 if (cpu.fxsr) printf(" fxsave+fxrstor"); 683 if (cpu.pconfig) printf(" pconfig"); 684 if (cpu.cldemote) printf(" cldemote"); 685 if (cpu.movdiri) printf(" movdiri"); 686 if (cpu.movdir64b) printf(" movdir64b"); 687 if (cpu.enqcmd) printf(" enqcmd"); 688 if (cpu.skinit) printf(" skinit+stgi"); 689 if (cpu.serialize) printf(" serialize"); 690 691 // 692 // ANCHOR Vendor specific technologies 693 // 694 695 printf("\nFeatures :"); 696 printFeatures(cpu); 697 698 // 699 // ANCHOR Cache information 700 // 701 702 printf("\nCache :"); 703 if (cpu.clflush) 704 printf(" clflush=%uB", cpu.clflushLinesize << 3); 705 if (cpu.clflushopt) printf(" clflushopt"); 706 if (cpu.cnxtId) printf(" cnxt-id"); 707 if (cpu.ss) printf(" ss"); 708 if (cpu.prefetchw) printf(" prefetchw"); 709 if (cpu.invpcid) printf(" invpcid"); 710 if (cpu.wbnoinvd) printf(" wbnoinvd"); 711 712 for (uint i; i < cpu.cacheLevels; ++i) { 713 cache = &cpu.cache[i]; 714 printf("\nLevel %u-%c : %2ux %6u KiB, %u ways, %u parts, %u B, %u sets", 715 cache.level, cache.type, cache.sharedCores, cache.size, 716 cache.ways, cache.partitions, cache.lineSize, cache.sets 717 ); 718 printCacheFeats(cache.features); 719 } 720 721 printf("\nSystem :"); 722 if (cpu.apci) printf(" acpi"); 723 if (cpu.apic) printf(" apic"); 724 if (cpu.x2apic) printf(" x2apic"); 725 if (cpu.arat) printf(" arat"); 726 if (cpu.tm) printf(" tm"); 727 if (cpu.tm2) printf(" tm2"); 728 printf(" apic-id=%u", cpu.apicId); 729 if (cpu.apicMaxId) printf(" max-id=%u", cpu.apicMaxId); 730 731 printf("\nVirtual :"); 732 if (cpu.vme) printf(" vme"); 733 if (cpu.apicv) printf(" apicv"); 734 735 // Paravirtualization 736 if (cpu.maxLeafVirt >= 0x4000_0000) { 737 if (cpu.virtVendor.id) { 738 // See vendor string case 739 printf(" host=%.12s", cast(char*)cpu.virtVendor.string_); 740 } else { 741 printf(" host=(null)"); 742 } 743 switch (cpu.virtVendor.id) with (VirtVendor) { 744 case VBoxMin: 745 if (cpu.vbox.tsc_freq_khz) 746 printf(" tsc_freq_khz=%u", cpu.vbox.tsc_freq_khz); 747 if (cpu.vbox.apic_freq_khz) 748 printf(" apic_freq_khz=%u", cpu.vbox.apic_freq_khz); 749 break; 750 case HyperV: 751 printf(" opensource=%d vendor_id=%d os=%d major=%d minor=%d service=%d build=%d", 752 cpu.hv.guest_opensource, 753 cpu.hv.guest_vendor_id, 754 cpu.hv.guest_os, 755 cpu.hv.guest_major, 756 cpu.hv.guest_minor, 757 cpu.hv.guest_service, 758 cpu.hv.guest_build); 759 if (cpu.hv.base_feat_vp_runtime_msr) printf(" hv_base_feat_vp_runtime_msr"); 760 if (cpu.hv.base_feat_part_time_ref_count_msr) printf(" hv_base_feat_part_time_ref_count_msr"); 761 if (cpu.hv.base_feat_basic_synic_msrs) printf(" hv_base_feat_basic_synic_msrs"); 762 if (cpu.hv.base_feat_stimer_msrs) printf(" hv_base_feat_stimer_msrs"); 763 if (cpu.hv.base_feat_apic_access_msrs) printf(" hv_base_feat_apic_access_msrs"); 764 if (cpu.hv.base_feat_hypercall_msrs) printf(" hv_base_feat_hypercall_msrs"); 765 if (cpu.hv.base_feat_vp_id_msr) printf(" hv_base_feat_vp_id_msr"); 766 if (cpu.hv.base_feat_virt_sys_reset_msr) printf(" hv_base_feat_virt_sys_reset_msr"); 767 if (cpu.hv.base_feat_stat_pages_msr) printf(" hv_base_feat_stat_pages_msr"); 768 if (cpu.hv.base_feat_part_ref_tsc_msr) printf(" hv_base_feat_part_ref_tsc_msr"); 769 if (cpu.hv.base_feat_guest_idle_state_msr) printf(" hv_base_feat_guest_idle_state_msr"); 770 if (cpu.hv.base_feat_timer_freq_msrs) printf(" hv_base_feat_timer_freq_msrs"); 771 if (cpu.hv.base_feat_debug_msrs) printf(" hv_base_feat_debug_msrs"); 772 if (cpu.hv.part_flags_create_part) printf(" hv_part_flags_create_part"); 773 if (cpu.hv.part_flags_access_part_id) printf(" hv_part_flags_access_part_id"); 774 if (cpu.hv.part_flags_access_memory_pool) printf(" hv_part_flags_access_memory_pool"); 775 if (cpu.hv.part_flags_adjust_msg_buffers) printf(" hv_part_flags_adjust_msg_buffers"); 776 if (cpu.hv.part_flags_post_msgs) printf(" hv_part_flags_post_msgs"); 777 if (cpu.hv.part_flags_signal_events) printf(" hv_part_flags_signal_events"); 778 if (cpu.hv.part_flags_create_port) printf(" hv_part_flags_create_port"); 779 if (cpu.hv.part_flags_connect_port) printf(" hv_part_flags_connect_port"); 780 if (cpu.hv.part_flags_access_stats) printf(" hv_part_flags_access_stats"); 781 if (cpu.hv.part_flags_debugging) printf(" hv_part_flags_debugging"); 782 if (cpu.hv.part_flags_cpu_mgmt) printf(" hv_part_flags_cpu_mgmt"); 783 if (cpu.hv.part_flags_cpu_profiler) printf(" hv_part_flags_cpu_profiler"); 784 if (cpu.hv.part_flags_expanded_stack_walk) printf(" hv_part_flags_expanded_stack_walk"); 785 if (cpu.hv.part_flags_access_vsm) printf(" hv_part_flags_access_vsm"); 786 if (cpu.hv.part_flags_access_vp_regs) printf(" hv_part_flags_access_vp_regs"); 787 if (cpu.hv.part_flags_extended_hypercalls) printf(" hv_part_flags_extended_hypercalls"); 788 if (cpu.hv.part_flags_start_vp) printf(" hv_part_flags_start_vp"); 789 if (cpu.hv.pm_max_cpu_power_state_c0) printf(" hv_pm_max_cpu_power_state_c0"); 790 if (cpu.hv.pm_max_cpu_power_state_c1) printf(" hv_pm_max_cpu_power_state_c1"); 791 if (cpu.hv.pm_max_cpu_power_state_c2) printf(" hv_pm_max_cpu_power_state_c2"); 792 if (cpu.hv.pm_max_cpu_power_state_c3) printf(" hv_pm_max_cpu_power_state_c3"); 793 if (cpu.hv.pm_hpet_reqd_for_c3) printf(" hv_pm_hpet_reqd_for_c3"); 794 if (cpu.hv.misc_feat_mwait) printf(" hv_misc_feat_mwait"); 795 if (cpu.hv.misc_feat_guest_debugging) printf(" hv_misc_feat_guest_debugging"); 796 if (cpu.hv.misc_feat_perf_mon) printf(" hv_misc_feat_perf_mon"); 797 if (cpu.hv.misc_feat_pcpu_dyn_part_event) printf(" hv_misc_feat_pcpu_dyn_part_event"); 798 if (cpu.hv.misc_feat_xmm_hypercall_input) printf(" hv_misc_feat_xmm_hypercall_input"); 799 if (cpu.hv.misc_feat_guest_idle_state) printf(" hv_misc_feat_guest_idle_state"); 800 if (cpu.hv.misc_feat_hypervisor_sleep_state) printf(" hv_misc_feat_hypervisor_sleep_state"); 801 if (cpu.hv.misc_feat_query_numa_distance) printf(" hv_misc_feat_query_numa_distance"); 802 if (cpu.hv.misc_feat_timer_freq) printf(" hv_misc_feat_timer_freq"); 803 if (cpu.hv.misc_feat_inject_synmc_xcpt) printf(" hv_misc_feat_inject_synmc_xcpt"); 804 if (cpu.hv.misc_feat_guest_crash_msrs) printf(" hv_misc_feat_guest_crash_msrs"); 805 if (cpu.hv.misc_feat_debug_msrs) printf(" hv_misc_feat_debug_msrs"); 806 if (cpu.hv.misc_feat_npiep1) printf(" hv_misc_feat_npiep1"); 807 if (cpu.hv.misc_feat_disable_hypervisor) printf(" hv_misc_feat_disable_hypervisor"); 808 if (cpu.hv.misc_feat_ext_gva_range_for_flush_va_list) printf(" hv_misc_feat_ext_gva_range_for_flush_va_list"); 809 if (cpu.hv.misc_feat_hypercall_output_xmm) printf(" hv_misc_feat_hypercall_output_xmm"); 810 if (cpu.hv.misc_feat_sint_polling_mode) printf(" hv_misc_feat_sint_polling_mode"); 811 if (cpu.hv.misc_feat_hypercall_msr_lock) printf(" hv_misc_feat_hypercall_msr_lock"); 812 if (cpu.hv.misc_feat_use_direct_synth_msrs) printf(" hv_misc_feat_use_direct_synth_msrs"); 813 if (cpu.hv.hint_hypercall_for_process_switch) printf(" hv_hint_hypercall_for_process_switch"); 814 if (cpu.hv.hint_hypercall_for_tlb_flush) printf(" hv_hint_hypercall_for_tlb_flush"); 815 if (cpu.hv.hint_hypercall_for_tlb_shootdown) printf(" hv_hint_hypercall_for_tlb_shootdown"); 816 if (cpu.hv.hint_msr_for_apic_access) printf(" hv_hint_msr_for_apic_access"); 817 if (cpu.hv.hint_msr_for_sys_reset) printf(" hv_hint_msr_for_sys_reset"); 818 if (cpu.hv.hint_relax_time_checks) printf(" hv_hint_relax_time_checks"); 819 if (cpu.hv.hint_dma_remapping) printf(" hv_hint_dma_remapping"); 820 if (cpu.hv.hint_interrupt_remapping) printf(" hv_hint_interrupt_remapping"); 821 if (cpu.hv.hint_x2apic_msrs) printf(" hv_hint_x2apic_msrs"); 822 if (cpu.hv.hint_deprecate_auto_eoi) printf(" hv_hint_deprecate_auto_eoi"); 823 if (cpu.hv.hint_synth_cluster_ipi_hypercall) printf(" hv_hint_synth_cluster_ipi_hypercall"); 824 if (cpu.hv.hint_ex_proc_masks_interface) printf(" hv_hint_ex_proc_masks_interface"); 825 if (cpu.hv.hint_nested_hyperv) printf(" hv_hint_nested_hyperv"); 826 if (cpu.hv.hint_int_for_mbec_syscalls) printf(" hv_hint_int_for_mbec_syscalls"); 827 if (cpu.hv.hint_nested_enlightened_vmcs_interface) printf(" hv_hint_nested_enlightened_vmcs_interface"); 828 if (cpu.hv.host_feat_avic) printf(" hv_host_feat_avic"); 829 if (cpu.hv.host_feat_msr_bitmap) printf(" hv_host_feat_msr_bitmap"); 830 if (cpu.hv.host_feat_perf_counter) printf(" hv_host_feat_perf_counter"); 831 if (cpu.hv.host_feat_nested_paging) printf(" hv_host_feat_nested_paging"); 832 if (cpu.hv.host_feat_dma_remapping) printf(" hv_host_feat_dma_remapping"); 833 if (cpu.hv.host_feat_interrupt_remapping) printf(" hv_host_feat_interrupt_remapping"); 834 if (cpu.hv.host_feat_mem_patrol_scrubber) printf(" hv_host_feat_mem_patrol_scrubber"); 835 if (cpu.hv.host_feat_dma_prot_in_use) printf(" hv_host_feat_dma_prot_in_use"); 836 if (cpu.hv.host_feat_hpet_requested) printf(" hv_host_feat_hpet_requested"); 837 if (cpu.hv.host_feat_stimer_volatile) printf(" hv_host_feat_stimer_volatile"); 838 break; 839 case VirtVendor.KVM: 840 if (cpu.kvm.feature_clocksource) printf(" kvm_feature_clocksource"); 841 if (cpu.kvm.feature_nop_io_delay) printf(" kvm_feature_nop_io_delay"); 842 if (cpu.kvm.feature_mmu_op) printf(" kvm_feature_mmu_op"); 843 if (cpu.kvm.feature_clocksource2) printf(" kvm_feature_clocksource2"); 844 if (cpu.kvm.feature_async_pf) printf(" kvm_feature_async_pf"); 845 if (cpu.kvm.feature_steal_time) printf(" kvm_feature_steal_time"); 846 if (cpu.kvm.feature_pv_eoi) printf(" kvm_feature_pv_eoi"); 847 if (cpu.kvm.feature_pv_unhault) printf(" kvm_feature_pv_unhault"); 848 if (cpu.kvm.feature_pv_tlb_flush) printf(" kvm_feature_pv_tlb_flush"); 849 if (cpu.kvm.feature_async_pf_vmexit) printf(" kvm_feature_async_pf_vmexit"); 850 if (cpu.kvm.feature_pv_send_ipi) printf(" kvm_feature_pv_send_ipi"); 851 if (cpu.kvm.feature_pv_poll_control) printf(" kvm_feature_pv_poll_control"); 852 if (cpu.kvm.feature_pv_sched_yield) printf(" kvm_feature_pv_sched_yield"); 853 if (cpu.kvm.feature_clocsource_stable_bit) printf(" kvm_feature_clocsource_stable_bit"); 854 if (cpu.kvm.hint_realtime) printf(" kvm_hints_realtime"); 855 break; 856 default: 857 } 858 } 859 860 printf("\nMemory :"); 861 862 if (cpu.pae) printf(" pae"); 863 if (cpu.pse) printf(" pse"); 864 if (cpu.pse36) printf(" pse-36"); 865 if (cpu.page1gb) printf(" page1gb"); 866 if (cpu.nx) { 867 switch (cpu.vendor.id) with (Vendor) { 868 case Intel: tstr = " intel-xd/nx"; break; 869 case AMD: tstr = " amd-evp/nx"; break; 870 default: tstr = " nx"; 871 } 872 printf(tstr); 873 } 874 if (cpu.dca) printf(" dca"); 875 if (cpu.pat) printf(" pat"); 876 if (cpu.mtrr) printf(" mtrr"); 877 if (cpu.pge) printf(" pge"); 878 if (cpu.smep) printf(" smep"); 879 if (cpu.smap) printf(" smap"); 880 if (cpu.pku) printf(" pku"); 881 if (cpu._5pl) printf(" 5pl"); 882 if (cpu.fsrepmov) printf(" fsrm"); 883 if (cpu.lam) printf(" lam"); 884 885 printf("\nPhysicalBits: %u\nLinearBits : %u\nDebugging :", 886 cpu.physicalBits, cpu.linearBits); 887 888 if (cpu.mca) printf(" mca"); 889 if (cpu.mce) printf(" mce"); 890 if (cpu.de) printf(" de"); 891 if (cpu.ds) printf(" ds"); 892 if (cpu.ds_cpl) printf(" ds-cpl"); 893 if (cpu.dtes64) printf(" dtes64"); 894 if (cpu.pdcm) printf(" pdcm"); 895 if (cpu.sdbg) printf(" sdbg"); 896 if (cpu.pbe) printf(" pbe"); 897 898 printf("\nSecurity :"); 899 if (cpu.ia32_arch_capabilities) printf(" ia32_arch_capabilities"); 900 printSecurity(cpu); 901 902 with (cpu) printf( 903 "\n"~ 904 "Max. Leaf : 0x%x\n"~ 905 "Max. V-Leaf : 0x%x\n"~ 906 "Max. E-Leaf : 0x%x\n"~ 907 "Type : %s\n"~ 908 "Brand Index : %u\n"~ 909 "Misc. :", 910 maxLeaf, maxLeafVirt, maxLeafExtended, typeString, brandIndex); 911 912 if (cpu.xtpr) printf(" xtpr"); 913 if (cpu.psn) printf(" psn"); 914 if (cpu.pcid) printf(" pcid"); 915 if (cpu.fsgsbase) printf(" fsgsbase"); 916 if (cpu.uintr) printf(" uintr"); 917 918 putchar('\n'); 919 920 return 0; 921 }