Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / bin / sysinfo.cpp
blob1429c2260fb1e0c386f93da4d236cf57132ad368
1 /*
2 * Copyright 2004-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2002, Carlos Hasan.
5 * Distributed under the terms of the MIT license.
6 */
9 #include <OS.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
15 #include <cpu_type.h>
18 // TODO: -disable_cpu_sn option is not yet implemented
19 // TODO: most of this file should go into an architecture dependent source file
20 #if defined(__INTEL__) || defined(__x86_64__)
22 struct cache_description {
23 uint8 code;
24 const char *description;
25 } static sIntelCacheDescriptions[] = {
26 {0x01, "Instruction TLB: 4k-byte pages, 4-way set associative, 32 entries"},
27 {0x02, "Instruction TLB: 4M-byte pages, fully associative, 2 entries"},
28 {0x03, "Data TLB: 4k-byte pages, 4-way set associative, 64 entries"},
29 {0x04, "Data TLB: 4M-byte pages, 4-way set associative, 8 entries"},
30 {0x05, "Data TLB: 4M-byte pages, 4-way set associative, 32 entries"},
31 {0x06, "L1 inst cache: 8 KB, 4-way set associative, 32 bytes/line"},
32 {0x08, "L1 inst cache: 16 KB, 4-way set associative, 32 bytes/line"},
33 {0x0A, "L1 data cache: 8 KB, 2-way set associative, 32 bytes/line"},
34 {0x0C, "L1 data cache: 16 KB, 4-way set associative, 32 bytes/line"},
35 {0x0D, "L1 data cache: 16 KB, 4-way set associative, 64-bytes/line, ECC"},
36 {0x0E, "L1 data cache, 24 KB, 6-way set associative, 64-bytes/line"},
37 {0x10, /* IA-64 */ "L1 data cache: 16 KB, 4-way set associative, 32 bytes/line"},
38 {0x15, /* IA-64 */ "L1 inst cache: 16 KB, 4-way set associative, 32 bytes/line"},
39 {0x1A, /* IA-64 */ "L2 cache: 96 KB, 6-way set associative, 64 bytes/line"},
40 {0x21, "L2 cache: 256 KB (MLC), 8-way set associative, 64-bytes/line"},
41 {0x22, "L3 cache: 512 KB, 4-way set associative (!), 64 bytes/line, dual-sectored"},
42 {0x23, "L3 cache: 1 MB, 8-way set associative, 64 bytes/line, dual-sectored"},
43 {0x25, "L3 cache: 2 MB, 8-way set associative, 64 bytes/line, dual-sectored"},
44 {0x29, "L3 cache: 4 MB, 8-way set associative, 64 bytes/line, dual-sectored"},
45 {0x2c, "L1 data cache: 32 KB, 8-way set associative, 64 bytes/line"},
46 {0x30, "L1 inst cache: 32 KB, 8-way set associative, 64 bytes/line"},
47 {0x39, "L2 cache: 128 KB, 4-way set associative, 64 bytes/line, sectored"},
48 {0x3A, "L2 cache: 192 KB, 4-way set associative, 64 bytes/line, sectored"},
49 {0x3B, "L2 cache: 128 KB, 2-way set associative, 64 bytes/line, sectored"},
50 {0x3C, "L2 cache: 256 KB, 4-way set associative, 64 bytes/line, sectored"},
51 {0x3D, "L2 cache: 384 KB, 6-way set associative, 64 bytes/line, sectored"},
52 {0x3E, "L2 cache: 512 KB, 4-way set associative, 64 bytes/line, sectored"},
53 {0x40, NULL /*"No integrated L2 cache (P6 core) or L3 cache (P4 core)"*/},
54 // this one is separately handled
55 {0x41, "L2 cache: 128 KB, 4-way set associative, 32 bytes/line"},
56 {0x42, "L2 cache: 256 KB, 4-way set associative, 32 bytes/line"},
57 {0x43, "L2 cache: 512 KB, 4-way set associative, 32 bytes/line"},
58 {0x44, "L2 cache: 1024 KB, 4-way set associative, 32 bytes/line"},
59 {0x45, "L2 cache: 2048 KB, 4-way set associative, 32 bytes/line"},
60 {0x46, "L3 cache: 4096 KB, 4-way set associative, 64 bytes/line"},
61 {0x47, "L3 cache: 8192 KB, 8-way set associative, 64 bytes/line"},
62 {0x48, "L2 cache: 3072 KB, 12-way set associative, 64 bytes/line, unified on-die"},
63 // 0x49 requires special handling, either 4M L3 (Xeon MP, 0F06; otherwise 4M L2
64 {0x4A, "L3 cache: 6144 KB, 12-way set associative, 64 bytes/line"},
65 {0x4B, "L3 cache: 8192 KB, 16-way set associative, 64 bytes/line"},
66 {0x4C, "L3 cache: 12288 KB, 12-way set associative, 64 bytes/line"},
67 {0x4D, "L3 cache: 16384 KB, 16-way set associative, 64 bytes/line"},
68 {0x4E, "L2 cache: 6144 KB, 24-way set associative, 64 bytes/line"},
69 {0x4F, "Inst TLB, 4K-bytes pages, 32 entries"},
70 {0x50, "Inst TLB: 4K/4M/2M-bytes pages, fully associative, 64 entries"},
71 {0x51, "Inst TLB: 4K/4M/2M-bytes pages, fully associative, 128 entries"},
72 {0x52, "Inst TLB: 4K/4M/2M-bytes pages, fully associative, 256 entries"},
73 {0x55, "Inst TLB: 2M/4M-bytes pages, fully associative, 7 entries"},
74 {0x56, "L1 Data TLB: 4M-bytes pages, 4-way set associative, 16 entries"},
75 {0x57, "L1 Data TLB: 4K-bytes pages, 4-way set associative, 16 entries"},
76 {0x59, "L0 Data TLB, 4K-bytes pages, fully associative, 16 entries"},
77 {0x5A, "Data TLB: 2M/4M-bytes pages, 4-way set associative, 32 entries"},
78 {0x5B, "Data TLB: 4K/4M-bytes pages, fully associative, 64 entries"},
79 {0x5C, "Data TLB: 4K/4M-bytes pages, fully associative, 128 entries"},
80 {0x5D, "Data TLB: 4K/4M-bytes pages, fully associative, 256 entries"},
81 {0x66, "L1 data cache: 8 KB, 4-way set associative, 64 bytes/line, sectored"},
82 {0x67, "L1 data cache: 16 KB, 4-way set associative, 64 bytes/line, sectored"},
83 {0x68, "L1 data cache: 32 KB, 4-way set associative, 64 bytes/line, sectored"},
84 {0x70, "Inst trace cache: 12K µOPs, 8-way set associative"},
85 {0x71, "Inst trace cache: 16K µOPs, 8-way set associative"},
86 {0x72, "Inst trace cache: 32K µOPs, 8-way set associative"},
87 {0x77, /* IA-64 */ "L1 inst cache: 16 KB, 4-way set associative, 64 bytes/line, sectored"},
88 {0x79, "L2 cache: 128 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
89 {0x7A, "L2 cache: 256 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
90 {0x7B, "L2 cache: 512 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
91 {0x7C, "L2 cache: 1024 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
92 {0x7D, "L2 cache: 2048 KB, 8-way set associative, 64 bytes/line"},
93 {0x7E, /* IA-64 */ "L2 cache: 256 KB, 8-way set associative, 128 bytes/line, sectored"},
94 {0x7F, "L2 cache: 512 KB, 2-way set associative, 64 bytes/line"},
95 {0x81, "L2 cache: 128 KB, 8-way set associative, 32 bytes/line"},
96 {0x82, "L2 cache: 256 KB, 8-way set associative, 32 bytes/line"},
97 {0x83, "L2 cache: 512 KB, 8-way set associative, 32 bytes/line"},
98 {0x84, "L2 cache: 1024 KB, 8-way set associative, 32 bytes/line"},
99 {0x85, "L2 cache: 2048 KB, 8-way set associative, 32 bytes/line"},
100 {0x86, "L2 cache: 512 KB, 4-way set associative, 64 bytes/line"},
101 {0x87, "L2 cache: 1024 KB, 8-way set associative, 64 bytes/line"},
102 {0x88, /* IA-64 */ "L3 cache: 2 MB, 4-way set associative, 64 bytes/line"},
103 {0x89, /* IA-64 */ "L3 cache: 4 MB, 4-way set associative, 64 bytes/line"},
104 {0x8A, /* IA-64 */ "L3 cache: 8 MB, 4-way set associative, 64 bytes/line"},
105 {0x8D, /* IA-64 */ "L3 cache: 3 MB, 12-way set associative, 128 bytes/line"},
106 {0x90, /* IA-64 */ "Inst TLB: 4K-256Mbytes pages, fully associative, 64 entries"},
107 {0x96, /* IA-64 */ "L1 data TLB: 4K-256M bytes pages, fully associative, 32 entries"},
108 {0x9B, /* IA-64 */ "L2 data TLB: 4K-256M bytes pages, fully associative, 96 entries"},
109 // {0x70, "Cyrix specific: Code and data TLB: 4k-bytes pages, 4-way set associative, 32 entries"},
110 // {0x74, "Cyrix specific: ???"},
111 // {0x77, "Cyrix specific: ???"},
112 {0x80, /* Cyrix specific */ "L1 cache: 16 KB, 4-way set associative, 16 bytes/line"},
113 // {0x82, "Cyrix specific: ???"},
114 // {0x84, "Cyrix specific: ???"},
115 {0xB0, "Inst TLB: 4K-bytes pages, 4-way set associative, 128 entries"},
116 {0xB1, "Inst TLB: 2M-bytes pages, 4-way set associative, 8 entries OR 4M, 4-way, 4 entries"},
117 // Intel doesn't give any details how to determine which of the two options is the case
118 // as per Intel Application Note 485, November 2008.
119 {0xB2, "Inst TLB: 4K-bytes pages, 4-way set associative, 64 entries"},
120 {0xB3, "Data TLB: 4K-bytes pages, 4-way set associative, 128 entries"},
121 {0xB4, "Data TLB: 4K-bytes pages, 4-way set associative, 256 entries"},
122 {0xBA, "Data TLB, 4K-bytes pages, 4-way set associative, 64 entries"},
123 {0xC0, "Data TLB, 4K-4M bytes pages, 4-way set associative, 8 entries"},
124 {0xCA, "Shared 2nd-level TLB: 4K, 4-way set associative, 512 entries"},
125 {0xD0, "L3 cache: 512 KB, 4-way set associative, 64-bytes/line"},
126 {0xD1, "L3 cache: 1024 KB, 4-way set associative, 64-bytes/line"},
127 {0xD2, "L3 cache: 2048 KB, 4-way set associative, 64-bytes/line"},
128 {0xD6, "L3 cache: 1024 KB, 8-way set associative, 64-bytes/line"},
129 {0xD7, "L3 cache: 2048 KB, 8-way set associative, 64-bytes/line"},
130 {0xD8, "L3 cache: 4096 KB, 8-way set associative, 64-bytes/line"},
131 {0xDC, "L3 cache: 2048 KB, 12-way set associative, 64-bytes/line"},
132 {0xDD, "L3 cache: 4096 KB, 12-way set associative, 64-bytes/line"},
133 {0xDE, "L3 cache: 8192 KB, 12-way set associative, 64-bytes/line"},
134 {0xE2, "L3 cache: 2048 KB, 16-way set associative, 64-bytes/line"},
135 {0xE3, "L3 cache: 4096 KB, 16-way set associative, 64-bytes/line"},
136 {0xE4, "L3 cache: 8192 KB, 16-way set associative, 64-bytes/line"},
137 {0xF0, "64-byte Prefetching"},
138 {0xF1, "128-byte Prefetching"},
139 {0, NULL}
143 static void
144 print_intel_cache_descriptors(enum cpu_vendor vendor, uint32 model,
145 cpuid_info *info)
147 uint8 cacheDescriptors[15]; // Max
149 int maxDesc = 0;
150 int i = 0;
152 // put valid values into array
153 if ((info->regs.eax & 0x80000000) == 0) {
154 // eax is valid, include values
155 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
156 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
157 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
158 } else {
159 i += 3;
161 if ((info->regs.ebx & 0x80000000) == 0) {
162 // ebx is valid, include values
163 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
164 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
165 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
166 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
167 } else {
168 i += 4;
170 if ((info->regs.edx & 0x80000000) == 0) {
171 // edx is valid, include values
172 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
173 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
174 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
175 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
176 } else {
177 i += 4;
179 if ((info->regs.ecx & 0x80000000) == 0) {
180 // ecx is valid, include values
181 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
182 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
183 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
184 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
187 putchar('\n');
189 for (int i = 0; i < maxDesc; i++) {
190 // ignore NULL descriptors
191 if (cacheDescriptors[i] == 0)
192 continue;
194 int j;
195 for (j = 0; sIntelCacheDescriptions[j].code; j++) {
196 if (cacheDescriptors[i] == sIntelCacheDescriptions[j].code) {
197 if (cacheDescriptors[i] == 0x40) {
198 printf("\tNo integrated L%u cache\n",
199 ((model >> 8) & 0xf) == 0xf
200 && vendor == B_CPU_VENDOR_INTEL ? 3 : 2);
201 } else
202 printf("\t%s\n", sIntelCacheDescriptions[j].description);
203 break;
207 // Reached the end without finding a descriptor
208 if (sIntelCacheDescriptions[j].code == 0)
209 printf("\tUnknown cache descriptor 0x%02x\n", cacheDescriptors[i]);
214 #endif // __INTEL__ || __x86_64__
217 static void
218 print_TLB(uint32 reg, const char *pages)
220 int entries[2];
221 int ways[2];
222 const char *name[2] = { "Inst TLB", "Data TLB" };
224 entries[0] = (reg & 0xff);
225 ways[0] = ((reg >> 8) & 0xff);
226 entries[1] = ((reg >> 16) & 0xff);
227 ways[1] = ((reg >> 24) & 0xff);
229 for (int num = 0; num < 2; num++) {
230 printf("\t%s: %s%s%u entries, ", name[num],
231 pages ? pages : "", pages ? " pages, " : "", entries[num]);
233 if (ways[num] == 0xff)
234 printf("fully associative\n");
235 else
236 printf("%u-way set associative\n", ways[num]);
241 static void
242 print_level2_cache(uint32 reg, const char *name)
244 uint32 size = (reg >> 16) & 0xffff;
245 uint32 ways = (reg >> 12) & 0xf;
246 uint32 linesPerTag = (reg >> 8) & 0xf;
247 // intel does not define this
248 uint32 lineSize = reg & 0xff;
250 printf("\t%s: %" B_PRIu32 " KB, ", name, size);
251 if (ways == 0xf)
252 printf("fully associative, ");
253 else if (ways == 0x1)
254 printf("direct-mapped, ");
255 else
256 printf("%lu-way set associative, ", 1UL << (ways / 2));
257 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
258 lineSize);
262 static void
263 print_level1_cache(uint32 reg, const char *name)
265 uint32 size = (reg >> 24) & 0xff;
266 uint32 ways = (reg >> 16) & 0xff;
267 uint32 linesPerTag = (reg >> 8) & 0xff;
268 uint32 lineSize = reg & 0xff;
270 printf("\t%s: %" B_PRIu32 " KB, ", name, size);
271 if (ways == 0xff)
272 printf("fully associative, ");
273 else
274 printf("%" B_PRIu32 "-way set associative, ", ways);
275 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
276 lineSize);
280 #if defined(__INTEL__) || defined(__x86_64__)
282 static void
283 print_cache_desc(int32 cpu)
285 cpuid_info info;
286 get_cpuid(&info, 0x80000005, cpu);
288 putchar('\n');
290 if (info.regs.eax)
291 print_TLB(info.regs.eax, info.regs.ebx ? "2M/4M-byte" : NULL);
292 if (info.regs.ebx)
293 print_TLB(info.regs.ebx, info.regs.eax ? "4K-byte" : NULL);
295 print_level1_cache(info.regs.ecx, "L1 inst cache");
296 print_level1_cache(info.regs.edx, "L1 data cache");
298 get_cpuid(&info, 0x80000006, cpu);
299 print_level2_cache(info.regs.ecx, "L2 cache");
303 static void
304 print_intel_cache_desc(int32 cpu)
306 cpuid_info info;
308 // A second parameters needs to be passed to CPUID which determines the
309 // cache level to query
310 get_cpuid(&info, 0x00000004, cpu);
312 putchar('\n');
314 uint32 type = info.regs.eax & 0xf;
315 uint32 level = (info.regs.eax & 0x70) >> 4;
316 bool isFullyAssoc = info.regs.eax & 0x100;
318 uint32 lineSize = (info.regs.ebx & 0xfff) + 1;
319 uint32 linesPerTag = ((info.regs.ebx & 0x3ff000) >> 12) + 1;
320 uint32 ways = ((info.regs.ebx & 0xffc00000) >> 22) + 1;
322 uint32 sets = info.regs.ecx;
324 printf("\tL%" B_PRId32 " ",level);
326 switch (type) {
327 case 1: printf("Data cache "); break;
328 case 2: printf("Inst cache "); break;
329 case 3: printf("Unified cache "); break;
330 default: break;
333 if (isFullyAssoc)
334 printf("fully associative, ");
335 else
336 printf("%" B_PRIu32 "-way set associative, ", ways);
337 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
338 lineSize);
340 get_cpuid(&info, 0x80000006, cpu);
341 print_level2_cache(sets, "L2 cache");
345 static void
346 print_transmeta_features(uint32 features)
348 if (features & (1 << 16))
349 printf("\t\tFCMOV\n");
352 #endif // __INTEL__ || __x86_64__
355 static void
356 print_amd_power_management_features(uint32 features)
358 static const char *kFeatures[6] = {
359 "TS", "FID", "VID", "TTP", "TM", "STC",
361 int32 found = 4;
363 printf("\tPower Management Features:");
365 for (int32 i = 0; i < 6; i++) {
366 if ((features & (1UL << i)) && kFeatures[i] != NULL) {
367 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]);
368 found++;
369 if (found > 0 && (found % 16) == 0) {
370 putchar('\n');
371 found = 0;
376 if (found != 0)
377 putchar('\n');
381 static void
382 print_amd_features(uint32 features)
384 static const char *kFeatures[32] = {
385 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
386 NULL, NULL, NULL, "SCE", NULL, NULL, NULL, NULL,
387 NULL, NULL, NULL, NULL, "NX", NULL, "AMD-MMX", NULL,
388 NULL, "FFXSTR", NULL, "RDTSCP", NULL, "64", "3DNow+", "3DNow!"
390 int32 found = 0;
392 for (int32 i = 0; i < 32; i++) {
393 if ((features & (1UL << i)) && kFeatures[i] != NULL) {
394 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]);
395 found++;
396 if (found > 0 && (found % 16) == 0) {
397 putchar('\n');
398 found = 0;
403 if (found != 0)
404 putchar('\n');
408 static void
409 print_extended_features(uint32 features)
411 static const char *kFeatures[32] = {
412 "SSE3", "PCLMULDQ", "DTES64", "MONITOR", "DS-CPL", "VMX", "SMX", "EST",
413 "TM2", "SSSE3", "CNTXT-ID", NULL, "FMA", "CX16", "xTPR", "PDCM",
414 NULL, "PCID", "DCA", "SSE4.1", "SSE4.2", "x2APIC", "MOVEB", "POPCNT",
415 "TSC-DEADLINE", "AES", "XSAVE", "OSXSAVE", "AVX", "F16C", "RDRND",
416 "HYPERVISOR"
418 int32 found = 0;
420 for (int32 i = 0; i < 32; i++) {
421 if ((features & (1UL << i)) && kFeatures[i] != NULL) {
422 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]);
423 found++;
424 if (found > 0 && (found % 16) == 0) {
425 putchar('\n');
426 found = 0;
431 if (found != 0)
432 putchar('\n');
436 static void
437 print_features(uint32 features)
439 static const char *kFeatures[32] = {
440 "FPU", "VME", "DE", "PSE",
441 "TSC", "MSR", "PAE", "MCE",
442 "CX8", "APIC", NULL, "SEP",
443 "MTRR", "PGE", "MCA", "CMOV",
444 "PAT", "PSE36", "PSN", "CFLUSH",
445 NULL, "DS", "ACPI", "MMX",
446 "FXSTR", "SSE", "SSE2", "SS",
447 "HTT", "TM", NULL, "PBE",
449 int32 found = 0;
451 for (int32 i = 0; i < 32; i++) {
452 if ((features & (1UL << i)) && kFeatures[i] != NULL) {
453 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]);
454 found++;
455 if (found > 0 && (found % 16) == 0) {
456 putchar('\n');
457 found = 0;
462 if (found != 0)
463 putchar('\n');
467 #if defined(__INTEL__) || defined(__x86_64__)
469 static void
470 print_processor_signature(enum cpu_vendor vendor, cpuid_info *info,
471 const char *prefix)
474 if (vendor == B_CPU_VENDOR_AMD) {
475 printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32
476 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n",
477 prefix ? prefix : "", prefix && prefix[0] ? "t" : "T",
478 info->eax_1.type,
479 info->eax_1.family + (info->eax_1.family == 0xf
480 ? info->eax_1.extended_family : 0),
481 info->eax_1.model + (info->eax_1.model == 0xf
482 ? info->eax_1.extended_model << 4 : 0),
483 info->eax_1.stepping,
484 info->eax_1.features);
485 } else if (vendor == B_CPU_VENDOR_INTEL) {
486 // model calculation is different for INTEL
487 printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32
488 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n",
489 prefix ? prefix : "", prefix && prefix[0] ? "t" : "T",
490 info->eax_1.type,
491 info->eax_1.family + (info->eax_1.family == 0xf
492 ? info->eax_1.extended_family : 0),
493 info->eax_1.model
494 + ((info->eax_1.family == 0xf || info->eax_1.family == 0x6)
495 ? info->eax_1.extended_model << 4 : 0),
496 info->eax_1.stepping,
497 info->eax_1.features);
501 #endif // __INTEL__ || __x86_64__
504 static void
505 dump_platform(system_info *info)
507 cpu_topology_node_info root;
508 uint32 count = 1;
509 get_cpu_topology_info(&root, &count);
511 const char* platform;
512 switch (root.data.root.platform) {
513 case B_CPU_x86:
514 platform = "IntelArchitecture";
515 break;
517 case B_CPU_x86_64:
518 platform = "IntelArchitecture (64 bit)";
519 break;
521 default:
522 platform = "unknown";
523 break;
526 printf("%s\n", platform);
530 #if defined(__INTEL__) || defined(__x86_64__)
532 static void
533 dump_cpu(enum cpu_vendor vendor, uint32 model, int32 cpu)
535 // References:
536 // http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html
537 // http://www.sandpile.org/ia32/cpuid.htm
538 // http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/TN13.pdf (Duron erratum)
540 cpuid_info baseInfo;
541 if (get_cpuid(&baseInfo, 0, cpu) != B_OK) {
542 // this CPU doesn't support cpuid
543 return;
546 int32 maxStandardFunction = baseInfo.eax_0.max_eax;
547 if (maxStandardFunction >= 500) {
548 // old Pentium sample chips has cpu signature here
549 maxStandardFunction = 0;
552 // Extended cpuid
554 cpuid_info cpuInfo;
555 get_cpuid(&cpuInfo, 0x80000000, cpu);
557 // Extended cpuid is only supported if max_eax is greater than the
558 // service id
559 int32 maxExtendedFunction = 0;
560 if (cpuInfo.eax_0.max_eax > 0x80000000)
561 maxExtendedFunction = cpuInfo.eax_0.max_eax & 0xff;
563 if (maxExtendedFunction >=4 ) {
564 char buffer[49];
565 char *name = buffer;
567 memset(buffer, 0, sizeof(buffer));
569 for (int32 i = 0; i < 3; i++) {
570 cpuid_info nameInfo;
571 get_cpuid(&nameInfo, 0x80000002 + i, cpu);
573 memcpy(name, &nameInfo.regs.eax, 4);
574 memcpy(name + 4, &nameInfo.regs.ebx, 4);
575 memcpy(name + 8, &nameInfo.regs.ecx, 4);
576 memcpy(name + 12, &nameInfo.regs.edx, 4);
577 name += 16;
580 // cut off leading spaces (names are right aligned)
581 name = buffer;
582 while (name[0] == ' ')
583 name++;
585 // the BIOS may not have set the processor name
586 if (name[0])
587 printf("CPU #%" B_PRId32 ": \"%s\"\n", cpu, name);
588 else {
589 // Intel CPUs don't seem to have the genuine vendor field
590 printf("CPU #%" B_PRId32 ": %.12s\n", cpu,
591 vendor == B_CPU_VENDOR_INTEL ?
592 baseInfo.eax_0.vendor_id : cpuInfo.eax_0.vendor_id);
594 } else {
595 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, baseInfo.eax_0.vendor_id);
596 if (maxStandardFunction == 0)
597 return;
600 get_cpuid(&cpuInfo, 1, cpu);
601 // Dump Raw CPUID
602 printf("\tRaw CPUID: 0x%1" B_PRIx32 "%1" B_PRIx32 "0%1" B_PRIx32
603 "%1" B_PRIx32 "%1" B_PRIx32 ", ", cpuInfo.eax_1.extended_family,
604 cpuInfo.eax_1.extended_model, cpuInfo.eax_1.family,
605 cpuInfo.eax_1.model, cpuInfo.eax_1.stepping);
607 print_processor_signature(vendor, &cpuInfo, NULL);
608 print_features(cpuInfo.eax_1.features);
610 if (maxStandardFunction >= 1) {
611 /* Extended features */
612 printf("\tExtended Intel: 0x%08" B_PRIx32 "\n", cpuInfo.eax_1.extended_features);
613 print_extended_features(cpuInfo.eax_1.extended_features);
616 /* Extended CPUID */
617 if (maxExtendedFunction >= 1) {
618 get_cpuid(&cpuInfo, 0x80000001, cpu);
619 print_processor_signature(vendor, &cpuInfo, "Extended AMD: ");
621 if (vendor == B_CPU_VENDOR_AMD || vendor == B_CPU_VENDOR_INTEL) {
622 print_amd_features(cpuInfo.regs.edx);
623 if (maxExtendedFunction >= 7) {
624 get_cpuid(&cpuInfo, 0x80000007, cpu);
625 print_amd_power_management_features(cpuInfo.regs.edx);
627 } else if (vendor == B_CPU_VENDOR_TRANSMETA)
628 print_transmeta_features(cpuInfo.regs.edx);
631 /* Cache/TLB descriptors */
632 if (maxExtendedFunction >= 5) {
633 if (!strncmp(baseInfo.eax_0.vendor_id, "CyrixInstead", 12)) {
634 get_cpuid(&cpuInfo, 0x00000002, cpu);
635 print_intel_cache_descriptors(vendor, model, &cpuInfo);
636 } else if (vendor == B_CPU_VENDOR_INTEL) {
637 // Intel does not support extended function 5 (but it does 6 hmm)
638 print_intel_cache_desc(cpu);
639 } else {
640 print_cache_desc(cpu);
644 if (maxStandardFunction >= 2) {
645 do {
646 get_cpuid(&cpuInfo, 2, cpu);
648 if (cpuInfo.eax_2.call_num > 0)
649 print_intel_cache_descriptors(vendor, model, &cpuInfo);
650 } while (cpuInfo.eax_2.call_num > 1);
653 /* Serial number */
654 if (maxStandardFunction >= 3) {
655 cpuid_info flagsInfo;
656 get_cpuid(&flagsInfo, 1, cpu);
658 if (flagsInfo.eax_1.features & (1UL << 18)) {
659 get_cpuid(&cpuInfo, 3, cpu);
660 printf("Serial number: %04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32
661 "-%04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 "\n",
662 flagsInfo.eax_1.features >> 16,
663 flagsInfo.eax_1.features & 0xffff,
664 cpuInfo.regs.edx >> 16, cpuInfo.regs.edx & 0xffff,
665 cpuInfo.regs.ecx >> 16, cpuInfo.regs.edx & 0xffff);
669 putchar('\n');
672 #endif // __INTEL__ || __x86_64__
675 static void
676 dump_cpus(system_info *info)
678 uint32 topologyNodeCount = 0;
679 cpu_topology_node_info* topology = NULL;
680 get_cpu_topology_info(NULL, &topologyNodeCount);
681 if (topologyNodeCount != 0)
682 topology = new cpu_topology_node_info[topologyNodeCount];
683 get_cpu_topology_info(topology, &topologyNodeCount);
685 enum cpu_platform platform = B_CPU_UNKNOWN;
686 enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
687 uint32 cpuModel = 0;
688 uint64 frequency = 0;
689 for (uint32 i = 0; i < topologyNodeCount; i++) {
690 switch (topology[i].type) {
691 case B_TOPOLOGY_ROOT:
692 platform = topology[i].data.root.platform;
693 break;
695 case B_TOPOLOGY_PACKAGE:
696 cpuVendor = topology[i].data.package.vendor;
697 break;
699 case B_TOPOLOGY_CORE:
700 cpuModel = topology[i].data.core.model;
701 frequency = topology[i].data.core.default_frequency;
702 break;
704 default:
705 break;
708 delete[] topology;
710 const char *vendor = get_cpu_vendor_string(cpuVendor);
711 const char *model = get_cpu_model_string(platform, cpuVendor, cpuModel);
712 char modelString[32];
714 if (model == NULL && vendor == NULL)
715 model = "(Unknown)";
716 else if (model == NULL) {
717 model = modelString;
718 snprintf(modelString, 32, "(Unknown %" B_PRIx32 ")", cpuModel);
721 printf("%" B_PRId32 " %s%s%s, revision %04" B_PRIx32 " running at %"
722 B_PRIu64 "MHz\n\n",
723 info->cpu_count,
724 vendor ? vendor : "", vendor ? " " : "", model,
725 cpuModel,
726 frequency / 1000000);
728 #if defined(__INTEL__) || defined(__x86_64__)
729 for (uint32 cpu = 0; cpu < info->cpu_count; cpu++)
730 dump_cpu(cpuVendor, cpuModel, cpu);
731 #endif // __INTEL__ || __x86_64__
735 static void
736 dump_mem(system_info *info)
738 printf("%10" B_PRIu64 " bytes free (used/max %10" B_PRIu64 " / %10"
739 B_PRIu64 ")\n",
740 B_PAGE_SIZE * (uint64)(info->max_pages - info->used_pages),
741 B_PAGE_SIZE * (uint64)info->used_pages,
742 B_PAGE_SIZE * (uint64)info->max_pages);
743 printf(" (cached %10" B_PRIu64 ")\n",
744 B_PAGE_SIZE * (uint64)info->cached_pages);
748 static void
749 dump_sem(system_info *info)
751 printf("%10" B_PRId32 " semaphores free (used/max %10" B_PRId32 " / %10"
752 B_PRId32 ")\n",
753 info->max_sems - info->used_sems,
754 info->used_sems, info->max_sems);
758 static void
759 dump_ports(system_info *info)
761 printf("%10" B_PRId32 " ports free (used/max %10" B_PRId32 " / %10"
762 B_PRId32 ")\n",
763 info->max_ports - info->used_ports,
764 info->used_ports, info->max_ports);
768 static void
769 dump_thread(system_info *info)
771 printf("%10" B_PRId32 " threads free (used/max %10" B_PRId32 " / %10"
772 B_PRId32 ")\n",
773 info->max_threads - info->used_threads,
774 info->used_threads, info->max_threads);
778 static void
779 dump_team(system_info *info)
781 printf("%10" B_PRId32 " teams free (used/max %10" B_PRId32 " / %10"
782 B_PRId32 ")\n",
783 info->max_teams - info->used_teams,
784 info->used_teams, info->max_teams);
788 static void
789 dump_kinfo(system_info *info)
791 printf("Kernel name: %s built on: %s %s version 0x%" B_PRIx64 "\n",
792 info->kernel_name,
793 info->kernel_build_date, info->kernel_build_time,
794 info->kernel_version );
798 static void
799 dump_system_info(system_info *info)
801 dump_kinfo(info);
802 dump_cpus(info);
803 dump_mem(info);
804 dump_sem(info);
805 dump_ports(info);
806 dump_thread(info);
807 dump_team(info);
812 main(int argc, char *argv[])
814 if (!is_computer_on()) {
815 printf("The computer is not on! No info available\n");
816 exit(EXIT_FAILURE);
819 system_info info;
820 if (get_system_info(&info) != B_OK) {
821 printf("Error getting system information!\n");
822 return 1;
825 if (argc <= 1) {
826 dump_system_info(&info);
827 } else {
828 for (int i = 1; i < argc; i++) {
829 const char *opt = argv[i];
830 if (strncmp(opt, "-id", strlen(opt)) == 0) {
831 /* note: the original also assumes this option on "sysinfo -" */
832 printf("%#.8x %#.8x\n", 0,0);
833 } else if (strncmp(opt, "-cpu", strlen(opt)) == 0) {
834 dump_cpus(&info);
835 } else if (strncmp(opt, "-mem", strlen(opt)) == 0) {
836 dump_mem(&info);
837 } else if (strncmp(opt, "-semaphores", strlen(opt)) == 0) {
838 dump_sem(&info);
839 } else if (strncmp(opt, "-ports", strlen(opt)) == 0) {
840 dump_ports(&info);
841 } else if (strncmp(opt, "-threads", strlen(opt)) == 0) {
842 dump_thread(&info);
843 } else if (strncmp(opt, "-teams", strlen(opt)) == 0) {
844 dump_team(&info);
845 } else if (strncmp(opt, "-kinfo", strlen(opt)) == 0) {
846 dump_kinfo(&info);
847 } else if (strncmp(opt, "-platform", strlen(opt)) == 0) {
848 dump_platform(&info);
849 } else if (strncmp(opt, "-disable_cpu_sn", strlen(opt)) == 0) {
850 /* TODO: printf("CPU #%d serial number: old state: %s, new state: %s\n", ... ); */
851 fprintf(stderr, "Sorry, not yet implemented\n");
852 } else {
853 const char *name = strrchr(argv[0], '/');
854 if (name == NULL)
855 name = argv[0];
856 else
857 name++;
859 fprintf(stderr, "Usage:\n");
860 fprintf(stderr, " %s [-id|-cpu|-mem|-semaphore|-ports|-threads|-teams|-platform|-disable_cpu_sn|-kinfo]\n", name);
861 return 0;
865 return 0;