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