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