1 /* 2 * Copyright 2004-2012, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2002, Carlos Hasan. 4 * 5 * Distributed under the terms of the MIT license. 6 */ 7 8 9 #include <OS.h> 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <cpu_type.h> 16 17 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__) 21 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} 140 }; 141 142 143 static void 144 print_intel_cache_descriptors(enum cpu_types type, cpuid_info *info) 145 { 146 uint8 cacheDescriptors[15]; // Max 147 148 int maxDesc = 0; 149 int i = 0; 150 151 // put valid values into array 152 if ((info->regs.eax & 0x80000000) == 0) { 153 // eax is valid, include values 154 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 155 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 156 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 157 } else { 158 i += 3; 159 } 160 if ((info->regs.ebx & 0x80000000) == 0) { 161 // ebx is valid, include values 162 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 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 } else { 167 i += 4; 168 } 169 if ((info->regs.edx & 0x80000000) == 0) { 170 // edx is valid, include values 171 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 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 } else { 176 i += 4; 177 } 178 if ((info->regs.ecx & 0x80000000) == 0) { 179 // ecx is valid, include values 180 cacheDescriptors[maxDesc++] = info->eax_2.cache_descriptors[i++]; 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 } 185 186 putchar('\n'); 187 188 for (int i = 0; i < maxDesc; i++) { 189 // ignore NULL descriptors 190 if (cacheDescriptors[i] == 0) 191 continue; 192 193 int j; 194 for (j = 0; sIntelCacheDescriptions[j].code; j++) { 195 if (cacheDescriptors[i] == sIntelCacheDescriptions[j].code) { 196 if (cacheDescriptors[i] == 0x40) { 197 printf("\tNo integrated L%u cache\n", 198 type >= B_CPU_INTEL_PENTIUM_IV 199 && (type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86 200 ? 3 : 2); 201 } else 202 printf("\t%s\n", sIntelCacheDescriptions[j].description); 203 break; 204 } 205 } 206 207 // Reached the end without finding a descriptor 208 if (sIntelCacheDescriptions[j].code == 0) 209 printf("\tUnknown cache descriptor 0x%02x\n", cacheDescriptors[i]); 210 } 211 } 212 213 #endif // __INTEL__ || __x86_64__ 214 215 216 static void 217 print_TLB(uint32 reg, const char *pages) 218 { 219 int entries[2]; 220 int ways[2]; 221 const char *name[2] = { "Inst TLB", "Data TLB" }; 222 223 entries[0] = (reg & 0xff); 224 ways[0] = ((reg >> 8) & 0xff); 225 entries[1] = ((reg >> 16) & 0xff); 226 ways[1] = ((reg >> 24) & 0xff); 227 228 for (int num = 0; num < 2; num++) { 229 printf("\t%s: %s%s%u entries, ", name[num], 230 pages ? pages : "", pages ? " pages, " : "", entries[num]); 231 232 if (ways[num] == 0xff) 233 printf("fully associative\n"); 234 else 235 printf("%u-way set associative\n", ways[num]); 236 } 237 } 238 239 240 static void 241 print_level2_cache(uint32 reg, const char *name) 242 { 243 uint32 size = (reg >> 16) & 0xffff; 244 uint32 ways = (reg >> 12) & 0xf; 245 uint32 linesPerTag = (reg >> 8) & 0xf; 246 // intel does not define this 247 uint32 lineSize = reg & 0xff; 248 249 printf("\t%s: %" B_PRIu32 " KB, ", name, size); 250 if (ways == 0xf) 251 printf("fully associative, "); 252 else if (ways == 0x1) 253 printf("direct-mapped, "); 254 else 255 printf("%lu-way set associative, ", 1UL << (ways / 2)); 256 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag, 257 lineSize); 258 } 259 260 261 static void 262 print_level1_cache(uint32 reg, const char *name) 263 { 264 uint32 size = (reg >> 24) & 0xff; 265 uint32 ways = (reg >> 16) & 0xff; 266 uint32 linesPerTag = (reg >> 8) & 0xff; 267 uint32 lineSize = reg & 0xff; 268 269 printf("\t%s: %" B_PRIu32 " KB, ", name, size); 270 if (ways == 0xff) 271 printf("fully associative, "); 272 else 273 printf("%" B_PRIu32 "-way set associative, ", ways); 274 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag, 275 lineSize); 276 } 277 278 279 #if defined(__INTEL__) || defined(__x86_64__) 280 281 static void 282 print_cache_desc(int32 cpu) 283 { 284 cpuid_info info; 285 get_cpuid(&info, 0x80000005, cpu); 286 287 putchar('\n'); 288 289 if (info.regs.eax) 290 print_TLB(info.regs.eax, info.regs.ebx ? "2M/4M-byte" : NULL); 291 if (info.regs.ebx) 292 print_TLB(info.regs.ebx, info.regs.eax ? "4K-byte" : NULL); 293 294 print_level1_cache(info.regs.ecx, "L1 inst cache"); 295 print_level1_cache(info.regs.edx, "L1 data cache"); 296 297 get_cpuid(&info, 0x80000006, cpu); 298 print_level2_cache(info.regs.ecx, "L2 cache"); 299 } 300 301 302 static void 303 print_intel_cache_desc(int32 cpu) 304 { 305 cpuid_info info; 306 307 // A second parameters needs to be passed to CPUID which determines the 308 // cache level to query 309 get_cpuid(&info, 0x00000004, cpu); 310 311 putchar('\n'); 312 313 uint32 type = info.regs.eax & 0xf; 314 uint32 level = (info.regs.eax & 0x70) >> 4; 315 bool isFullyAssoc = info.regs.eax & 0x100; 316 317 uint32 lineSize = (info.regs.ebx & 0xfff) + 1; 318 uint32 linesPerTag = ((info.regs.ebx & 0x3ff000) >> 12) + 1; 319 uint32 ways = ((info.regs.ebx & 0xffc00000) >> 22) + 1; 320 321 uint32 sets = info.regs.ecx; 322 323 printf("\tL%" B_PRId32 " ",level); 324 325 switch (type) { 326 case 1: printf("Data cache "); break; 327 case 2: printf("Inst cache "); break; 328 case 3: printf("Unified cache "); break; 329 default: break; 330 } 331 332 if (isFullyAssoc) 333 printf("fully associative, "); 334 else 335 printf("%" B_PRIu32 "-way set associative, ", ways); 336 printf("%" B_PRIu32 " lines/tag, %" B_PRIu32 " bytes/line\n", linesPerTag, 337 lineSize); 338 339 get_cpuid(&info, 0x80000006, cpu); 340 print_level2_cache(sets, "L2 cache"); 341 } 342 343 344 static void 345 print_transmeta_features(uint32 features) 346 { 347 if (features & (1 << 16)) 348 printf("\t\tFCMOV\n"); 349 } 350 351 #endif // __INTEL__ || __x86_64__ 352 353 354 static void 355 print_amd_power_management_features(uint32 features) 356 { 357 static const char *kFeatures[6] = { 358 "TS", "FID", "VID", "TTP", "TM", "STC", 359 }; 360 int32 found = 4; 361 362 printf("\tPower Management Features:"); 363 364 for (int32 i = 0; i < 6; i++) { 365 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 366 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 367 found++; 368 if (found > 0 && (found % 16) == 0) { 369 putchar('\n'); 370 found = 0; 371 } 372 } 373 } 374 375 if (found != 0) 376 putchar('\n'); 377 } 378 379 380 static void 381 print_amd_features(uint32 features) 382 { 383 static const char *kFeatures[32] = { 384 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 385 NULL, NULL, NULL, "SCE", NULL, NULL, NULL, NULL, 386 NULL, NULL, NULL, NULL, "NX", NULL, "AMD-MMX", NULL, 387 NULL, "FFXSTR", NULL, "RDTSCP", NULL, "64", "3DNow+", "3DNow!" 388 }; 389 int32 found = 0; 390 391 for (int32 i = 0; i < 32; i++) { 392 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 393 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 394 found++; 395 if (found > 0 && (found % 16) == 0) { 396 putchar('\n'); 397 found = 0; 398 } 399 } 400 } 401 402 if (found != 0) 403 putchar('\n'); 404 } 405 406 407 static void 408 print_extended_features(uint32 features) 409 { 410 static const char *kFeatures[32] = { 411 "SSE3", "PCLMULDQ", "DTES64", "MONITOR", "DS-CPL", "VMX", "SMX", "EST", 412 "TM2", "SSSE3", "CNTXT-ID", NULL, "FMA", "CX16", "xTPR", "PDCM", 413 NULL, "PCID", "DCA", "SSE4.1", "SSE4.2", "x2APIC", "MOVEB", "POPCNT", 414 "TSC-DEADLINE", "AES", "XSAVE", "OSXSAVE", "AVX", "F16C", "RDRND", 415 "HYPERVISOR" 416 }; 417 int32 found = 0; 418 419 for (int32 i = 0; i < 32; i++) { 420 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 421 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 422 found++; 423 if (found > 0 && (found % 16) == 0) { 424 putchar('\n'); 425 found = 0; 426 } 427 } 428 } 429 430 if (found != 0) 431 putchar('\n'); 432 } 433 434 435 static void 436 print_features(uint32 features) 437 { 438 static const char *kFeatures[32] = { 439 "FPU", "VME", "DE", "PSE", 440 "TSC", "MSR", "PAE", "MCE", 441 "CX8", "APIC", NULL, "SEP", 442 "MTRR", "PGE", "MCA", "CMOV", 443 "PAT", "PSE36", "PSN", "CFLUSH", 444 NULL, "DS", "ACPI", "MMX", 445 "FXSTR", "SSE", "SSE2", "SS", 446 "HTT", "TM", NULL, "PBE", 447 }; 448 int32 found = 0; 449 450 for (int32 i = 0; i < 32; i++) { 451 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 452 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 453 found++; 454 if (found > 0 && (found % 16) == 0) { 455 putchar('\n'); 456 found = 0; 457 } 458 } 459 } 460 461 if (found != 0) 462 putchar('\n'); 463 } 464 465 466 #if defined(__INTEL__) || defined(__x86_64__) 467 468 static void 469 print_processor_signature(system_info *sys_info, cpuid_info *info, 470 const char *prefix) 471 { 472 473 if ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86) { 474 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 ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) 486 == B_CPU_INTEL_x86) { 487 // model calculation is different for INTEL 488 printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32 489 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n", 490 prefix ? prefix : "", prefix && prefix[0] ? "t" : "T", 491 info->eax_1.type, 492 info->eax_1.family + (info->eax_1.family == 0xf 493 ? info->eax_1.extended_family : 0), 494 info->eax_1.model 495 + ((info->eax_1.family == 0xf || info->eax_1.family == 0x6) 496 ? info->eax_1.extended_model << 4 : 0), 497 info->eax_1.stepping, 498 info->eax_1.features); 499 } 500 } 501 502 #endif // __INTEL__ || __x86_64__ 503 504 505 static void 506 dump_platform(system_info *info) 507 { 508 printf("%s\n", 509 info->platform_type == B_AT_CLONE_PLATFORM ? "IntelArchitecture" : 510 info->platform_type == B_MAC_PLATFORM ? "Macintosh" : 511 info->platform_type == B_BEBOX_PLATFORM ? "BeBox" : "unknown"); 512 } 513 514 515 #if defined(__INTEL__) || defined(__x86_64__) 516 517 static void 518 dump_cpu(system_info *info, int32 cpu) 519 { 520 // References: 521 // http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html 522 // http://www.sandpile.org/ia32/cpuid.htm 523 // http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/TN13.pdf (Duron erratum) 524 525 cpuid_info baseInfo; 526 if (get_cpuid(&baseInfo, 0, cpu) != B_OK) { 527 // this CPU doesn't support cpuid 528 return; 529 } 530 531 int32 maxStandardFunction = baseInfo.eax_0.max_eax; 532 if (maxStandardFunction >= 500) { 533 // old Pentium sample chips has cpu signature here 534 maxStandardFunction = 0; 535 } 536 537 // Extended cpuid 538 539 cpuid_info cpuInfo; 540 get_cpuid(&cpuInfo, 0x80000000, cpu); 541 542 // Extended cpuid is only supported if max_eax is greater than the 543 // service id 544 int32 maxExtendedFunction = 0; 545 if (cpuInfo.eax_0.max_eax > 0x80000000) 546 maxExtendedFunction = cpuInfo.eax_0.max_eax & 0xff; 547 548 if (maxExtendedFunction >=4 ) { 549 char buffer[49]; 550 char *name = buffer; 551 552 memset(buffer, 0, sizeof(buffer)); 553 554 for (int32 i = 0; i < 3; i++) { 555 cpuid_info nameInfo; 556 get_cpuid(&nameInfo, 0x80000002 + i, cpu); 557 558 memcpy(name, &nameInfo.regs.eax, 4); 559 memcpy(name + 4, &nameInfo.regs.ebx, 4); 560 memcpy(name + 8, &nameInfo.regs.ecx, 4); 561 memcpy(name + 12, &nameInfo.regs.edx, 4); 562 name += 16; 563 } 564 565 // cut off leading spaces (names are right aligned) 566 name = buffer; 567 while (name[0] == ' ') 568 name++; 569 570 // the BIOS may not have set the processor name 571 if (name[0]) 572 printf("CPU #%" B_PRId32 ": \"%s\"\n", cpu, name); 573 else { 574 // Intel CPUs don't seem to have the genuine vendor field 575 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, 576 (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86 ? 577 baseInfo.eax_0.vendor_id : cpuInfo.eax_0.vendor_id); 578 } 579 } else { 580 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, baseInfo.eax_0.vendor_id); 581 if (maxStandardFunction == 0) 582 return; 583 } 584 585 get_cpuid(&cpuInfo, 1, cpu); 586 print_processor_signature(info, &cpuInfo, NULL); 587 print_features(cpuInfo.eax_1.features); 588 589 if (maxStandardFunction >= 1) { 590 /* Extended features */ 591 printf("\tExtended Intel: 0x%08" B_PRIx32 "\n", cpuInfo.eax_1.extended_features); 592 print_extended_features(cpuInfo.eax_1.extended_features); 593 } 594 595 /* Extended CPUID */ 596 if (maxExtendedFunction >= 1) { 597 get_cpuid(&cpuInfo, 0x80000001, cpu); 598 print_processor_signature(info, &cpuInfo, "Extended AMD: "); 599 600 if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86 601 || (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86) { 602 print_amd_features(cpuInfo.regs.edx); 603 if (maxExtendedFunction >= 7) { 604 get_cpuid(&cpuInfo, 0x80000007, cpu); 605 print_amd_power_management_features(cpuInfo.regs.edx); 606 } 607 } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) 608 == B_CPU_TRANSMETA_x86) 609 print_transmeta_features(cpuInfo.regs.edx); 610 } 611 612 /* Cache/TLB descriptors */ 613 if (maxExtendedFunction >= 5) { 614 if (!strncmp(baseInfo.eax_0.vendor_id, "CyrixInstead", 12)) { 615 get_cpuid(&cpuInfo, 0x00000002, cpu); 616 print_intel_cache_descriptors(info->cpu_type, &cpuInfo); 617 } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) 618 == B_CPU_INTEL_x86) { 619 // Intel does not support extended function 5 (but it does 6 hmm) 620 print_intel_cache_desc(cpu); 621 } else { 622 print_cache_desc(cpu); 623 } 624 } 625 626 if (maxStandardFunction >= 2) { 627 do { 628 get_cpuid(&cpuInfo, 2, cpu); 629 630 if (cpuInfo.eax_2.call_num > 0) 631 print_intel_cache_descriptors(info->cpu_type, &cpuInfo); 632 } while (cpuInfo.eax_2.call_num > 1); 633 } 634 635 /* Serial number */ 636 if (maxStandardFunction >= 3) { 637 cpuid_info flagsInfo; 638 get_cpuid(&flagsInfo, 1, cpu); 639 640 if (flagsInfo.eax_1.features & (1UL << 18)) { 641 get_cpuid(&cpuInfo, 3, cpu); 642 printf("Serial number: %04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 643 "-%04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 "\n", 644 flagsInfo.eax_1.features >> 16, 645 flagsInfo.eax_1.features & 0xffff, 646 cpuInfo.regs.edx >> 16, cpuInfo.regs.edx & 0xffff, 647 cpuInfo.regs.ecx >> 16, cpuInfo.regs.edx & 0xffff); 648 } 649 } 650 651 putchar('\n'); 652 } 653 654 #endif // __INTEL__ || __x86_64__ 655 656 657 static void 658 dump_cpus(system_info *info) 659 { 660 const char *vendor = get_cpu_vendor_string(info->cpu_type); 661 const char *model = get_cpu_model_string(info); 662 char modelString[32]; 663 664 if (model == NULL && vendor == NULL) 665 model = "(Unknown)"; 666 else if (model == NULL) { 667 model = modelString; 668 snprintf(modelString, 32, "(Unknown %x)", info->cpu_type); 669 } 670 671 printf("%" B_PRId32 " %s%s%s, revision %04" B_PRIx32 " running at %" 672 B_PRId64 "MHz (ID: 0x%08" B_PRIx32 " 0x%08" B_PRIx32 ")\n\n", 673 info->cpu_count, 674 vendor ? vendor : "", vendor ? " " : "", model, 675 info->cpu_revision, 676 info->cpu_clock_speed / 1000000, 677 info->id[0], info->id[1]); 678 679 #if defined(__INTEL__) || defined(__x86_64__) 680 for (int32 cpu = 0; cpu < info->cpu_count; cpu++) 681 dump_cpu(info, cpu); 682 #endif // __INTEL__ || __x86_64__ 683 } 684 685 686 static void 687 dump_mem(system_info *info) 688 { 689 printf("%10" B_PRIu64 " bytes free (used/max %10" B_PRIu64 " / %10" 690 B_PRIu64 ")\n", 691 B_PAGE_SIZE * (uint64)(info->max_pages - info->used_pages), 692 B_PAGE_SIZE * (uint64)info->used_pages, 693 B_PAGE_SIZE * (uint64)info->max_pages); 694 printf(" (cached %10" B_PRIu64 ")\n", 695 B_PAGE_SIZE * (uint64)info->cached_pages); 696 } 697 698 699 static void 700 dump_sem(system_info *info) 701 { 702 printf("%10" B_PRId32 " semaphores free (used/max %10" B_PRId32 " / %10" 703 B_PRId32 ")\n", 704 info->max_sems - info->used_sems, 705 info->used_sems, info->max_sems); 706 } 707 708 709 static void 710 dump_ports(system_info *info) 711 { 712 printf("%10" B_PRId32 " ports free (used/max %10" B_PRId32 " / %10" 713 B_PRId32 ")\n", 714 info->max_ports - info->used_ports, 715 info->used_ports, info->max_ports); 716 } 717 718 719 static void 720 dump_thread(system_info *info) 721 { 722 printf("%10" B_PRId32 " threads free (used/max %10" B_PRId32 " / %10" 723 B_PRId32 ")\n", 724 info->max_threads - info->used_threads, 725 info->used_threads, info->max_threads); 726 } 727 728 729 static void 730 dump_team(system_info *info) 731 { 732 printf("%10" B_PRId32 " teams free (used/max %10" B_PRId32 " / %10" 733 B_PRId32 ")\n", 734 info->max_teams - info->used_teams, 735 info->used_teams, info->max_teams); 736 } 737 738 739 static void 740 dump_kinfo(system_info *info) 741 { 742 printf("Kernel name: %s built on: %s %s version 0x%" B_PRIx64 "\n", 743 info->kernel_name, 744 info->kernel_build_date, info->kernel_build_time, 745 info->kernel_version ); 746 } 747 748 749 static void 750 dump_system_info(system_info *info) 751 { 752 dump_kinfo(info); 753 dump_cpus(info); 754 dump_mem(info); 755 dump_sem(info); 756 dump_ports(info); 757 dump_thread(info); 758 dump_team(info); 759 } 760 761 762 int 763 main(int argc, char *argv[]) 764 { 765 if (!is_computer_on()) { 766 printf("The computer is not on! No info available\n"); 767 exit(EXIT_FAILURE); 768 } 769 770 system_info info; 771 if (get_system_info(&info) != B_OK) { 772 printf("Error getting system information!\n"); 773 return 1; 774 } 775 776 if (argc <= 1) { 777 dump_system_info(&info); 778 } else { 779 for (int i = 1; i < argc; i++) { 780 const char *opt = argv[i]; 781 if (strncmp(opt, "-id", strlen(opt)) == 0) { 782 /* note: the original also assumes this option on "sysinfo -" */ 783 printf("0x%.8" B_PRIx32 " 0x%.8" B_PRIx32 "\n", info.id[0], 784 info.id[1]); 785 } else if (strncmp(opt, "-cpu", strlen(opt)) == 0) { 786 dump_cpus(&info); 787 } else if (strncmp(opt, "-mem", strlen(opt)) == 0) { 788 dump_mem(&info); 789 } else if (strncmp(opt, "-semaphores", strlen(opt)) == 0) { 790 dump_sem(&info); 791 } else if (strncmp(opt, "-ports", strlen(opt)) == 0) { 792 dump_ports(&info); 793 } else if (strncmp(opt, "-threads", strlen(opt)) == 0) { 794 dump_thread(&info); 795 } else if (strncmp(opt, "-teams", strlen(opt)) == 0) { 796 dump_team(&info); 797 } else if (strncmp(opt, "-kinfo", strlen(opt)) == 0) { 798 dump_kinfo(&info); 799 } else if (strncmp(opt, "-platform", strlen(opt)) == 0) { 800 dump_platform(&info); 801 } else if (strncmp(opt, "-disable_cpu_sn", strlen(opt)) == 0) { 802 /* TODO: printf("CPU #%d serial number: old state: %s, new state: %s\n", ... ); */ 803 fprintf(stderr, "Sorry, not yet implemented\n"); 804 } else { 805 const char *name = strrchr(argv[0], '/'); 806 if (name == NULL) 807 name = argv[0]; 808 else 809 name++; 810 811 fprintf(stderr, "Usage:\n"); 812 fprintf(stderr, " %s [-id|-cpu|-mem|-semaphore|-ports|-threads|-teams|-platform|-disable_cpu_sn|-kinfo]\n", name); 813 return 0; 814 } 815 } 816 } 817 return 0; 818 } 819