1 /** 2 * Program entry point. 3 * 4 * NOTE: printf is mainly used for two reasons. First, fputs with stdout 5 * crashes on Windows. Secondly, line buffering is used by default. 6 * 7 * Authors: dd86k (dd@dax.moe) 8 * Copyright: © 2016-2021 dd86k 9 * License: MIT 10 */ 11 module main; 12 13 import core.stdc.errno : errno; 14 import core.stdc.stdio : printf, puts, sscanf, FILE, fopen, fread, fwrite; 15 import core.stdc.string : strcmp, strerror; 16 import ddcpuid; 17 18 private: 19 @system: 20 extern (C): 21 22 int putchar(int); 23 24 /// Compiler version template for betterC usage 25 template CVER(int v) { 26 enum CVER = 27 cast(char)((v / 1000) + '0') ~ 28 "." ~ 29 cast(char)(((v % 1000) / 100) + '0') ~ 30 cast(char)(((v % 100) / 10) + '0') ~ 31 cast(char)((v % 10) + '0'); 32 } 33 34 /// Make a bit mask of one bit at n position 35 template BIT(int n) if (n <= 31) { enum uint BIT = 1 << n; } 36 37 enum : uint { 38 MAX_LEAF = 0x20, /// Maximum leaf override 39 MAX_VLEAF = 0x4000_0000 + MAX_LEAF, /// Maximum virt leaf override 40 MAX_ELEAF = 0x8000_0000 + MAX_LEAF, /// Maximum extended leaf override 41 } 42 43 /// Command-line options 44 struct options_t { align(1): 45 // FILE *file; /// Dump 46 int maxLevel; /// Maximum leaf for -r (-S) 47 int maxSub; /// Maximum subleaf for -r (-s) 48 bool hasLevel; /// If -S has been used 49 bool table; /// Raw table (-r) 50 bool override_; /// Override leaves (-o) 51 bool getLevel; /// Get x86-64 optimization feature level 52 bool getDetails; /// Get the boring details 53 bool[3] reserved; /// 54 } 55 56 immutable const(char) *secret = r" 57 ############ 58 ###################### 59 ########################### 60 ################# 61 ############ ####### 62 ######### _ _ ### R ##### 63 ####### | | | | ########### 64 ####### __| | __| | ######## 65 ##### / _ | / _ | ###### 66 ##### | (_| || (_| | ##### 67 #### \____| \____| #### 68 ### _ ### 69 ### [_] [_] | | ## 70 ## _ _ __ ___ _ __| | ____ ### 71 ### | || '_ \/ __/| | / _ |/ __ \ ### 72 ### | || | | |\__ \| || (_| || __/ #### 73 ### |_||_| |_||___/|_| \____|\____| ##### 74 ##### ##### 75 ###### ###### 76 ####### ####### 77 ######### ########### 78 ############################### 79 ###################### 80 "; 81 82 //TODO: Consider having a CPUINFO instance globally to avoid parameter spam 83 84 /// print help page 85 void clih() { 86 puts( 87 "x86/AMD64 CPUID information tool\n"~ 88 "\n"~ 89 "USAGE\n"~ 90 " ddcpuid [OPTIONS...]\n"~ 91 "\n"~ 92 "OPTIONS\n"~ 93 " -d, --details Show detailed processor information\n"~ 94 " -r, --table Show raw CPUID data in a table\n"~ 95 " -S Table: Set leaf (EAX) input value\n"~ 96 " -s Table: Set subleaf (ECX) input value\n"~ 97 // " -D, --dump Dump CPUID data into binary\n"~ 98 " -o Override maximum leaves to 0x20, 0x4000_0020, and 0x8000_0020\n"~ 99 " -l, --level Print the processor's feature level\n"~ 100 "\n"~ 101 "PAGES\n"~ 102 " --version Print version screen and quit\n"~ 103 " --ver Print version and quit\n"~ 104 " -h, --help Print this help screen and quit" 105 ); 106 } 107 108 /// print version page 109 void cliv() { 110 puts( 111 "ddcpuid-"~DDCPUID_PLATFORM~" "~DDCPUID_VERSION~" (built: "~__TIMESTAMP__~")\n"~ 112 "Copyright (c) 2016-2021 dd86k <dd@dax.moe>\n"~ 113 "License: MIT License <http://opensource.org/licenses/MIT>\n"~ 114 "Homepage: <https://github.com/dd86k/ddcpuid>\n"~ 115 "Compiler: "~__VENDOR__~" "~CVER!(__VERSION__) 116 ); 117 } 118 119 void outcpuid(uint leaf, uint sub/*, FILE *file*/) { 120 REGISTERS regs = void; 121 asmcpuid(regs, leaf, sub); 122 /* if (file) { 123 dumpWrite(file, &leaf, leaf.sizeof); 124 dumpWrite(file, &sub, sub.sizeof); 125 dumpWrite(file, ®s, regs.sizeof); 126 } else {*/ 127 printcpuid(regs, leaf, sub); 128 // } 129 } 130 131 /// Print cpuid table entry into stdout. 132 /// Params: 133 /// leaf = EAX input 134 /// sub = ECX input 135 pragma(inline, false) // ldc optimization thing 136 void printcpuid(ref REGISTERS regs, uint leaf, uint sub) { 137 with (regs) 138 printf("| %8x | %8x | %8x | %8x | %8x | %8x |\n", 139 leaf, sub, eax, ebx, ecx, edx); 140 } 141 142 // NOTE: ddcpuid dump structure 143 // char[4]: "ddcu" 144 // ubyte : file format version 145 // ubyte : reserved 146 // ubyte : reserved 147 // ubyte : reserved 148 // uint[6]: leaf, subleaf, eax, ebx, ecx, edx 149 150 /*int dumpOpen(FILE **file, const(char) *path) { 151 return (*file = fopen(path, "w+b")) == null ? errno : 0; 152 } 153 154 int dumpWrite(FILE *file, const(void) *data, size_t size) { 155 return fwrite(data, size, 1, file) != 1; 156 } 157 158 int dumpRead(FILE *file) { 159 160 }*/ 161 162 const(char) *classification(ref CPUINFO info) { 163 // That's a story for another time 164 if (info.extensions.x86_64 == false) goto L_X86_64_NONE; 165 166 // v4 167 if (info.avx.avx512f && info.avx.avx512bw && 168 info.avx.avx512cd && info.avx.avx512dq && 169 info.avx.avx512vl) { 170 return "x86-64-v4"; 171 } 172 173 // v3 174 if (info.avx.avx2 && info.avx.avx && 175 info.extensions.bmi2 && info.extensions.bmi1 && 176 info.extensions.f16c && info.extensions.fma3 && 177 info.extras.lzcnt && info.extras.movbe && 178 info.extras.osxsave) { 179 return "x86-64-v3"; 180 } 181 182 // v2 183 if (info.sse.sse42 && info.sse.sse41 && 184 info.sse.ssse3 && info.sse.sse3 && 185 info.extensions.lahf64 && info.extras.popcnt && 186 info.extras.cmpxchg16b) { 187 return "x86-64-v2"; 188 } 189 190 // baseline 191 if (info.sse.sse2 && info.sse.sse && 192 info.extensions.mmx && info.extras.fxsr && 193 info.extras.cmpxchg8b && info.extras.cmov && 194 info.extensions.fpu && info.extras.syscall) { 195 return "x86-64"; // v1/baseline 196 } 197 198 L_X86_64_NONE: 199 return "i386"; 200 } 201 202 char adjust(ref float size) { 203 version (Trace) trace("size=%u", size); 204 if (size >= 1024.0) { 205 size /= 1024; 206 return 'M'; 207 } 208 return 'K'; 209 } 210 /// adjust 211 @system unittest { 212 uint size = 1; 213 assert(adjust(size) == 'K'); 214 assert(size == 1); 215 size = 1024; 216 assert(adjust(size) == 'M'); 217 assert(size == 1); 218 size = 4096; 219 assert(adjust(size) == 'M'); 220 assert(size == 4); 221 } 222 char adjustBits(ref uint size, int bitpos) { 223 version (Trace) trace("size=%u bit=%d", size, bitpos); 224 immutable char[8] SIZE = [ 0, 'K', 'M', 'G', 'T', 'P', 'E', 'Z' ]; 225 size_t s; 226 while (bitpos >= 10) { 227 bitpos -= 10; 228 ++s; 229 } 230 size = 1 << bitpos; 231 return SIZE[s]; 232 } 233 //TODO: Make DUB to include this main, somehow 234 /// adjustBits 235 @system unittest { 236 float size; 237 assert(adjustBits(size, 0) == 0); 238 assert(size == 1); 239 assert(adjustBits(size, 1) == 0); 240 assert(size == 2); 241 assert(adjustBits(size, 10) == 'K'); 242 assert(size == 1); 243 assert(adjustBits(size, 11) == 'K'); 244 assert(size == 2); 245 assert(adjustBits(size, 20) == 'M'); 246 assert(size == 1); 247 assert(adjustBits(size, 36) == 'G'); 248 assert(size == 64); 249 assert(adjustBits(size, 48) == 'T'); 250 assert(size == 256); 251 } 252 253 void printLegacy(ref CPUINFO info) { 254 if (info.extensions.fpu) { 255 printf(" x87/FPU"); 256 if (info.extensions.f16c) printf(" +F16C"); 257 } 258 if (info.extensions.mmx) { 259 printf(" MMX"); 260 if (info.extensions.mmxExtended) printf(" ExtMMX"); 261 } 262 if (info.extensions._3DNow) { 263 printf(" 3DNow!"); 264 if (info.extensions._3DNowExtended) printf(" Ext3DNow!"); 265 } 266 } 267 void printTechs(ref CPUINFO info) { 268 switch (info.vendorId) { 269 case Vendor.Intel: 270 if (info.tech.eist) printf(" EIST"); 271 if (info.tech.turboboost) { 272 printf(" TurboBoost"); 273 if (info.tech.turboboost30) printf("-3.0"); 274 } 275 if (info.memory.tsx) { 276 printf(" TSX"); 277 if (info.memory.hle) 278 printf(" +HLE"); 279 if (info.memory.rtm) 280 printf(" +RTM"); 281 if (info.memory.tsxldtrk) 282 printf(" +TSXLDTRK"); 283 } 284 if (info.tech.smx) printf(" Intel-TXT/SMX"); 285 if (info.sgx.supported) { 286 // NOTE: SGX system configuration 287 // "enabled" in BIOS: only CPUID.7h.EBX[2] 288 // "user controlled" in BIOS: SGX1/SGX2/size bits 289 if (info.sgx.sgx1 && info.sgx.sgx2) { 290 if (info.sgx.sgx1) printf(" SGX1"); 291 if (info.sgx.sgx2) printf(" SGX2"); 292 } else printf(" SGX"); // Fallback per-say 293 if (info.sgx.maxSize) { 294 uint s32 = void, s64 = void; 295 char m32 = adjustBits(s32, info.sgx.maxSize); 296 char m64 = adjustBits(s64, info.sgx.maxSize64); 297 /*printf(" +maxSize=%u +maxSize64=%u", 298 1 << info.sgx.maxSize, 299 1 << info.sgx.maxSize64);*/ 300 printf(" +maxSize=%u%cB +maxSize64=%u%cB", s32, m32, s64, m64); 301 } 302 } 303 break; 304 case Vendor.AMD: 305 if (info.tech.turboboost) printf(" Core-Performance-Boost"); 306 break; 307 default: 308 } 309 if (info.tech.htt) printf(" HTT"); 310 } 311 void printSSE(ref CPUINFO info) { 312 printf(" SSE"); 313 if (info.sse.sse2) printf(" SSE2"); 314 if (info.sse.sse3) printf(" SSE3"); 315 if (info.sse.ssse3) printf(" SSSE3"); 316 if (info.sse.sse41) printf(" SSE4.1"); 317 if (info.sse.sse42) printf(" SSE4.2"); 318 if (info.sse.sse4a) printf(" SSE4a"); 319 } 320 void printAVX(ref CPUINFO info) { 321 printf(" AVX"); 322 if (info.avx.avx2) printf(" AVX2"); 323 if (info.avx.avx512f) { 324 printf(" AVX512F"); 325 if (info.avx.avx512er) printf(" +ER"); 326 if (info.avx.avx512pf) printf(" +PF"); 327 if (info.avx.avx512cd) printf(" +CD"); 328 if (info.avx.avx512dq) printf(" +DQ"); 329 if (info.avx.avx512bw) printf(" +BW"); 330 if (info.avx.avx512vl) printf(" +VL"); 331 if (info.avx.avx512_ifma) printf(" +IFMA"); 332 if (info.avx.avx512_vbmi) printf(" +VBMI"); 333 if (info.avx.avx512_4vnniw) printf(" +4VNNIW"); 334 if (info.avx.avx512_4fmaps) printf(" +4FMAPS"); 335 if (info.avx.avx512_vbmi2) printf(" +VBMI2"); 336 if (info.avx.avx512_gfni) printf(" +GFNI"); 337 if (info.avx.avx512_vaes) printf(" +VAES"); 338 if (info.avx.avx512_vnni) printf(" +VNNI"); 339 if (info.avx.avx512_bitalg) printf(" +BITALG"); 340 if (info.avx.avx512_bf16) printf(" +BF16"); 341 if (info.avx.avx512_vp2intersect) printf(" +VP2INTERSECT"); 342 } 343 if (info.extensions.xop) printf(" XOP"); 344 } 345 void printFMA(ref CPUINFO info) { 346 if (info.extensions.fma3) printf(" FMA3"); 347 if (info.extensions.fma4) printf(" FMA4"); 348 } 349 void printAMX(ref CPUINFO info) { 350 printf(" AMX"); 351 if (info.amx.bf16) printf(" +BF16"); 352 if (info.amx.int8) printf(" +INT8"); 353 if (info.amx.xtilecfg) printf(" +XTILECFG"); 354 if (info.amx.xtiledata) printf(" +XTILEDATA"); 355 if (info.amx.xfd) printf(" +XFD"); 356 } 357 void printOthers(ref CPUINFO info) { 358 if (info.extensions.aes_ni) printf(" AES-NI"); 359 if (info.extensions.adx) printf(" ADX"); 360 if (info.extensions.sha) printf(" SHA"); 361 if (info.extensions.tbm) printf(" TBM"); 362 if (info.extensions.bmi1) printf(" BMI1"); 363 if (info.extensions.bmi2) printf(" BMI2"); 364 if (info.extensions.waitpkg) printf(" WAITPKG"); 365 } 366 void printSecurity(ref CPUINFO info) { 367 if (info.security.ibpb) printf(" IBPB"); 368 if (info.security.ibrs) printf(" IBRS"); 369 if (info.security.ibrsAlwaysOn) printf(" IBRS_ON"); // AMD 370 if (info.security.ibrsPreferred) printf(" IBRS_PREF"); // AMD 371 if (info.security.stibp) printf(" STIBP"); 372 if (info.security.stibpAlwaysOn) printf(" STIBP_ON"); // AMD 373 if (info.security.ssbd) printf(" SSBD"); 374 if (info.security.l1dFlush) printf(" L1D_FLUSH"); // Intel 375 if (info.security.md_clear) printf(" MD_CLEAR"); // Intel 376 if (info.security.cetIbt) printf(" CET_IBT"); // Intel 377 if (info.security.cetSs) printf(" CET_SS"); // Intel 378 } 379 void printCacheFeats(ushort feats) { 380 if (feats & BIT!(0)) printf(" SI"); // Self Initiative 381 if (feats & BIT!(1)) printf(" FA"); // Fully Associative 382 if (feats & BIT!(2)) printf(" NWBV"); // No Write-Back Validation 383 if (feats & BIT!(3)) printf(" CI"); // Cache Inclusive 384 if (feats & BIT!(4)) printf(" CCI"); // Complex Cache Indexing 385 } 386 387 version (unittest) {} else 388 int main(int argc, const(char) **argv) { 389 options_t options; /// Command-line options 390 391 const(char) *arg = void; 392 // int e = void; 393 for (int argi = 1; argi < argc; ++argi) { 394 if (argv[argi][1] == '-') { // Long arguments 395 arg = argv[argi] + 2; 396 /* if (strcmp(arg, "dump") == 0) { 397 if (++argi >= argc) { 398 puts("Missing argument: path"); 399 return 1; 400 } 401 e = dumpOpen(&options.file, argv[argi]); 402 if (e) { 403 printf("Couldn't open file: %s\n", strerror(e)); 404 return 2; 405 } 406 continue; 407 }*/ 408 if (strcmp(arg, "table") == 0) { 409 options.table = true; 410 continue; 411 } 412 if (strcmp(arg, "level") == 0) { 413 options.getLevel = true; 414 continue; 415 } 416 if (strcmp(arg, "details") == 0) { 417 options.getDetails = true; 418 continue; 419 } 420 if (strcmp(arg, "version") == 0) { 421 cliv; 422 return 0; 423 } 424 if (strcmp(arg, "ver") == 0) { 425 puts(DDCPUID_VERSION); 426 return 0; 427 } 428 if (strcmp(arg, "help") == 0) { 429 clih; 430 return 0; 431 } 432 if (strcmp(arg, "inside") == 0) { 433 puts(secret); 434 return 0; 435 } 436 printf("Unknown parameter: '%s'\n", arg); 437 return 1; 438 } else if (argv[argi][0] == '-') { // Short arguments 439 arg = argv[argi] + 1; 440 char o = void; 441 while ((o = *arg) != 0) { 442 ++arg; 443 switch (o) { 444 case 'd': options.getDetails = true; continue; 445 case 'l': options.getLevel = true; continue; 446 case 'o': options.override_ = true; continue; 447 case 'r': options.table = true; continue; 448 /* case 'D': 449 if (++argi >= argc) { 450 puts("Missing parameter: file"); 451 return 1; 452 } 453 e = dumpOpen(&options.file, argv[argi]); 454 if (e) { 455 printf("Couldn't open file: %s\n", strerror(e)); 456 return 2; 457 } 458 continue;*/ 459 case 'S': 460 if (++argi >= argc) { 461 puts("Missing parameter: leaf"); 462 return 1; 463 } 464 options.hasLevel = sscanf(argv[argi], "%i", &options.maxLevel) == 1; 465 if (options.hasLevel == false) { 466 puts("Could not parse level (-S)"); 467 return 2; 468 } 469 continue; 470 case 's': 471 if (++argi >= argc) { 472 puts("Missing parameter: sub-leaf (-s)"); 473 return 1; 474 } 475 if (sscanf(argv[argi], "%i", &options.maxSub) != 1) { 476 puts("Could not parse sub-level (-s)"); 477 return 2; 478 } 479 continue; 480 case 'h': clih; return 0; 481 case 'V': cliv; return 0; 482 default: 483 printf("Unknown parameter: '-%c'\n", o); 484 return 1; 485 } 486 } // while 487 } // else if 488 } // for 489 490 CPUINFO info; 491 492 if (options.override_ == false) { 493 getLeaves(info); 494 } else { 495 info.maxLeaf = MAX_LEAF; 496 info.maxLeafVirt = MAX_VLEAF; 497 info.maxLeafExtended = MAX_ELEAF; 498 } 499 500 if (options.table/* || options.file*/) { // -r|-D 501 uint l = void, s = void; 502 //TODO: outcpuid should just accept ref options_t and s 503 504 // if (options.file) { 505 // __gshared const(char) *HEADER = "ddcu\x01\x00\x00\x00"; 506 // dumpWrite(options.file, HEADER, 8); 507 // } else { 508 puts( 509 "| Leaf | Sub-leaf | EAX | EBX | ECX | EDX |\n"~ 510 "|----------|----------|----------|----------|----------|----------|" 511 ); 512 // } 513 514 if (options.hasLevel) { 515 for (s = 0; s <= options.maxSub; ++s) 516 outcpuid(options.maxLevel, s/*, options.file*/); 517 return 0; 518 } 519 520 // Normal 521 for (l = 0; l <= info.maxLeaf; ++l) 522 for (s = 0; s <= options.maxSub; ++s) 523 outcpuid(l, s/*, options.file*/); 524 525 // Paravirtualization 526 if (info.maxLeafVirt > 0x4000_0000) 527 for (l = 0x4000_0000; l <= info.maxLeafVirt; ++l) 528 for (s = 0; s <= options.maxSub; ++s) 529 outcpuid(l, s/*, options.file*/); 530 531 // Extended 532 for (l = 0x8000_0000; l <= info.maxLeafExtended; ++l) 533 for (s = 0; s <= options.maxSub; ++s) 534 outcpuid(l, s/*, options.file*/); 535 return 0; 536 } 537 538 getInfo(info); 539 540 if (options.getLevel) { 541 puts(classification(info)); 542 return 0; 543 } 544 545 // NOTE: .ptr crash with GDC -O3 546 // glibc!__strlen_sse2 (in printf) 547 char *vendor = cast(char*)info.vendorString; 548 char *brand = cast(char*)info.brandString; 549 550 // Brand string left space trimming 551 // Extremely common in Intel but let's also do it for others 552 while (*brand == ' ') ++brand; 553 554 CACHEINFO *cache = void; /// Current cache level 555 556 // 557 // ANCHOR Summary 558 // 559 560 if (options.getDetails == false) { 561 uint maxPhys = void; 562 uint maxLine = void; 563 char cphys = adjustBits(maxPhys, info.memory.physBits); 564 char cline = adjustBits(maxLine, info.memory.lineBits); 565 with (info) printf( 566 "Name: %.12s %.48s\n"~ 567 "Identifier: Family 0x%x Model 0x%x Stepping 0x%x\n"~ 568 "Cores: %u cores %u threads\n"~ 569 "Max. Memory: %u%cB physical %u%cB virtual\n"~ 570 "Techs: %s", 571 vendor, brand, 572 family, model, stepping, 573 cores.physical, cores.logical, 574 maxPhys, cphys, maxLine, cline, 575 classification(info) 576 ); 577 578 printTechs(info); 579 580 immutable const(char) *none = " None"; 581 582 printf("\nSSE: "); 583 if (info.sse.sse) { 584 printSSE(info); 585 putchar('\n'); 586 } else puts(none); 587 588 printf("AVX: "); 589 if (info.avx.avx) { 590 printAVX(info); 591 putchar('\n'); 592 } else puts(none); 593 594 printf("AMX: "); 595 if (info.amx.enabled) { 596 printAMX(info); 597 putchar('\n'); 598 } else puts(none); 599 600 printf("Others: "); 601 printLegacy(info); 602 printOthers(info); 603 putchar('\n'); 604 605 printf("Mitigations:"); 606 printSecurity(info); 607 putchar('\n'); 608 609 if (info.virt.vendorId) { 610 const(char) *virtVendor = void; 611 switch (info.virt.vendorId) with (VirtVendor) { 612 case KVM: virtVendor = "KVM"; break; 613 case HyperV: virtVendor = "Hyper-V"; break; 614 case VBoxHyperV: virtVendor = "VirtualBox Hyper-V"; break; 615 case VBoxMin: virtVendor = "VirtualBox Minimal"; break; 616 default: virtVendor = "Unknown"; 617 } 618 printf("ParaVirt.: %s\n", virtVendor); 619 } 620 621 for (size_t i; i < info.cache.levels; ++i) { 622 cache = &info.cache.level[i]; 623 float csize = cache.size; 624 float tsize = csize * cache.sharedCores; 625 char cc = adjust(csize); 626 char ct = adjust(tsize); 627 with (cache) 628 printf("Cache L%u-%c: %ux %g%cB\t(%g%cB)\t", 629 level, type, sharedCores, 630 csize, cc, tsize, ct); 631 printCacheFeats(cache.features); 632 putchar('\n'); 633 } 634 635 return 0; 636 } 637 638 // 639 // ANCHOR Detailed view 640 // 641 642 with (info) printf( 643 "Vendor : %.12s\n"~ 644 "Brand : %.48s\n"~ 645 "Identifier : 0x%x\n"~ 646 "Family : 0x%x\n"~ 647 "BaseFamily : 0x%x\n"~ 648 "ExtFamily : 0x%x\n"~ 649 "Model : 0x%x\n"~ 650 "BaseModel : 0x%x\n"~ 651 "ExtModel : 0x%x\n"~ 652 "Stepping : 0x%x\n"~ 653 "Cores : %u\n"~ 654 "Threads : %u\n"~ 655 "Extensions :", 656 vendor, brand, 657 identifier, 658 family, familyBase, familyExtended, 659 model, modelBase, modelExtended, 660 stepping, 661 cores.physical, cores.logical 662 ); 663 664 printLegacy(info); 665 if (info.sse.sse) printSSE(info); 666 if (info.extensions.x86_64) { 667 switch (info.vendorId) { 668 case Vendor.Intel: printf(" Intel64/x86-64"); break; 669 case Vendor.AMD: printf(" AMD64/x86-64"); break; 670 default: printf(" x86-64"); 671 } 672 if (info.extensions.lahf64) 673 printf(" +LAHF64"); 674 } 675 if (info.virt.available) 676 switch (info.vendorId) { 677 case Vendor.Intel: printf(" VT-x/VMX"); break; 678 case Vendor.AMD: // SVM 679 printf(" AMD-V/VMX"); 680 if (info.virt.version_) 681 printf(":v%u", info.virt.version_); 682 break; 683 case Vendor.VIA: printf(" VIA-VT/VMX"); break; 684 default: printf(" VMX"); 685 } 686 if (info.avx.avx) printAVX(info); 687 printFMA(info); 688 printOthers(info); 689 if (info.amx.enabled) printAMX(info); 690 691 // 692 // ANCHOR Extra/lone instructions 693 // 694 695 printf("\nExtra :"); 696 if (info.extras.monitor) { 697 printf(" MONITOR+MWAIT"); 698 if (info.extras.mwaitMin) 699 printf(" +MIN=%u +MAX=%u", 700 info.extras.mwaitMin, info.extras.mwaitMax); 701 if (info.extras.monitorx) printf(" MONITORX+MWAITX"); 702 } 703 if (info.extras.pclmulqdq) printf(" PCLMULQDQ"); 704 if (info.extras.cmpxchg8b) printf(" CMPXCHG8B"); 705 if (info.extras.cmpxchg16b) printf(" CMPXCHG16B"); 706 if (info.extras.movbe) printf(" MOVBE"); 707 if (info.extras.rdrand) printf(" RDRAND"); 708 if (info.extras.rdseed) printf(" RDSEED"); 709 if (info.extras.rdmsr) printf(" RDMSR+WRMSR"); 710 if (info.extras.sysenter) printf(" SYSENTER+SYSEXIT"); 711 if (info.extras.syscall) printf(" SYSCALL+SYSRET"); 712 if (info.extras.rdtsc) { 713 printf(" RDTSC"); 714 if (info.extras.rdtscDeadline) 715 printf(" +TSC-Deadline"); 716 if (info.extras.rdtscInvariant) 717 printf(" +TSC-Invariant"); 718 } 719 if (info.extras.rdtscp) printf(" RDTSCP"); 720 if (info.extras.rdpid) printf(" RDPID"); 721 if (info.extras.cmov) { 722 printf(" CMOV"); 723 if (info.extensions.fpu) printf(" FCOMI+FCMOV"); 724 } 725 if (info.extras.lzcnt) printf(" LZCNT"); 726 if (info.extras.popcnt) printf(" POPCNT"); 727 if (info.extras.xsave) printf(" XSAVE+XRSTOR"); 728 if (info.extras.osxsave) printf(" XSETBV+XGETBV"); 729 if (info.extras.fxsr) printf(" FXSAVE+FXRSTOR"); 730 if (info.extras.pconfig) printf(" PCONFIG"); 731 if (info.extras.cldemote) printf(" CLDEMOTE"); 732 if (info.extras.movdiri) printf(" MOVDIRI"); 733 if (info.extras.movdir64b) printf(" MOVDIR64B"); 734 if (info.extras.enqcmd) printf(" ENQCMD"); 735 if (info.extras.skinit) printf(" SKINIT+STGI"); 736 if (info.extras.serialize) printf(" SERIALIZE"); 737 738 // 739 // ANCHOR Vendor specific technologies 740 // 741 742 printf("\nTechnologies:"); 743 printTechs(info); 744 745 // 746 // ANCHOR Cache information 747 // 748 749 printf("\nCache :"); 750 if (info.cache.clflush) 751 printf(" CLFLUSH=%uB", info.cache.clflushLinesize << 3); 752 if (info.cache.clflushopt) printf(" CLFLUSHOPT"); 753 if (info.cache.cnxtId) printf(" CNXT-ID"); 754 if (info.cache.ss) printf(" SS"); 755 if (info.cache.prefetchw) printf(" PREFETCHW"); 756 if (info.cache.invpcid) printf(" INVPCID"); 757 if (info.cache.wbnoinvd) printf(" WBNOINVD"); 758 759 for (uint i; i < info.cache.levels; ++i) { 760 cache = &info.cache.level[i]; 761 printf("\nLevel %u-%c : %ux %5u KB, %u ways, %u parts, %u B, %u sets", 762 cache.level, cache.type, cache.sharedCores, cache.size, 763 cache.ways, cache.partitions, cache.lineSize, cache.sets 764 ); 765 printCacheFeats(cache.features); 766 } 767 768 printf("\nSystem :"); 769 if (info.sys.available) printf(" ACPI"); 770 if (info.sys.apic) printf(" APIC"); 771 if (info.sys.x2apic) printf(" x2APIC"); 772 if (info.sys.arat) printf(" ARAT"); 773 if (info.sys.tm) printf(" TM"); 774 if (info.sys.tm2) printf(" TM2"); 775 printf(" APIC-ID=%u", info.sys.apicId); 776 if (info.sys.maxApicId) printf(" MAX-ID=%u", info.sys.maxApicId); 777 778 printf("\nVirtual :"); 779 if (info.virt.vme) printf(" VME"); 780 if (info.virt.apicv) printf(" APICv"); 781 782 // Paravirtualization 783 if (info.virt.vendorId) { 784 // See vendor string case 785 char *virtvendor = cast(char*)info.virt.vendorString; 786 printf(" HOST=%.12s", virtvendor); 787 } 788 switch (info.virt.vendorId) { 789 case VirtVendor.VBoxMin: 790 if (info.virt.vbox.tsc_freq_khz) 791 printf(" TSC_FREQ_KHZ=%u", info.virt.vbox.tsc_freq_khz); 792 if (info.virt.vbox.apic_freq_khz) 793 printf(" APIC_FREQ_KHZ=%u", info.virt.vbox.apic_freq_khz); 794 break; 795 case VirtVendor.HyperV: 796 printf(" OPENSOURCE=%d VENDOR_ID=%d OS=%d MAJOR=%d MINOR=%d SERVICE=%d BUILD=%d", 797 info.virt.hv.guest_opensource, 798 info.virt.hv.guest_vendor_id, 799 info.virt.hv.guest_os, 800 info.virt.hv.guest_major, 801 info.virt.hv.guest_minor, 802 info.virt.hv.guest_service, 803 info.virt.hv.guest_build); 804 if (info.virt.hv.base_feat_vp_runtime_msr) printf(" HV_BASE_FEAT_VP_RUNTIME_MSR"); 805 if (info.virt.hv.base_feat_part_time_ref_count_msr) printf(" HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR"); 806 if (info.virt.hv.base_feat_basic_synic_msrs) printf(" HV_BASE_FEAT_BASIC_SYNIC_MSRS"); 807 if (info.virt.hv.base_feat_stimer_msrs) printf(" HV_BASE_FEAT_STIMER_MSRS"); 808 if (info.virt.hv.base_feat_apic_access_msrs) printf(" HV_BASE_FEAT_APIC_ACCESS_MSRS"); 809 if (info.virt.hv.base_feat_hypercall_msrs) printf(" HV_BASE_FEAT_HYPERCALL_MSRS"); 810 if (info.virt.hv.base_feat_vp_id_msr) printf(" HV_BASE_FEAT_VP_ID_MSR"); 811 if (info.virt.hv.base_feat_virt_sys_reset_msr) printf(" HV_BASE_FEAT_VIRT_SYS_RESET_MSR"); 812 if (info.virt.hv.base_feat_stat_pages_msr) printf(" HV_BASE_FEAT_STAT_PAGES_MSR"); 813 if (info.virt.hv.base_feat_part_ref_tsc_msr) printf(" HV_BASE_FEAT_PART_REF_TSC_MSR"); 814 if (info.virt.hv.base_feat_guest_idle_state_msr) printf(" HV_BASE_FEAT_GUEST_IDLE_STATE_MSR"); 815 if (info.virt.hv.base_feat_timer_freq_msrs) printf(" HV_BASE_FEAT_TIMER_FREQ_MSRS"); 816 if (info.virt.hv.base_feat_debug_msrs) printf(" HV_BASE_FEAT_DEBUG_MSRS"); 817 if (info.virt.hv.part_flags_create_part) printf(" HV_PART_FLAGS_CREATE_PART"); 818 if (info.virt.hv.part_flags_access_part_id) printf(" HV_PART_FLAGS_ACCESS_PART_ID"); 819 if (info.virt.hv.part_flags_access_memory_pool) printf(" HV_PART_FLAGS_ACCESS_MEMORY_POOL"); 820 if (info.virt.hv.part_flags_adjust_msg_buffers) printf(" HV_PART_FLAGS_ADJUST_MSG_BUFFERS"); 821 if (info.virt.hv.part_flags_post_msgs) printf(" HV_PART_FLAGS_POST_MSGS"); 822 if (info.virt.hv.part_flags_signal_events) printf(" HV_PART_FLAGS_SIGNAL_EVENTS"); 823 if (info.virt.hv.part_flags_create_port) printf(" HV_PART_FLAGS_CREATE_PORT"); 824 if (info.virt.hv.part_flags_connect_port) printf(" HV_PART_FLAGS_CONNECT_PORT"); 825 if (info.virt.hv.part_flags_access_stats) printf(" HV_PART_FLAGS_ACCESS_STATS"); 826 if (info.virt.hv.part_flags_debugging) printf(" HV_PART_FLAGS_DEBUGGING"); 827 if (info.virt.hv.part_flags_cpu_mgmt) printf(" HV_PART_FLAGS_CPU_MGMT"); 828 if (info.virt.hv.part_flags_cpu_profiler) printf(" HV_PART_FLAGS_CPU_PROFILER"); 829 if (info.virt.hv.part_flags_expanded_stack_walk) printf(" HV_PART_FLAGS_EXPANDED_STACK_WALK"); 830 if (info.virt.hv.part_flags_access_vsm) printf(" HV_PART_FLAGS_ACCESS_VSM"); 831 if (info.virt.hv.part_flags_access_vp_regs) printf(" HV_PART_FLAGS_ACCESS_VP_REGS"); 832 if (info.virt.hv.part_flags_extended_hypercalls) printf(" HV_PART_FLAGS_EXTENDED_HYPERCALLS"); 833 if (info.virt.hv.part_flags_start_vp) printf(" HV_PART_FLAGS_START_VP"); 834 if (info.virt.hv.pm_max_cpu_power_state_c0) printf(" HV_PM_MAX_CPU_POWER_STATE_C0"); 835 if (info.virt.hv.pm_max_cpu_power_state_c1) printf(" HV_PM_MAX_CPU_POWER_STATE_C1"); 836 if (info.virt.hv.pm_max_cpu_power_state_c2) printf(" HV_PM_MAX_CPU_POWER_STATE_C2"); 837 if (info.virt.hv.pm_max_cpu_power_state_c3) printf(" HV_PM_MAX_CPU_POWER_STATE_C3"); 838 if (info.virt.hv.pm_hpet_reqd_for_c3) printf(" HV_PM_HPET_REQD_FOR_C3"); 839 if (info.virt.hv.misc_feat_mwait) printf(" HV_MISC_FEAT_MWAIT"); 840 if (info.virt.hv.misc_feat_guest_debugging) printf(" HV_MISC_FEAT_GUEST_DEBUGGING"); 841 if (info.virt.hv.misc_feat_perf_mon) printf(" HV_MISC_FEAT_PERF_MON"); 842 if (info.virt.hv.misc_feat_pcpu_dyn_part_event) printf(" HV_MISC_FEAT_PCPU_DYN_PART_EVENT"); 843 if (info.virt.hv.misc_feat_xmm_hypercall_input) printf(" HV_MISC_FEAT_XMM_HYPERCALL_INPUT"); 844 if (info.virt.hv.misc_feat_guest_idle_state) printf(" HV_MISC_FEAT_GUEST_IDLE_STATE"); 845 if (info.virt.hv.misc_feat_hypervisor_sleep_state) printf(" HV_MISC_FEAT_HYPERVISOR_SLEEP_STATE"); 846 if (info.virt.hv.misc_feat_query_numa_distance) printf(" HV_MISC_FEAT_QUERY_NUMA_DISTANCE"); 847 if (info.virt.hv.misc_feat_timer_freq) printf(" HV_MISC_FEAT_TIMER_FREQ"); 848 if (info.virt.hv.misc_feat_inject_synmc_xcpt) printf(" HV_MISC_FEAT_INJECT_SYNMC_XCPT"); 849 if (info.virt.hv.misc_feat_guest_crash_msrs) printf(" HV_MISC_FEAT_GUEST_CRASH_MSRS"); 850 if (info.virt.hv.misc_feat_debug_msrs) printf(" HV_MISC_FEAT_DEBUG_MSRS"); 851 if (info.virt.hv.misc_feat_npiep1) printf(" HV_MISC_FEAT_NPIEP1"); 852 if (info.virt.hv.misc_feat_disable_hypervisor) printf(" HV_MISC_FEAT_DISABLE_HYPERVISOR"); 853 if (info.virt.hv.misc_feat_ext_gva_range_for_flush_va_list) printf(" HV_MISC_FEAT_EXT_GVA_RANGE_FOR_FLUSH_VA_LIST"); 854 if (info.virt.hv.misc_feat_hypercall_output_xmm) printf(" HV_MISC_FEAT_HYPERCALL_OUTPUT_XMM"); 855 if (info.virt.hv.misc_feat_sint_polling_mode) printf(" HV_MISC_FEAT_SINT_POLLING_MODE"); 856 if (info.virt.hv.misc_feat_hypercall_msr_lock) printf(" HV_MISC_FEAT_HYPERCALL_MSR_LOCK"); 857 if (info.virt.hv.misc_feat_use_direct_synth_msrs) printf(" HV_MISC_FEAT_USE_DIRECT_SYNTH_MSRS"); 858 if (info.virt.hv.hint_hypercall_for_process_switch) printf(" HV_HINT_HYPERCALL_FOR_PROCESS_SWITCH"); 859 if (info.virt.hv.hint_hypercall_for_tlb_flush) printf(" HV_HINT_HYPERCALL_FOR_TLB_FLUSH"); 860 if (info.virt.hv.hint_hypercall_for_tlb_shootdown) printf(" HV_HINT_HYPERCALL_FOR_TLB_SHOOTDOWN"); 861 if (info.virt.hv.hint_msr_for_apic_access) printf(" HV_HINT_MSR_FOR_APIC_ACCESS"); 862 if (info.virt.hv.hint_msr_for_sys_reset) printf(" HV_HINT_MSR_FOR_SYS_RESET"); 863 if (info.virt.hv.hint_relax_time_checks) printf(" HV_HINT_RELAX_TIME_CHECKS"); 864 if (info.virt.hv.hint_dma_remapping) printf(" HV_HINT_DMA_REMAPPING"); 865 if (info.virt.hv.hint_interrupt_remapping) printf(" HV_HINT_INTERRUPT_REMAPPING"); 866 if (info.virt.hv.hint_x2apic_msrs) printf(" HV_HINT_X2APIC_MSRS"); 867 if (info.virt.hv.hint_deprecate_auto_eoi) printf(" HV_HINT_DEPRECATE_AUTO_EOI"); 868 if (info.virt.hv.hint_synth_cluster_ipi_hypercall) printf(" HV_HINT_SYNTH_CLUSTER_IPI_HYPERCALL"); 869 if (info.virt.hv.hint_ex_proc_masks_interface) printf(" HV_HINT_EX_PROC_MASKS_INTERFACE"); 870 if (info.virt.hv.hint_nested_hyperv) printf(" HV_HINT_NESTED_HYPERV"); 871 if (info.virt.hv.hint_int_for_mbec_syscalls) printf(" HV_HINT_INT_FOR_MBEC_SYSCALLS"); 872 if (info.virt.hv.hint_nested_enlightened_vmcs_interface) printf(" HV_HINT_NESTED_ENLIGHTENED_VMCS_INTERFACE"); 873 if (info.virt.hv.host_feat_avic) printf(" HV_HOST_FEAT_AVIC"); 874 if (info.virt.hv.host_feat_msr_bitmap) printf(" HV_HOST_FEAT_MSR_BITMAP"); 875 if (info.virt.hv.host_feat_perf_counter) printf(" HV_HOST_FEAT_PERF_COUNTER"); 876 if (info.virt.hv.host_feat_nested_paging) printf(" HV_HOST_FEAT_NESTED_PAGING"); 877 if (info.virt.hv.host_feat_dma_remapping) printf(" HV_HOST_FEAT_DMA_REMAPPING"); 878 if (info.virt.hv.host_feat_interrupt_remapping) printf(" HV_HOST_FEAT_INTERRUPT_REMAPPING"); 879 if (info.virt.hv.host_feat_mem_patrol_scrubber) printf(" HV_HOST_FEAT_MEM_PATROL_SCRUBBER"); 880 if (info.virt.hv.host_feat_dma_prot_in_use) printf(" HV_HOST_FEAT_DMA_PROT_IN_USE"); 881 if (info.virt.hv.host_feat_hpet_requested) printf(" HV_HOST_FEAT_HPET_REQUESTED"); 882 if (info.virt.hv.host_feat_stimer_volatile) printf(" HV_HOST_FEAT_STIMER_VOLATILE"); 883 break; 884 case VirtVendor.KVM: 885 if (info.virt.kvm.feature_clocksource) printf(" KVM_FEATURE_CLOCKSOURCE"); 886 if (info.virt.kvm.feature_nop_io_delay) printf(" KVM_FEATURE_NOP_IO_DELAY"); 887 if (info.virt.kvm.feature_mmu_op) printf(" KVM_FEATURE_MMU_OP"); 888 if (info.virt.kvm.feature_clocksource2) printf(" KVM_FEATURE_CLOCKSOURCE2"); 889 if (info.virt.kvm.feature_async_pf) printf(" KVM_FEATURE_ASYNC_PF"); 890 if (info.virt.kvm.feature_steal_time) printf(" KVM_FEATURE_STEAL_TIME"); 891 if (info.virt.kvm.feature_pv_eoi) printf(" KVM_FEATURE_PV_EOI"); 892 if (info.virt.kvm.feature_pv_unhault) printf(" KVM_FEATURE_PV_UNHAULT"); 893 if (info.virt.kvm.feature_pv_tlb_flush) printf(" KVM_FEATURE_PV_TLB_FLUSH"); 894 if (info.virt.kvm.feature_async_pf_vmexit) printf(" KVM_FEATURE_ASYNC_PF_VMEXIT"); 895 if (info.virt.kvm.feature_pv_send_ipi) printf(" KVM_FEATURE_PV_SEND_IPI"); 896 if (info.virt.kvm.feature_pv_poll_control) printf(" KVM_FEATURE_PV_POLL_CONTROL"); 897 if (info.virt.kvm.feature_pv_sched_yield) printf(" KVM_FEATURE_PV_SCHED_YIELD"); 898 if (info.virt.kvm.feature_clocsource_stable_bit) printf(" KVM_FEATURE_CLOCSOURCE_STABLE_BIT"); 899 if (info.virt.kvm.hint_realtime) printf(" KVM_HINTS_REALTIME"); 900 break; 901 default: 902 } 903 904 printf("\nMemory :"); 905 906 if (info.memory.pae) printf(" PAE"); 907 if (info.memory.pse) printf(" PSE"); 908 if (info.memory.pse36) printf(" PSE-36"); 909 if (info.memory.page1gb) printf(" Page1GB"); 910 if (info.memory.nx) 911 switch (info.vendorId) { 912 case Vendor.Intel: printf(" Intel-XD/NX"); break; 913 case Vendor.AMD: printf(" AMD-EVP/NX"); break; 914 default: printf(" NX"); 915 } 916 if (info.memory.dca) printf(" DCA"); 917 if (info.memory.pat) printf(" PAT"); 918 if (info.memory.mtrr) printf(" MTRR"); 919 if (info.memory.pge) printf(" PGE"); 920 if (info.memory.smep) printf(" SMEP"); 921 if (info.memory.smap) printf(" SMAP"); 922 if (info.memory.pku) printf(" PKU"); 923 if (info.memory._5pl) printf(" 5PL"); 924 if (info.memory.fsrepmov) printf(" FSRM"); 925 if (info.memory.lam) printf(" LAM"); 926 927 with (info.memory) 928 printf("\nPhysicalBits: %u\nLinearBits : %u\nDebugging :", 929 physBits, lineBits); 930 931 if (info.debugging.mca) printf(" MCA"); 932 if (info.debugging.mce) printf(" MCE"); 933 if (info.debugging.de) printf(" DE"); 934 if (info.debugging.ds) printf(" DS"); 935 if (info.debugging.dsCpl) printf(" DS-CPL"); 936 if (info.debugging.dtes64) printf(" DTES64"); 937 if (info.debugging.pdcm) printf(" PDCM"); 938 if (info.debugging.sdbg) printf(" SDBG"); 939 if (info.debugging.pbe) printf(" PBE"); 940 941 printf("\nSecurity :"); 942 if (info.security.ia32_arch_capabilities) printf(" IA32_ARCH_CAPABILITIES"); 943 printSecurity(info); 944 945 with (info) 946 printf( 947 "\nMax. Leaf : 0x%x\n"~ 948 "Max. V-Leaf : 0x%x\n"~ 949 "Max. E-Leaf : 0x%x\n"~ 950 "Type : %s\n"~ 951 "Brand Index : %u\n"~ 952 "Misc. :", 953 maxLeaf, maxLeafVirt, maxLeafExtended, typeString, brandIndex); 954 955 if (info.misc.xtpr) printf(" xTPR"); 956 if (info.misc.psn) printf(" PSN"); 957 if (info.misc.pcid) printf(" PCID"); 958 if (info.misc.fsgsbase) printf(" FSGSBASE"); 959 if (info.misc.uintr) printf(" UINTR"); 960 961 putchar('\n'); 962 963 return 0; 964 }