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. 6 * 7 * Authors: dd86k (dd@dax.moe) 8 * Copyright: © 2016-2021 dd86k 9 * License: MIT 10 */ 11 module main; 12 13 import ddcpuid; 14 15 private: 16 @system: 17 extern (C): 18 19 int strcmp(scope const char*, scope const char*); 20 int puts(scope const char*); 21 int putchar(int); 22 int atoi(scope const char*); 23 24 static if (__VERSION__ >= 2092) { 25 pragma(printf) 26 int printf(scope const char*, ...); 27 } else { 28 int printf(scope const char*, ...); 29 } 30 31 /// Compiler version template for betterC usage 32 template CVER(int v) { 33 enum CVER = 34 cast(char)((v / 1000) + '0') ~ 35 "." ~ 36 cast(char)(((v % 1000) / 100) + '0') ~ 37 cast(char)(((v % 100) / 10) + '0') ~ 38 cast(char)((v % 10) + '0'); 39 } 40 41 /// Make a bit mask of one bit at n position 42 template BIT(int n) if (n <= 31) { enum uint BIT = 1 << n; } 43 44 enum : uint { 45 MAX_LEAF = 0x20, /// Maximum leaf override 46 MAX_VLEAF = 0x4000_0020, /// Maximum virt leaf override 47 MAX_ELEAF = 0x8000_0020, /// Maximum extended leaf override 48 } 49 50 /// Command-line options 51 struct options_t { 52 uint maxsub; /// Maximum subleaf for -r (-s) 53 bool table; /// Raw table (-r) 54 bool override_; /// Override leaves (-o) 55 bool optlevel; /// Get x86-64 optimization feature level 56 } 57 58 /// print help page 59 void clih() { 60 puts( 61 "x86/AMD64 CPUID information tool\n"~ 62 "\n"~ 63 "USAGE\n"~ 64 " ddcpuid [OPTIONS...]\n"~ 65 "\n"~ 66 "OPTIONS\n"~ 67 " -r, --table Show raw CPUID data in a table\n"~ 68 " -s Set subleaf (ECX) input value with -r\n"~ 69 " -o Override maximum leaves to 20h, 4000_0020h, and 8000_0020h\n"~ 70 " -l, --level Print the processor's feature level\n"~ 71 "\n"~ 72 "PAGES\n"~ 73 " --version Print version screen and quit\n"~ 74 " --ver Print version and quit\n"~ 75 " -h, --help Print this help screen and quit" 76 ); 77 } 78 79 /// print version page 80 void cliv() { 81 puts( 82 "ddcpuid-"~DDCPUID_PLATFORM~" v"~DDCPUID_VERSION~" ("~__TIMESTAMP__~")\n"~ 83 "Copyright (c) 2016-2021 dd86k <dd@dax.moe>\n"~ 84 "License: MIT License <http://opensource.org/licenses/MIT>\n"~ 85 "Project page: <https://github.com/dd86k/ddcpuid>\n"~ 86 "Compiler: "~__VENDOR__~" v"~CVER!(__VERSION__) 87 ); 88 } 89 90 /// Print cpuid table entry into stdout. 91 /// Params: 92 /// leaf = EAX input 93 /// sub = ECX input 94 pragma(inline, false) // ldc optimization thing 95 void printcpuid(uint leaf, uint sub) { 96 REGISTERS regs = void; 97 asmcpuid(regs, leaf, sub); 98 with (regs) 99 printf("| %8x | %8x | %8x | %8x | %8x | %8x |\n", 100 leaf, sub, eax, ebx, ecx, edx); 101 } 102 103 int main(int argc, const(char) **argv) { 104 options_t opts; /// Command-line options 105 106 const(char) *arg = void; 107 for (int argi = 1; argi < argc; ++argi) { 108 if (argv[argi][1] == '-') { // Long arguments 109 arg = argv[argi] + 2; 110 if (strcmp(arg, "level") == 0) { opts.optlevel = true; continue; } 111 if (strcmp(arg, "version") == 0) { cliv; return 0; } 112 if (strcmp(arg, "ver") == 0) { puts(DDCPUID_VERSION); return 0; } 113 if (strcmp(arg, "help") == 0) { clih; return 0; } 114 printf("Unknown parameter: '%s'\n", arg); 115 return 1; 116 } else if (argv[argi][0] == '-') { // Short arguments 117 arg = argv[argi] + 1; 118 char o = void; 119 while ((o = *arg) != 0) { 120 ++arg; 121 switch (o) { 122 case 'l': opts.optlevel = true; continue; 123 case 'o': opts.override_ = true; continue; 124 case 'r': opts.table = true; continue; 125 case 's': //TODO: Consider supporting -sN syntax 126 if (++argi >= argc) { 127 puts("Missing parameter: sub-leaf (-s)"); 128 return 1; 129 } 130 opts.maxsub = atoi(argv[argi]); 131 continue; 132 case 'h': clih; return 0; 133 case 'V': cliv; return 0; 134 default: 135 printf("Unknown parameter: '-%c'\n", o); 136 return 1; 137 } 138 } 139 } // else if 140 } // for 141 142 CPUINFO info; 143 144 if (opts.override_ == false) { 145 getLeaves(info); 146 } else { 147 info.max_leaf = MAX_LEAF; 148 info.max_virt_leaf = MAX_VLEAF; 149 info.max_ext_leaf = MAX_ELEAF; 150 } 151 152 if (opts.table) { // -r 153 puts( 154 "| Leaf | Sub-leaf | EAX | EBX | ECX | EDX |\n"~ 155 "|----------|----------|----------|----------|----------|----------|" 156 ); 157 158 // Normal 159 uint l = void, s = void; 160 for (l = 0; l <= info.max_leaf; ++l) 161 for (s = 0; s <= opts.maxsub; ++s) 162 printcpuid(l, s); 163 164 // Paravirtualization 165 if (info.max_virt_leaf > 0x4000_0000) 166 for (l = 0x4000_0000; l <= info.max_virt_leaf; ++l) 167 for (s = 0; s <= opts.maxsub; ++s) 168 printcpuid(l, s); 169 170 // Extended 171 for (l = 0x8000_0000; l <= info.max_ext_leaf; ++l) 172 for (s = 0; s <= opts.maxsub; ++s) 173 printcpuid(l, s); 174 return 0; 175 } 176 177 getInfo(info); 178 179 if (opts.optlevel) { 180 // That's a story for another time 181 if (info.ext.x86_64 == false) goto L_X86_64_NONE; 182 183 // v4 184 if (info.ext.avx512f && info.ext.avx512bw && 185 info.ext.avx512cd && info.ext.avx512dq && 186 info.ext.avx512vl) { 187 puts("x86-64-v4"); 188 return 0; 189 } 190 191 // v3 192 if (info.ext.avx2 && info.ext.avx && 193 info.ext.bmi2 && info.ext.bmi1 && 194 info.ext.f16c && info.ext.fma3 && 195 info.extras.lzcnt && info.extras.movbe && 196 info.extras.osxsave) { 197 puts("x86-64-v3"); 198 return 0; 199 } 200 201 // v2 202 if (info.ext.sse42 && info.ext.sse41 && 203 info.ext.ssse3 && info.ext.sse3 && 204 info.ext.lahf64 && info.extras.popcnt && 205 info.extras.cmpxchg16b) { 206 puts("x86-64-v2"); 207 return 0; 208 } 209 210 // baseline 211 if (info.ext.sse2 && info.ext.sse && 212 info.ext.mmx && info.extras.fxsr && 213 info.extras.cmpxchg8b && info.extras.cmov && 214 info.ext.fpu && info.extras.syscall) { 215 puts("x86-64"); // v1/base 216 return 0; 217 } 218 219 L_X86_64_NONE: 220 puts("none"); 221 return 0; 222 } 223 224 // NOTE: .ptr crash with GDC -O3 225 // glibc!__strlen_sse2 (in printf) 226 char *vendor = cast(char*)info.vendor; 227 char *brand = cast(char*)info.brand; 228 229 // Brand string left space trimming 230 // Extremely common in Intel but let's also do it for others 231 while (*brand == ' ') ++brand; 232 233 // 234 // ANCHOR Processor basic information 235 // 236 237 printf( 238 "Vendor : %.12s\n"~ 239 "Brand : %.48s\n"~ 240 "Identifier : Family %u (0x%x) [0x%x:0x%x] Model %u (0x%x) [0x%x:0x%x] Stepping %u\n"~ 241 "Cores : %u threads\n"~ 242 "Extensions :", 243 vendor, brand, 244 info.family, info.family, info.family_base, info.family_ext, 245 info.model, info.model, info.model_base, info.model_ext, 246 info.stepping, 247 info.cores.logical 248 ); 249 250 if (info.ext.fpu) { 251 printf(" x87/FPU"); 252 if (info.ext.f16c) printf(" +F16C"); 253 } 254 if (info.ext.mmx) { 255 printf(" MMX"); 256 if (info.ext.mmxext) printf(" ExtMMX"); 257 } 258 if (info.ext._3dnow) { 259 printf(" 3DNow!"); 260 if (info.ext._3dnowext) printf(" Ext3DNow!"); 261 } 262 if (info.ext.sse) { 263 printf(" SSE"); 264 if (info.ext.sse2) printf(" SSE2"); 265 if (info.ext.sse3) printf(" SSE3"); 266 if (info.ext.ssse3) printf(" SSSE3"); 267 if (info.ext.sse41) printf(" SSE4.1"); 268 if (info.ext.sse42) printf(" SSE4.2"); 269 if (info.ext.sse4a) printf(" SSE4a"); 270 if (info.ext.xop) printf(" XOP"); 271 } 272 if (info.ext.x86_64) { 273 switch (info.vendor_id) { 274 case Vendor.Intel: printf(" Intel64/x86-64"); break; 275 case Vendor.AMD: printf(" AMD64/x86-64"); break; 276 default: printf(" x86-64"); 277 } 278 if (info.ext.lahf64) 279 printf(" +LAHF64"); 280 } 281 if (info.virt.available) 282 switch (info.vendor_id) { 283 case Vendor.Intel: printf(" VT-x/VMX"); break; 284 case Vendor.AMD: // SVM 285 printf(" AMD-V/VMX"); 286 if (info.virt.version_) 287 printf(":v%u", info.virt.version_); 288 break; 289 case Vendor.VIA: printf(" VIA-VT/VMX"); break; 290 default: printf(" VMX"); 291 } 292 if (info.ext.aes_ni) printf(" AES-NI"); 293 if (info.ext.avx) printf(" AVX"); 294 if (info.ext.avx2) printf(" AVX2"); 295 if (info.ext.avx512f) { 296 printf(" AVX512F"); 297 if (info.ext.avx512er) printf(" AVX512ER"); 298 if (info.ext.avx512pf) printf(" AVX512PF"); 299 if (info.ext.avx512cd) printf(" AVX512CD"); 300 if (info.ext.avx512dq) printf(" AVX512DQ"); 301 if (info.ext.avx512bw) printf(" AVX512BW"); 302 if (info.ext.avx512vl) printf(" AVX512VL"); 303 if (info.ext.avx512_ifma) printf(" AVX512_IFMA"); 304 if (info.ext.avx512_vbmi) printf(" AVX512_VBMI"); 305 if (info.ext.avx512_4vnniw) printf(" AVX512_4VNNIW"); 306 if (info.ext.avx512_4fmaps) printf(" AVX512_4FMAPS"); 307 if (info.ext.avx512_vbmi2) printf(" AVX512_VBMI2"); 308 if (info.ext.avx512_gfni) printf(" AVX512_GFNI"); 309 if (info.ext.avx512_vaes) printf(" AVX512_VAES"); 310 if (info.ext.avx512_vnni) printf(" AVX512_VNNI"); 311 if (info.ext.avx512_bitalg) printf(" AVX512_BITALG"); 312 if (info.ext.avx512_bf16) printf(" AVX512_BF16"); 313 if (info.ext.avx512_vp2intersect) printf(" AVX512_VP2INTERSECT"); 314 } 315 if (info.ext.adx) printf(" ADX"); 316 if (info.ext.sha) printf(" SHA"); 317 if (info.ext.fma3) printf(" FMA3"); 318 if (info.ext.fma4) printf(" FMA4"); 319 if (info.ext.tbm) printf(" TBM"); 320 if (info.ext.bmi1) printf(" BMI1"); 321 if (info.ext.bmi2) printf(" BMI2"); 322 if (info.ext.waitpkg) printf(" WAITPKG"); 323 if (info.ext.amx) printf(" AMX"); 324 if (info.ext.amx_bf16) printf(" +BF16"); 325 if (info.ext.amx_int8) printf(" +INT8"); 326 if (info.ext.amx_xtilecfg) printf(" +XTILECFG"); 327 if (info.ext.amx_xtiledata) printf(" +XTILEDATA"); 328 if (info.ext.amx_xfd) printf(" +XFD"); 329 330 // 331 // ANCHOR Extra/lone instructions 332 // 333 334 printf("\nExtra :"); 335 if (info.extras.monitor) { 336 printf(" MONITOR+MWAIT"); 337 if (info.extras.mwait_min) 338 printf(" +MIN=%u +MAX=%u", 339 info.extras.mwait_min, info.extras.mwait_max); 340 if (info.extras.monitorx) printf(" MONITORX+MWAITX"); 341 } 342 if (info.extras.pclmulqdq) printf(" PCLMULQDQ"); 343 if (info.extras.cmpxchg8b) printf(" CMPXCHG8B"); 344 if (info.extras.cmpxchg16b) printf(" CMPXCHG16B"); 345 if (info.extras.movbe) printf(" MOVBE"); 346 if (info.extras.rdrand) printf(" RDRAND"); 347 if (info.extras.rdseed) printf(" RDSEED"); 348 if (info.extras.rdmsr) printf(" RDMSR+WRMSR"); 349 if (info.extras.sysenter) printf(" SYSENTER+SYSEXIT"); 350 if (info.extras.syscall) printf(" SYSCALL+SYSRET"); 351 if (info.extras.rdtsc) { 352 printf(" RDTSC"); 353 if (info.extras.rdtsc_deadline) 354 printf(" +TSC-Deadline"); 355 if (info.extras.rdtsc_invariant) 356 printf(" +TSC-Invariant"); 357 } 358 if (info.extras.rdtscp) printf(" RDTSCP"); 359 if (info.extras.rdpid) printf(" RDPID"); 360 if (info.extras.cmov) { 361 printf(" CMOV"); 362 if (info.ext.fpu) printf(" FCOMI+FCMOV"); 363 } 364 if (info.extras.lzcnt) printf(" LZCNT"); 365 if (info.extras.popcnt) printf(" POPCNT"); 366 if (info.extras.xsave) printf(" XSAVE+XRSTOR"); 367 if (info.extras.osxsave) printf(" XSETBV+XGETBV"); 368 if (info.extras.fxsr) printf(" FXSAVE+FXRSTOR"); 369 if (info.extras.pconfig) printf(" PCONFIG"); 370 if (info.extras.cldemote) printf(" CLDEMOTE"); 371 if (info.extras.movdiri) printf(" MOVDIRI"); 372 if (info.extras.movdir64b) printf(" MOVDIR64B"); 373 if (info.extras.enqcmd) printf(" ENQCMD"); 374 if (info.extras.skinit) printf(" SKINIT+STGI"); 375 if (info.extras.serialize) printf(" SERIALIZE"); 376 377 // 378 // ANCHOR Vendor specific technologies 379 // 380 381 printf("\nTechnologies:"); 382 383 switch (info.vendor_id) { 384 case Vendor.Intel: 385 if (info.tech.eist) printf(" EIST"); 386 if (info.tech.turboboost) 387 printf(info.tech.turboboost30 ? 388 " TurboBoot-3.0" : " TurboBoost"); 389 if (info.mem.tsx) { 390 printf(" TSX"); 391 if (info.mem.hle) 392 printf(" +HLE"); 393 if (info.mem.rtm) 394 printf(" +RTM"); 395 if (info.mem.tsxldtrk) 396 printf(" +TSXLDTRK"); 397 } 398 if (info.tech.smx) printf(" Intel-TXT/SMX"); 399 if (info.tech.sgx) printf(" SGX"); 400 break; 401 case Vendor.AMD: 402 if (info.tech.turboboost) printf(" Core-Performance-Boost"); 403 break; 404 default: 405 } 406 if (info.tech.htt) printf(" HTT"); 407 408 // 409 // ANCHOR Cache information 410 // 411 412 printf("\nCache :"); 413 if (info.cache.clflush) 414 printf(" CLFLUSH=%uB", info.cache.clflush_linesize << 3); 415 if (info.cache.clflushopt) printf(" CLFLUSHOPT"); 416 if (info.cache.cnxt_id) printf(" CNXT_ID"); 417 if (info.cache.ss) printf(" SS"); 418 if (info.cache.prefetchw) printf(" PREFETCHW"); 419 if (info.cache.invpcid) printf(" INVPCID"); 420 if (info.cache.wbnoinvd) printf(" WBNOINVD"); 421 422 for (uint i; i < info.cache.levels; ++i) { 423 CACHEINFO *cache = &info.cache.level[i]; 424 char c = 'K'; 425 if (cache.size >= 1024) { 426 cache.size >>= 10; 427 c = 'M'; 428 } 429 printf("\n\tL%u-%c: %ux %4u %ciB, %u ways, %u parts, %u B, %u sets", 430 cache.level, cache.type, cache.sharedCores, cache.size, c, 431 cache.ways, cache.partitions, cache.linesize, cache.sets 432 ); 433 if (cache.feat & BIT!(0)) printf(" +SI"); // Self Initiative 434 if (cache.feat & BIT!(1)) printf(" +FA"); // Fully Associative 435 if (cache.feat & BIT!(2)) printf(" +NWBV"); // No Write-Back Validation 436 if (cache.feat & BIT!(3)) printf(" +CI"); // Cache Inclusive 437 if (cache.feat & BIT!(4)) printf(" +CCI"); // Complex Cache Indexing 438 } 439 440 printf("\nACPI :"); 441 if (info.acpi.available) printf(" ACPI"); 442 if (info.acpi.apic) printf(" APIC"); 443 if (info.acpi.x2apic) printf(" x2APIC"); 444 if (info.acpi.arat) printf(" ARAT"); 445 if (info.acpi.tm) printf(" TM"); 446 if (info.acpi.tm2) printf(" TM2"); 447 printf(" APIC-ID=%u", info.acpi.apic_id); 448 if (info.acpi.max_apic_id) printf(" MAX-ID=%u", info.acpi.max_apic_id); 449 450 printf("\nVirtual :"); 451 if (info.virt.vme) printf(" VME"); 452 if (info.virt.apivc) printf(" APICv"); 453 454 // Paravirtualization 455 if (info.virt.vendor_id) { 456 // See earlier NOTE 457 char *virtvendor = cast(char*)info.virt.vendor; 458 printf(" HOST=%.12s", virtvendor); 459 } 460 switch (info.virt.vendor_id) { 461 case VirtVendor.VBoxMin: 462 if (info.virt.vbox_tsc_freq_khz) 463 printf(" TSC_FREQ_KHZ=%u", info.virt.vbox_tsc_freq_khz); 464 if (info.virt.vbox_apic_freq_khz) 465 printf(" APIC_FREQ_KHZ=%u", info.virt.vbox_apic_freq_khz); 466 break; 467 case VirtVendor.HyperV: 468 printf(" OPENSOURCE=%d VENDOR_ID=%d OS=%d MAJOR=%d MINOR=%d SERVICE=%d BUILD=%d", 469 info.virt.hv_guest_opensource, 470 info.virt.hv_guest_vendor_id, 471 info.virt.hv_guest_os, 472 info.virt.hv_guest_major, 473 info.virt.hv_guest_minor, 474 info.virt.hv_guest_service, 475 info.virt.hv_guest_build); 476 if (info.virt.hv_base_feat_vp_runtime_msr) printf(" HV_BASE_FEAT_VP_RUNTIME_MSR"); 477 if (info.virt.hv_base_feat_part_time_ref_count_msr) printf(" HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR"); 478 if (info.virt.hv_base_feat_basic_synic_msrs) printf(" HV_BASE_FEAT_BASIC_SYNIC_MSRS"); 479 if (info.virt.hv_base_feat_stimer_msrs) printf(" HV_BASE_FEAT_STIMER_MSRS"); 480 if (info.virt.hv_base_feat_apic_access_msrs) printf(" HV_BASE_FEAT_APIC_ACCESS_MSRS"); 481 if (info.virt.hv_base_feat_hypercall_msrs) printf(" HV_BASE_FEAT_HYPERCALL_MSRS"); 482 if (info.virt.hv_base_feat_vp_id_msr) printf(" HV_BASE_FEAT_VP_ID_MSR"); 483 if (info.virt.hv_base_feat_virt_sys_reset_msr) printf(" HV_BASE_FEAT_VIRT_SYS_RESET_MSR"); 484 if (info.virt.hv_base_feat_stat_pages_msr) printf(" HV_BASE_FEAT_STAT_PAGES_MSR"); 485 if (info.virt.hv_base_feat_part_ref_tsc_msr) printf(" HV_BASE_FEAT_PART_REF_TSC_MSR"); 486 if (info.virt.hv_base_feat_guest_idle_state_msr) printf(" HV_BASE_FEAT_GUEST_IDLE_STATE_MSR"); 487 if (info.virt.hv_base_feat_timer_freq_msrs) printf(" HV_BASE_FEAT_TIMER_FREQ_MSRS"); 488 if (info.virt.hv_base_feat_debug_msrs) printf(" HV_BASE_FEAT_DEBUG_MSRS"); 489 if (info.virt.hv_part_flags_create_part) printf(" HV_PART_FLAGS_CREATE_PART"); 490 if (info.virt.hv_part_flags_access_part_id) printf(" HV_PART_FLAGS_ACCESS_PART_ID"); 491 if (info.virt.hv_part_flags_access_memory_pool) printf(" HV_PART_FLAGS_ACCESS_MEMORY_POOL"); 492 if (info.virt.hv_part_flags_adjust_msg_buffers) printf(" HV_PART_FLAGS_ADJUST_MSG_BUFFERS"); 493 if (info.virt.hv_part_flags_post_msgs) printf(" HV_PART_FLAGS_POST_MSGS"); 494 if (info.virt.hv_part_flags_signal_events) printf(" HV_PART_FLAGS_SIGNAL_EVENTS"); 495 if (info.virt.hv_part_flags_create_port) printf(" HV_PART_FLAGS_CREATE_PORT"); 496 if (info.virt.hv_part_flags_connect_port) printf(" HV_PART_FLAGS_CONNECT_PORT"); 497 if (info.virt.hv_part_flags_access_stats) printf(" HV_PART_FLAGS_ACCESS_STATS"); 498 if (info.virt.hv_part_flags_debugging) printf(" HV_PART_FLAGS_DEBUGGING"); 499 if (info.virt.hv_part_flags_cpu_mgmt) printf(" HV_PART_FLAGS_CPU_MGMT"); 500 if (info.virt.hv_part_flags_cpu_profiler) printf(" HV_PART_FLAGS_CPU_PROFILER"); 501 if (info.virt.hv_part_flags_expanded_stack_walk) printf(" HV_PART_FLAGS_EXPANDED_STACK_WALK"); 502 if (info.virt.hv_part_flags_access_vsm) printf(" HV_PART_FLAGS_ACCESS_VSM"); 503 if (info.virt.hv_part_flags_access_vp_regs) printf(" HV_PART_FLAGS_ACCESS_VP_REGS"); 504 if (info.virt.hv_part_flags_extended_hypercalls) printf(" HV_PART_FLAGS_EXTENDED_HYPERCALLS"); 505 if (info.virt.hv_part_flags_start_vp) printf(" HV_PART_FLAGS_START_VP"); 506 if (info.virt.hv_pm_max_cpu_power_state_c0) printf(" HV_PM_MAX_CPU_POWER_STATE_C0"); 507 if (info.virt.hv_pm_max_cpu_power_state_c1) printf(" HV_PM_MAX_CPU_POWER_STATE_C1"); 508 if (info.virt.hv_pm_max_cpu_power_state_c2) printf(" HV_PM_MAX_CPU_POWER_STATE_C2"); 509 if (info.virt.hv_pm_max_cpu_power_state_c3) printf(" HV_PM_MAX_CPU_POWER_STATE_C3"); 510 if (info.virt.hv_pm_hpet_reqd_for_c3) printf(" HV_PM_HPET_REQD_FOR_C3"); 511 if (info.virt.hv_misc_feat_mwait) printf(" HV_MISC_FEAT_MWAIT"); 512 if (info.virt.hv_misc_feat_guest_debugging) printf(" HV_MISC_FEAT_GUEST_DEBUGGING"); 513 if (info.virt.hv_misc_feat_perf_mon) printf(" HV_MISC_FEAT_PERF_MON"); 514 if (info.virt.hv_misc_feat_pcpu_dyn_part_event) printf(" HV_MISC_FEAT_PCPU_DYN_PART_EVENT"); 515 if (info.virt.hv_misc_feat_xmm_hypercall_input) printf(" HV_MISC_FEAT_XMM_HYPERCALL_INPUT"); 516 if (info.virt.hv_misc_feat_guest_idle_state) printf(" HV_MISC_FEAT_GUEST_IDLE_STATE"); 517 if (info.virt.hv_misc_feat_hypervisor_sleep_state) printf(" HV_MISC_FEAT_HYPERVISOR_SLEEP_STATE"); 518 if (info.virt.hv_misc_feat_query_numa_distance) printf(" HV_MISC_FEAT_QUERY_NUMA_DISTANCE"); 519 if (info.virt.hv_misc_feat_timer_freq) printf(" HV_MISC_FEAT_TIMER_FREQ"); 520 if (info.virt.hv_misc_feat_inject_synmc_xcpt) printf(" HV_MISC_FEAT_INJECT_SYNMC_XCPT"); 521 if (info.virt.hv_misc_feat_guest_crash_msrs) printf(" HV_MISC_FEAT_GUEST_CRASH_MSRS"); 522 if (info.virt.hv_misc_feat_debug_msrs) printf(" HV_MISC_FEAT_DEBUG_MSRS"); 523 if (info.virt.hv_misc_feat_npiep1) printf(" HV_MISC_FEAT_NPIEP1"); 524 if (info.virt.hv_misc_feat_disable_hypervisor) printf(" HV_MISC_FEAT_DISABLE_HYPERVISOR"); 525 if (info.virt.hv_misc_feat_ext_gva_range_for_flush_va_list) printf(" HV_MISC_FEAT_EXT_GVA_RANGE_FOR_FLUSH_VA_LIST"); 526 if (info.virt.hv_misc_feat_hypercall_output_xmm) printf(" HV_MISC_FEAT_HYPERCALL_OUTPUT_XMM"); 527 if (info.virt.hv_misc_feat_sint_polling_mode) printf(" HV_MISC_FEAT_SINT_POLLING_MODE"); 528 if (info.virt.hv_misc_feat_hypercall_msr_lock) printf(" HV_MISC_FEAT_HYPERCALL_MSR_LOCK"); 529 if (info.virt.hv_misc_feat_use_direct_synth_msrs) printf(" HV_MISC_FEAT_USE_DIRECT_SYNTH_MSRS"); 530 if (info.virt.hv_hint_hypercall_for_process_switch) printf(" HV_HINT_HYPERCALL_FOR_PROCESS_SWITCH"); 531 if (info.virt.hv_hint_hypercall_for_tlb_flush) printf(" HV_HINT_HYPERCALL_FOR_TLB_FLUSH"); 532 if (info.virt.hv_hint_hypercall_for_tlb_shootdown) printf(" HV_HINT_HYPERCALL_FOR_TLB_SHOOTDOWN"); 533 if (info.virt.hv_hint_msr_for_apic_access) printf(" HV_HINT_MSR_FOR_APIC_ACCESS"); 534 if (info.virt.hv_hint_msr_for_sys_reset) printf(" HV_HINT_MSR_FOR_SYS_RESET"); 535 if (info.virt.hv_hint_relax_time_checks) printf(" HV_HINT_RELAX_TIME_CHECKS"); 536 if (info.virt.hv_hint_dma_remapping) printf(" HV_HINT_DMA_REMAPPING"); 537 if (info.virt.hv_hint_interrupt_remapping) printf(" HV_HINT_INTERRUPT_REMAPPING"); 538 if (info.virt.hv_hint_x2apic_msrs) printf(" HV_HINT_X2APIC_MSRS"); 539 if (info.virt.hv_hint_deprecate_auto_eoi) printf(" HV_HINT_DEPRECATE_AUTO_EOI"); 540 if (info.virt.hv_hint_synth_cluster_ipi_hypercall) printf(" HV_HINT_SYNTH_CLUSTER_IPI_HYPERCALL"); 541 if (info.virt.hv_hint_ex_proc_masks_interface) printf(" HV_HINT_EX_PROC_MASKS_INTERFACE"); 542 if (info.virt.hv_hint_nested_hyperv) printf(" HV_HINT_NESTED_HYPERV"); 543 if (info.virt.hv_hint_int_for_mbec_syscalls) printf(" HV_HINT_INT_FOR_MBEC_SYSCALLS"); 544 if (info.virt.hv_hint_nested_enlightened_vmcs_interface) printf(" HV_HINT_NESTED_ENLIGHTENED_VMCS_INTERFACE"); 545 if (info.virt.hv_host_feat_avic) printf(" HV_HOST_FEAT_AVIC"); 546 if (info.virt.hv_host_feat_msr_bitmap) printf(" HV_HOST_FEAT_MSR_BITMAP"); 547 if (info.virt.hv_host_feat_perf_counter) printf(" HV_HOST_FEAT_PERF_COUNTER"); 548 if (info.virt.hv_host_feat_nested_paging) printf(" HV_HOST_FEAT_NESTED_PAGING"); 549 if (info.virt.hv_host_feat_dma_remapping) printf(" HV_HOST_FEAT_DMA_REMAPPING"); 550 if (info.virt.hv_host_feat_interrupt_remapping) printf(" HV_HOST_FEAT_INTERRUPT_REMAPPING"); 551 if (info.virt.hv_host_feat_mem_patrol_scrubber) printf(" HV_HOST_FEAT_MEM_PATROL_SCRUBBER"); 552 if (info.virt.hv_host_feat_dma_prot_in_use) printf(" HV_HOST_FEAT_DMA_PROT_IN_USE"); 553 if (info.virt.hv_host_feat_hpet_requested) printf(" HV_HOST_FEAT_HPET_REQUESTED"); 554 if (info.virt.hv_host_feat_stimer_volatile) printf(" HV_HOST_FEAT_STIMER_VOLATILE"); 555 break; 556 case VirtVendor.KVM: 557 if (info.virt.kvm_feature_clocksource) printf(" KVM_FEATURE_CLOCKSOURCE"); 558 if (info.virt.kvm_feature_nop_io_delay) printf(" KVM_FEATURE_NOP_IO_DELAY"); 559 if (info.virt.kvm_feature_mmu_op) printf(" KVM_FEATURE_MMU_OP"); 560 if (info.virt.kvm_feature_clocksource2) printf(" KVM_FEATURE_CLOCKSOURCE2"); 561 if (info.virt.kvm_feature_async_pf) printf(" KVM_FEATURE_ASYNC_PF"); 562 if (info.virt.kvm_feature_steal_time) printf(" KVM_FEATURE_STEAL_TIME"); 563 if (info.virt.kvm_feature_pv_eoi) printf(" KVM_FEATURE_PV_EOI"); 564 if (info.virt.kvm_feature_pv_unhault) printf(" KVM_FEATURE_PV_UNHAULT"); 565 if (info.virt.kvm_feature_pv_tlb_flush) printf(" KVM_FEATURE_PV_TLB_FLUSH"); 566 if (info.virt.kvm_feature_async_pf_vmexit) printf(" KVM_FEATURE_ASYNC_PF_VMEXIT"); 567 if (info.virt.kvm_feature_pv_send_ipi) printf(" KVM_FEATURE_PV_SEND_IPI"); 568 if (info.virt.kvm_feature_pv_poll_control) printf(" KVM_FEATURE_PV_POLL_CONTROL"); 569 if (info.virt.kvm_feature_pv_sched_yield) printf(" KVM_FEATURE_PV_SCHED_YIELD"); 570 if (info.virt.kvm_feature_clocsource_stable_bit) printf(" KVM_FEATURE_CLOCSOURCE_STABLE_BIT"); 571 if (info.virt.kvm_hint_realtime) printf(" KVM_HINTS_REALTIME"); 572 break; 573 default: 574 } 575 576 printf("\nMemory :"); 577 if (info.mem.phys_bits) printf(" P-Bits=%u", info.mem.phys_bits); 578 if (info.mem.line_bits) printf(" L-Bits=%u", info.mem.line_bits); 579 if (info.mem.pae) printf(" PAE"); 580 if (info.mem.pse) printf(" PSE"); 581 if (info.mem.pse_36) printf(" PSE-36"); 582 if (info.mem.page1gb) printf(" Page1GB"); 583 if (info.mem.nx) 584 switch (info.vendor_id) { 585 case Vendor.Intel: printf(" Intel-XD/NX"); break; 586 case Vendor.AMD: printf(" AMD-EVP/NX"); break; 587 default: printf(" NX"); 588 } 589 if (info.mem.dca) printf(" DCA"); 590 if (info.mem.pat) printf(" PAT"); 591 if (info.mem.mtrr) printf(" MTRR"); 592 if (info.mem.pge) printf(" PGE"); 593 if (info.mem.smep) printf(" SMEP"); 594 if (info.mem.smap) printf(" SMAP"); 595 if (info.mem.pku) printf(" PKU"); 596 if (info.mem._5pl) printf(" 5PL"); 597 if (info.mem.fsrepmov) printf(" FSRM"); 598 if (info.mem.lam) printf(" LAM"); 599 600 printf("\nDebugging :"); 601 if (info.dbg.mca) printf(" MCA"); 602 if (info.dbg.mce) printf(" MCE"); 603 if (info.dbg.de) printf(" DE"); 604 if (info.dbg.ds) printf(" DS"); 605 if (info.dbg.ds_cpl) printf(" DS-CPL"); 606 if (info.dbg.dtes64) printf(" DTES64"); 607 if (info.dbg.pdcm) printf(" PDCM"); 608 if (info.dbg.sdbg) printf(" SDBG"); 609 if (info.dbg.pbe) printf(" PBE"); 610 611 printf("\nSecurity :"); 612 if (info.sec.ia32_arch_capabilities) printf(" IA32_ARCH_CAPABILITIES"); 613 if (info.sec.ibpb) printf(" IBPB"); 614 if (info.sec.ibrs) printf(" IBRS"); 615 if (info.sec.ibrs_on) printf(" IBRS_ON"); // AMD 616 if (info.sec.ibrs_pref) printf(" IBRS_PREF"); // AMD 617 if (info.sec.stibp) printf(" STIBP"); 618 if (info.sec.stibp_on) printf(" STIBP_ON"); // AMD 619 if (info.sec.ssbd) printf(" SSBD"); 620 if (info.sec.l1d_flush) printf(" L1D_FLUSH"); // Intel 621 if (info.sec.md_clear) printf(" MD_CLEAR"); // Intel 622 if (info.sec.cet_ibt) printf(" CET_IBT"); // Intel 623 if (info.sec.cet_ss) printf(" CET_SS"); // Intel 624 625 printf("\nMisc. : HLeaf=0x%x HVLeaf=0x%x HELeaf=0x%x Type=%s Index=%u", 626 info.max_leaf, info.max_virt_leaf, info.max_ext_leaf, 627 info.type_string, info.brand_index); 628 if (info.misc.xtpr) printf(" xTPR"); 629 if (info.misc.psn) printf(" PSN"); 630 if (info.misc.pcid) printf(" PCID"); 631 if (info.misc.fsgsbase) printf(" FSGSBASE"); 632 if (info.misc.uintr) printf(" UINTR"); 633 634 putchar('\n'); 635 636 return 0; 637 }