vfs: check userland buffers before reading them.
[haiku.git] / src / bin / sysinfo.cpp
blob0d198077cac2ff3e83446d4d2dd5ad536fad3c85
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, "L0 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 {0x63, "Data TLB: 2M/4M-bytes pages, 4-way set associative, 32 entries"},
82 {0x66, "L1 data cache: 8 KB, 4-way set associative, 64 bytes/line, sectored"},
83 {0x67, "L1 data cache: 16 KB, 4-way set associative, 64 bytes/line, sectored"},
84 {0x68, "L1 data cache: 32 KB, 4-way set associative, 64 bytes/line, sectored"},
85 {0x70, "Inst trace cache: 12K µOPs, 8-way set associative"},
86 {0x71, "Inst trace cache: 16K µOPs, 8-way set associative"},
87 {0x72, "Inst trace cache: 32K µOPs, 8-way set associative"},
88 {0x76, "Code TLB: 2M/4M pages, fully, 8 entries"},
89 {0x77, /* IA-64 */ "L1 inst cache: 16 KB, 4-way set associative, 64 bytes/line, sectored"},
90 {0x79, "L2 cache: 128 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
91 {0x7A, "L2 cache: 256 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
92 {0x7B, "L2 cache: 512 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
93 {0x7C, "L2 cache: 1024 KB, 8-way set associative, 64 bytes/line, dual-sectored"},
94 {0x7D, "L2 cache: 2048 KB, 8-way set associative, 64 bytes/line"},
95 {0x7E, /* IA-64 */ "L2 cache: 256 KB, 8-way set associative, 128 bytes/line, sectored"},
96 {0x7F, "L2 cache: 512 KB, 2-way set associative, 64 bytes/line"},
97 {0x81, "L2 cache: 128 KB, 8-way set associative, 32 bytes/line"},
98 {0x82, "L2 cache: 256 KB, 8-way set associative, 32 bytes/line"},
99 {0x83, "L2 cache: 512 KB, 8-way set associative, 32 bytes/line"},
100 {0x84, "L2 cache: 1024 KB, 8-way set associative, 32 bytes/line"},
101 {0x85, "L2 cache: 2048 KB, 8-way set associative, 32 bytes/line"},
102 {0x86, "L2 cache: 512 KB, 4-way set associative, 64 bytes/line"},
103 {0x87, "L2 cache: 1024 KB, 8-way set associative, 64 bytes/line"},
104 {0x88, /* IA-64 */ "L3 cache: 2 MB, 4-way set associative, 64 bytes/line"},
105 {0x89, /* IA-64 */ "L3 cache: 4 MB, 4-way set associative, 64 bytes/line"},
106 {0x8A, /* IA-64 */ "L3 cache: 8 MB, 4-way set associative, 64 bytes/line"},
107 {0x8D, /* IA-64 */ "L3 cache: 3 MB, 12-way set associative, 128 bytes/line"},
108 {0x90, /* IA-64 */ "Inst TLB: 4K-256Mbytes pages, fully associative, 64 entries"},
109 {0x96, /* IA-64 */ "L1 data TLB: 4K-256M bytes pages, fully associative, 32 entries"},
110 {0x9B, /* IA-64 */ "L2 data TLB: 4K-256M bytes pages, fully associative, 96 entries"},
111 // {0x70, "Cyrix specific: Code and data TLB: 4k-bytes pages, 4-way set associative, 32 entries"},
112 // {0x74, "Cyrix specific: ???"},
113 // {0x77, "Cyrix specific: ???"},
114 {0x80, /* Cyrix specific */ "L1 cache: 16 KB, 4-way set associative, 16 bytes/line"},
115 // {0x82, "Cyrix specific: ???"},
116 // {0x84, "Cyrix specific: ???"},
117 {0xB0, "Inst TLB: 4K-bytes pages, 4-way set associative, 128 entries"},
118 {0xB1, "Inst TLB: 2M-bytes pages, 4-way set associative, 8 entries OR 4M, 4-way, 4 entries"},
119 // Intel doesn't give any details how to determine which of the two options is the case
120 // as per Intel Application Note 485, November 2008.
121 {0xB2, "Inst TLB: 4K-bytes pages, 4-way set associative, 64 entries"},
122 {0xB3, "Data TLB: 4K-bytes pages, 4-way set associative, 128 entries"},
123 {0xB4, "Data TLB: 4K-bytes pages, 4-way set associative, 256 entries"},
124 {0xB5, "Code TLB: 4K-bytes pages, 8-way set associative, 64 entries"},
125 {0xB6, "Code TLB: 4K-bytes pages, 8-way set associative, 128 entries"},
126 {0xBA, "Data TLB, 4K-bytes pages, 4-way set associative, 64 entries"},
127 {0xC0, "Data TLB, 4K-4M bytes pages, 4-way set associative, 8 entries"},
128 {0xC3, "Shared 2nd-level TLB: 4K/2M, 6-way set associative, 1536 entries"},
129 {0xCA, "Shared 2nd-level TLB: 4K, 4-way set associative, 512 entries"},
130 {0xD0, "L3 cache: 512 KB, 4-way set associative, 64-bytes/line"},
131 {0xD1, "L3 cache: 1024 KB, 4-way set associative, 64-bytes/line"},
132 {0xD2, "L3 cache: 2048 KB, 4-way set associative, 64-bytes/line"},
133 {0xD6, "L3 cache: 1024 KB, 8-way set associative, 64-bytes/line"},
134 {0xD7, "L3 cache: 2048 KB, 8-way set associative, 64-bytes/line"},
135 {0xD8, "L3 cache: 4096 KB, 8-way set associative, 64-bytes/line"},
136 {0xDC, "L3 cache: 2048 KB, 12-way set associative, 64-bytes/line"},
137 {0xDD, "L3 cache: 4096 KB, 12-way set associative, 64-bytes/line"},
138 {0xDE, "L3 cache: 8192 KB, 12-way set associative, 64-bytes/line"},
139 {0xE2, "L3 cache: 2048 KB, 16-way set associative, 64-bytes/line"},
140 {0xE3, "L3 cache: 4096 KB, 16-way set associative, 64-bytes/line"},
141 {0xE4, "L3 cache: 8192 KB, 16-way set associative, 64-bytes/line"},
142 {0xF0, "64-byte Prefetching"},
143 {0xF1, "128-byte Prefetching"},
144 {0xFF, "TODO: Query standard level 0000_0004h instead"},
145 {0, NULL}
149 /* CPU Features */
150 static const char *kFeatures[32] = {
151 "FPU", "VME", "DE", "PSE",
152 "TSC", "MSR", "PAE", "MCE",
153 "CX8", "APIC", NULL, "SEP",
154 "MTRR", "PGE", "MCA", "CMOV",
155 "PAT", "PSE36", "PSN", "CFLUSH",
156 NULL, "DS", "ACPI", "MMX",
157 "FXSTR", "SSE", "SSE2", "SS",
158 "HTT", "TM", NULL, "PBE",
161 /* CPU Extended features */
162 static const char *kExtendedFeatures[32] = {
163 "SSE3", "PCLMULDQ", "DTES64", "MONITOR", "DS-CPL", "VMX", "SMX", "EST",
164 "TM2", "SSSE3", "CNTXT-ID", NULL, "FMA", "CX16", "xTPR", "PDCM",
165 NULL, "PCID", "DCA", "SSE4.1", "SSE4.2", "x2APIC", "MOVEB", "POPCNT",
166 "TSC-DEADLINE", "AES", "XSAVE", "OSXSAVE", "AVX", "F16C", "RDRND",
167 "HYPERVISOR"
171 /* AMD Extended features leaf 0x80000001 */
172 static const char *kAMDExtFeatures[32] = {
173 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
174 NULL, NULL, NULL, "SCE", NULL, NULL, NULL, NULL,
175 NULL, NULL, NULL, NULL, "NX", NULL, "AMD-MMX", NULL,
176 "FXSR", "FFXSR", NULL, "RDTSCP", NULL, "64", "3DNow+", "3DNow!"
180 /* AMD Extended features leaf 0x80000007 */
181 static const char *kAMDExtFeaturesPower[32] = {
182 "TS", "FID", "VID", "TTP", "TM", "STC", "MUL100", "HWPS",
183 "ITSC", "CPB", "EFRO", "PFI", "PA", NULL, NULL, NULL,
184 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
185 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
189 /* AMD Extended features leaf 0x80000008 */
190 static const char *kAMDExtFeaturesTwo[32] = {
191 "CLZERO", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
192 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
193 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
194 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
198 static void
199 print_intel_cache_descriptors(enum cpu_vendor vendor, uint32 model,
200 cpuid_info *info)
202 uint8 cacheDescriptors[15]; // Max
204 int maxDesc = 0;
205 int i = 0;
207 // put valid values into array
208 if ((info->regs.eax & 0x80000000) == 0) {
209 // eax is valid, include values
210 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
211 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
212 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
213 } else {
214 i += 3;
216 if ((info->regs.ebx & 0x80000000) == 0) {
217 // ebx is valid, include values
218 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
219 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
220 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
221 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
222 } else {
223 i += 4;
225 if ((info->regs.edx & 0x80000000) == 0) {
226 // edx is valid, include values
227 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
228 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
229 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
230 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
231 } else {
232 i += 4;
234 if ((info->regs.ecx & 0x80000000) == 0) {
235 // ecx is valid, include values
236 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
237 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
238 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
239 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++];
242 putchar('\n');
244 for (int i = 0; i < maxDesc; i++) {
245 // ignore NULL descriptors
246 if (cacheDescriptors[i] == 0)
247 continue;
249 int j;
250 for (j = 0; sIntelCacheDescriptions[j].code; j++) {
251 if (cacheDescriptors[i] == sIntelCacheDescriptions[j].code) {
252 if (cacheDescriptors[i] == 0x40) {
253 printf("\tNo integrated L%u cache\n",
254 ((model >> 8) & 0xf) == 0xf
255 && vendor == B_CPU_VENDOR_INTEL ? 3 : 2);
256 } else
257 printf("\t%s\n", sIntelCacheDescriptions[j].description);
258 break;
262 // Reached the end without finding a descriptor
263 if (sIntelCacheDescriptions[j].code == 0)
264 printf("\tUnknown cache descriptor 0x%02x\n", cacheDescriptors[i]);
269 #endif // __INTEL__ || __x86_64__
272 static void
273 print_TLB(uint32 reg, const char *pages)
275 int entries[2];
276 int ways[2];
277 const char *name[2] = { "Inst TLB", "Data TLB" };
279 entries[0] = (reg & 0xff);
280 ways[0] = ((reg >> 8) & 0xff);
281 entries[1] = ((reg >> 16) & 0xff);
282 ways[1] = ((reg >> 24) & 0xff);
284 for (int num = 0; num < 2; num++) {
285 printf("\t%s: %s%s%u entries, ", name[num],
286 pages ? pages : "", pages ? " pages, " : "", entries[num]);
288 if (ways[num] == 0xff)
289 printf("fully associative\n");
290 else
291 printf("%u-way set associative\n", ways[num]);
296 static void
297 print_level2_cache(uint32 reg, const char *name)
299 uint32 size = (reg >> 16) & 0xffff;
300 uint32 ways = (reg >> 12) & 0xf;
301 uint32 linesPerTag = (reg >> 8) & 0xf;
302 // intel does not define this
303 uint32 lineSize = reg & 0xff;
305 printf("\t%s: %" B_PRIu32 " KB, ", name, size);
306 if (ways == 0xf)
307 printf("fully associative, ");
308 else if (ways == 0x1)
309 printf("direct-mapped, ");
310 else
311 printf("%lu-way set associative, ", 1UL << (ways / 2));
312 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
313 lineSize);
317 static void
318 print_level1_cache(uint32 reg, const char *name)
320 uint32 size = (reg >> 24) & 0xff;
321 uint32 ways = (reg >> 16) & 0xff;
322 uint32 linesPerTag = (reg >> 8) & 0xff;
323 uint32 lineSize = reg & 0xff;
325 printf("\t%s: %" B_PRIu32 " KB, ", name, size);
326 if (ways == 0xff)
327 printf("fully associative, ");
328 else
329 printf("%" B_PRIu32 "-way set associative, ", ways);
330 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
331 lineSize);
335 #if defined(__INTEL__) || defined(__x86_64__)
337 static void
338 print_cache_desc(int32 cpu)
340 cpuid_info info;
341 get_cpuid(&info, 0x80000005, cpu);
343 putchar('\n');
345 if (info.regs.eax)
346 print_TLB(info.regs.eax, info.regs.ebx ? "2M/4M-byte" : NULL);
347 if (info.regs.ebx)
348 print_TLB(info.regs.ebx, info.regs.eax ? "4K-byte" : NULL);
350 print_level1_cache(info.regs.ecx, "L1 inst cache");
351 print_level1_cache(info.regs.edx, "L1 data cache");
353 get_cpuid(&info, 0x80000006, cpu);
354 print_level2_cache(info.regs.ecx, "L2 cache");
358 static void
359 print_intel_cache_desc(int32 cpu)
361 cpuid_info info;
363 // A second parameters needs to be passed to CPUID which determines the
364 // cache level to query
365 get_cpuid(&info, 0x00000004, cpu);
367 putchar('\n');
369 uint32 type = info.regs.eax & 0xf;
370 uint32 level = (info.regs.eax & 0x70) >> 4;
371 bool isFullyAssoc = info.regs.eax & 0x100;
373 uint32 lineSize = (info.regs.ebx & 0xfff) + 1;
374 uint32 linesPerTag = ((info.regs.ebx & 0x3ff000) >> 12) + 1;
375 uint32 ways = ((info.regs.ebx & 0xffc00000) >> 22) + 1;
377 uint32 sets = info.regs.ecx;
379 printf("\tL%" B_PRId32 " ",level);
381 switch (type) {
382 case 1: printf("Data cache "); break;
383 case 2: printf("Inst cache "); break;
384 case 3: printf("Unified cache "); break;
385 default: break;
388 if (isFullyAssoc)
389 printf("fully associative, ");
390 else
391 printf("%" B_PRIu32 "-way set associative, ", ways);
392 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag,
393 lineSize);
395 get_cpuid(&info, 0x80000006, cpu);
396 print_level2_cache(sets, "L2 cache");
400 static void
401 print_transmeta_features(uint32 features)
403 if (features & (1 << 16))
404 printf("\t\tFCMOV\n");
407 #endif // __INTEL__ || __x86_64__
410 static void
411 print_features(const char** table, uint32 features)
413 int32 found = 0;
415 for (int32 i = 0; i < 32; i++) {
416 if ((features & (1UL << i)) && table[i] != NULL) {
417 printf("%s%s", found == 0 ? "\t\t" : " ", table[i]);
418 found++;
419 if (found > 0 && (found % 16) == 0) {
420 putchar('\n');
421 found = 0;
426 if (found != 0)
427 putchar('\n');
431 #if defined(__INTEL__) || defined(__x86_64__)
433 static void
434 print_processor_signature(enum cpu_vendor vendor, cpuid_info *info)
436 printf("\tSignature: 0x%1" B_PRIx32 "%1" B_PRIx32 "0%1" B_PRIx32
437 "%1" B_PRIx32 "%1" B_PRIx32 "; ", info->eax_1.extended_family,
438 info->eax_1.extended_model, info->eax_1.family,
439 info->eax_1.model, info->eax_1.stepping);
440 if (vendor == B_CPU_VENDOR_AMD) {
441 printf("Type %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32
442 ", stepping %" B_PRIu32 "\n",
443 info->eax_1.type,
444 info->eax_1.family + (info->eax_1.family == 0xf
445 ? info->eax_1.extended_family : 0),
446 info->eax_1.model + (info->eax_1.model == 0xf
447 ? info->eax_1.extended_model << 4 : 0),
448 info->eax_1.stepping);
449 } else if (vendor == B_CPU_VENDOR_INTEL) {
450 // model calculation is different for INTEL
451 printf("Type %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32
452 ", stepping %" B_PRIu32 "\n",
453 info->eax_1.type,
454 info->eax_1.family + (info->eax_1.family == 0xf
455 ? info->eax_1.extended_family : 0),
456 info->eax_1.model
457 + ((info->eax_1.family == 0xf || info->eax_1.family == 0x6)
458 ? info->eax_1.extended_model << 4 : 0),
459 info->eax_1.stepping);
463 #endif // __INTEL__ || __x86_64__
466 static void
467 dump_platform(system_info *info)
469 cpu_topology_node_info root;
470 uint32 count = 1;
471 get_cpu_topology_info(&root, &count);
473 const char* platform;
474 switch (root.data.root.platform) {
475 case B_CPU_x86:
476 platform = "IntelArchitecture";
477 break;
479 case B_CPU_x86_64:
480 platform = "IntelArchitecture (64 bit)";
481 break;
483 default:
484 platform = "unknown";
485 break;
488 printf("%s\n", platform);
492 #if defined(__INTEL__) || defined(__x86_64__)
494 static void
495 dump_cpu(enum cpu_vendor vendor, uint32 model, int32 cpu)
497 // References:
498 // http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html
499 // http://www.sandpile.org/ia32/cpuid.htm
500 // http://www.sandpile.org/x86/cpuid.htm
501 // http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/TN13.pdf (Duron erratum)
503 cpuid_info baseInfo;
504 if (get_cpuid(&baseInfo, 0, cpu) != B_OK) {
505 // this CPU doesn't support cpuid
506 return;
509 int32 maxStandardFunction = baseInfo.eax_0.max_eax;
510 if (maxStandardFunction >= 500) {
511 // old Pentium sample chips has cpu signature here
512 maxStandardFunction = 0;
515 // Extended cpuid
517 cpuid_info cpuInfo;
518 get_cpuid(&cpuInfo, 0x80000000, cpu);
520 // Extended cpuid is only supported if max_eax is greater than the
521 // service id
522 int32 maxExtendedFunction = 0;
523 if (cpuInfo.eax_0.max_eax > 0x80000000)
524 maxExtendedFunction = cpuInfo.eax_0.max_eax & 0xff;
526 if (maxExtendedFunction >=4 ) {
527 char buffer[49];
528 char *name = buffer;
530 memset(buffer, 0, sizeof(buffer));
532 for (int32 i = 0; i < 3; i++) {
533 cpuid_info nameInfo;
534 get_cpuid(&nameInfo, 0x80000002 + i, cpu);
536 memcpy(name, &nameInfo.regs.eax, 4);
537 memcpy(name + 4, &nameInfo.regs.ebx, 4);
538 memcpy(name + 8, &nameInfo.regs.ecx, 4);
539 memcpy(name + 12, &nameInfo.regs.edx, 4);
540 name += 16;
543 // cut off leading spaces (names are right aligned)
544 name = buffer;
545 while (name[0] == ' ')
546 name++;
548 // the BIOS may not have set the processor name
549 if (name[0])
550 printf("CPU #%" B_PRId32 ": \"%s\"\n", cpu, name);
551 else {
552 // Intel CPUs don't seem to have the genuine vendor field
553 printf("CPU #%" B_PRId32 ": %.12s\n", cpu,
554 vendor == B_CPU_VENDOR_INTEL ?
555 baseInfo.eax_0.vendor_id : cpuInfo.eax_0.vendor_id);
557 } else {
558 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, baseInfo.eax_0.vendor_id);
559 if (maxStandardFunction == 0)
560 return;
563 get_cpuid(&cpuInfo, 1, cpu);
564 print_processor_signature(vendor, &cpuInfo);
565 printf("\tFeatures: 0x%08" B_PRIx32 "\n", cpuInfo.eax_1.features);
566 print_features(kFeatures, cpuInfo.eax_1.features);
568 if (maxStandardFunction >= 1) {
569 /* Extended features */
570 printf("\tExtended Features (0x00000001): 0x%08" B_PRIx32 "\n",
571 cpuInfo.eax_1.extended_features);
572 print_features(kExtendedFeatures, cpuInfo.eax_1.extended_features);
575 /* Extended CPUID Information */
576 if (maxExtendedFunction >= 1) {
577 get_cpuid(&cpuInfo, 0x80000001, cpu);
578 if (vendor == B_CPU_VENDOR_INTEL || vendor == B_CPU_VENDOR_AMD) {
579 // 0x80000001 EDX has overlap of 64,ED,SY/SE between amd and intel
580 printf("\tExtended Features (0x80000001): 0x%08" B_PRIx32 "\n",
581 cpuInfo.eax_1.features);
582 print_features(kAMDExtFeatures, cpuInfo.regs.edx);
585 if (vendor == B_CPU_VENDOR_AMD) {
586 if (maxExtendedFunction >= 7) {
587 get_cpuid(&cpuInfo, 0x80000007, cpu);
588 printf("\tExtended Features (0x80000007): 0x%08" B_PRIx32 "\n",
589 cpuInfo.regs.edx);
590 print_features(kAMDExtFeaturesPower, cpuInfo.regs.edx);
592 if (maxExtendedFunction >= 8) {
593 get_cpuid(&cpuInfo, 0x80000008, cpu);
594 printf("\tExtended Features (0x80000008): 0x%08" B_PRIx32 "\n",
595 cpuInfo.regs.ebx);
596 print_features(kAMDExtFeaturesTwo, cpuInfo.regs.ebx);
598 } else if (vendor == B_CPU_VENDOR_TRANSMETA)
599 print_transmeta_features(cpuInfo.regs.edx);
602 /* Cache/TLB descriptors */
603 if (maxExtendedFunction >= 5) {
604 if (!strncmp(baseInfo.eax_0.vendor_id, "CyrixInstead", 12)) {
605 get_cpuid(&cpuInfo, 0x00000002, cpu);
606 print_intel_cache_descriptors(vendor, model, &cpuInfo);
607 } else if (vendor == B_CPU_VENDOR_INTEL) {
608 // Intel does not support extended function 5 (but it does 6 hmm)
609 print_intel_cache_desc(cpu);
610 } else {
611 print_cache_desc(cpu);
615 if (maxStandardFunction >= 2) {
616 do {
617 get_cpuid(&cpuInfo, 2, cpu);
619 if (cpuInfo.eax_2.call_num > 0)
620 print_intel_cache_descriptors(vendor, model, &cpuInfo);
621 } while (cpuInfo.eax_2.call_num > 1);
624 /* Serial number */
625 if (maxStandardFunction >= 3) {
626 cpuid_info flagsInfo;
627 get_cpuid(&flagsInfo, 1, cpu);
629 if (flagsInfo.eax_1.features & (1UL << 18)) {
630 get_cpuid(&cpuInfo, 3, cpu);
631 printf("Serial number: %04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32
632 "-%04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 "\n",
633 flagsInfo.eax_1.features >> 16,
634 flagsInfo.eax_1.features & 0xffff,
635 cpuInfo.regs.edx >> 16, cpuInfo.regs.edx & 0xffff,
636 cpuInfo.regs.ecx >> 16, cpuInfo.regs.edx & 0xffff);
640 putchar('\n');
643 #endif // __INTEL__ || __x86_64__
646 static void
647 dump_cpus(system_info *info)
649 uint32 topologyNodeCount = 0;
650 cpu_topology_node_info* topology = NULL;
651 get_cpu_topology_info(NULL, &topologyNodeCount);
652 if (topologyNodeCount != 0)
653 topology = new cpu_topology_node_info[topologyNodeCount];
654 get_cpu_topology_info(topology, &topologyNodeCount);
656 enum cpu_platform platform = B_CPU_UNKNOWN;
657 enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
658 uint32 cpuModel = 0;
659 uint64 frequency = 0;
660 for (uint32 i = 0; i < topologyNodeCount; i++) {
661 switch (topology[i].type) {
662 case B_TOPOLOGY_ROOT:
663 platform = topology[i].data.root.platform;
664 break;
666 case B_TOPOLOGY_PACKAGE:
667 cpuVendor = topology[i].data.package.vendor;
668 break;
670 case B_TOPOLOGY_CORE:
671 cpuModel = topology[i].data.core.model;
672 frequency = topology[i].data.core.default_frequency;
673 break;
675 default:
676 break;
679 delete[] topology;
681 const char *vendor = get_cpu_vendor_string(cpuVendor);
682 const char *model = get_cpu_model_string(platform, cpuVendor, cpuModel);
683 char modelString[32];
685 if (model == NULL && vendor == NULL)
686 model = "(Unknown)";
687 else if (model == NULL) {
688 model = modelString;
689 snprintf(modelString, 32, "(Unknown %" B_PRIx32 ")", cpuModel);
692 printf("%" B_PRId32 " %s%s%s, revision %04" B_PRIx32 " running at %"
693 B_PRIu64 "MHz\n\n",
694 info->cpu_count,
695 vendor ? vendor : "", vendor ? " " : "", model,
696 cpuModel,
697 frequency / 1000000);
699 #if defined(__INTEL__) || defined(__x86_64__)
700 for (uint32 cpu = 0; cpu < info->cpu_count; cpu++)
701 dump_cpu(cpuVendor, cpuModel, cpu);
702 #endif // __INTEL__ || __x86_64__
706 static void
707 dump_mem(system_info *info)
709 printf("%10" B_PRIu64 " bytes free (used/max %10" B_PRIu64 " / %10"
710 B_PRIu64 ")\n",
711 B_PAGE_SIZE * (uint64)(info->max_pages - info->used_pages),
712 B_PAGE_SIZE * (uint64)info->used_pages,
713 B_PAGE_SIZE * (uint64)info->max_pages);
714 printf(" (cached %10" B_PRIu64 ")\n",
715 B_PAGE_SIZE * (uint64)info->cached_pages);
719 static void
720 dump_sem(system_info *info)
722 printf("%10" B_PRId32 " semaphores free (used/max %10" B_PRId32 " / %10"
723 B_PRId32 ")\n",
724 info->max_sems - info->used_sems,
725 info->used_sems, info->max_sems);
729 static void
730 dump_ports(system_info *info)
732 printf("%10" B_PRId32 " ports free (used/max %10" B_PRId32 " / %10"
733 B_PRId32 ")\n",
734 info->max_ports - info->used_ports,
735 info->used_ports, info->max_ports);
739 static void
740 dump_thread(system_info *info)
742 printf("%10" B_PRId32 " threads free (used/max %10" B_PRId32 " / %10"
743 B_PRId32 ")\n",
744 info->max_threads - info->used_threads,
745 info->used_threads, info->max_threads);
749 static void
750 dump_team(system_info *info)
752 printf("%10" B_PRId32 " teams free (used/max %10" B_PRId32 " / %10"
753 B_PRId32 ")\n",
754 info->max_teams - info->used_teams,
755 info->used_teams, info->max_teams);
759 static void
760 dump_kinfo(system_info *info)
762 printf("Kernel name: %s built on: %s %s version 0x%" B_PRIx64 "\n",
763 info->kernel_name,
764 info->kernel_build_date, info->kernel_build_time,
765 info->kernel_version );
769 static void
770 dump_system_info(system_info *info)
772 dump_kinfo(info);
773 dump_cpus(info);
774 dump_mem(info);
775 dump_sem(info);
776 dump_ports(info);
777 dump_thread(info);
778 dump_team(info);
783 main(int argc, char *argv[])
785 if (!is_computer_on()) {
786 printf("The computer is not on! No info available\n");
787 exit(EXIT_FAILURE);
790 system_info info;
791 if (get_system_info(&info) != B_OK) {
792 printf("Error getting system information!\n");
793 return 1;
796 if (argc <= 1) {
797 dump_system_info(&info);
798 } else {
799 for (int i = 1; i < argc; i++) {
800 const char *opt = argv[i];
801 if (strncmp(opt, "-id", strlen(opt)) == 0) {
802 /* note: the original also assumes this option on "sysinfo -" */
803 printf("%#.8x %#.8x\n", 0,0);
804 } else if (strncmp(opt, "-cpu", strlen(opt)) == 0) {
805 dump_cpus(&info);
806 } else if (strncmp(opt, "-mem", strlen(opt)) == 0) {
807 dump_mem(&info);
808 } else if (strncmp(opt, "-semaphores", strlen(opt)) == 0) {
809 dump_sem(&info);
810 } else if (strncmp(opt, "-ports", strlen(opt)) == 0) {
811 dump_ports(&info);
812 } else if (strncmp(opt, "-threads", strlen(opt)) == 0) {
813 dump_thread(&info);
814 } else if (strncmp(opt, "-teams", strlen(opt)) == 0) {
815 dump_team(&info);
816 } else if (strncmp(opt, "-kinfo", strlen(opt)) == 0) {
817 dump_kinfo(&info);
818 } else if (strncmp(opt, "-platform", strlen(opt)) == 0) {
819 dump_platform(&info);
820 } else if (strncmp(opt, "-disable_cpu_sn", strlen(opt)) == 0) {
821 /* TODO: printf("CPU #%d serial number: old state: %s, new state: %s\n", ... ); */
822 fprintf(stderr, "Sorry, not yet implemented\n");
823 } else {
824 const char *name = strrchr(argv[0], '/');
825 if (name == NULL)
826 name = argv[0];
827 else
828 name++;
830 fprintf(stderr, "Usage:\n");
831 fprintf(stderr, " %s [-id|-cpu|-mem|-semaphore|-ports|-threads|-teams|-platform|-disable_cpu_sn|-kinfo]\n", name);
832 return 0;
836 return 0;