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