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, NULL, "CX16", "xTPR", "PDCM", 413 NULL, NULL, "DCA", "SSE4.1", "SSE4.2", "x2APIC", "MOVEB", "POPCNT", 414 NULL, "AES", "XSAVE", "OSXSAVE", NULL, NULL, NULL, NULL 415 }; 416 int32 found = 0; 417 418 for (int32 i = 0; i < 32; i++) { 419 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 420 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 421 found++; 422 if (found > 0 && (found % 16) == 0) { 423 putchar('\n'); 424 found = 0; 425 } 426 } 427 } 428 429 if (found != 0) 430 putchar('\n'); 431 } 432 433 434 static void 435 print_features(uint32 features) 436 { 437 static const char *kFeatures[32] = { 438 "FPU", "VME", "DE", "PSE", 439 "TSC", "MSR", "PAE", "MCE", 440 "CX8", "APIC", NULL, "SEP", 441 "MTRR", "PGE", "MCA", "CMOV", 442 "PAT", "PSE36", "PSN", "CFLUSH", 443 NULL, "DS", "ACPI", "MMX", 444 "FXSTR", "SSE", "SSE2", "SS", 445 "HTT", "TM", NULL, "PBE", 446 }; 447 int32 found = 0; 448 449 for (int32 i = 0; i < 32; i++) { 450 if ((features & (1UL << i)) && kFeatures[i] != NULL) { 451 printf("%s%s", found == 0 ? "\t\t" : " ", kFeatures[i]); 452 found++; 453 if (found > 0 && (found % 16) == 0) { 454 putchar('\n'); 455 found = 0; 456 } 457 } 458 } 459 460 if (found != 0) 461 putchar('\n'); 462 } 463 464 465 #if defined(__INTEL__) || defined(__x86_64__) 466 467 static void 468 print_processor_signature(system_info *sys_info, cpuid_info *info, 469 const char *prefix) 470 { 471 472 if ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86) { 473 474 printf("\t%s%sype %" B_PRIu32 ", family %" B_PRIu32 ", model %" B_PRIu32 475 ", stepping %" B_PRIu32 ", features 0x%08" B_PRIx32 "\n", 476 prefix ? prefix : "", prefix && prefix[0] ? "t" : "T", 477 info->eax_1.type, 478 info->eax_1.family + (info->eax_1.family == 0xf 479 ? info->eax_1.extended_family : 0), 480 info->eax_1.model + (info->eax_1.model == 0xf 481 ? info->eax_1.extended_model << 4 : 0), 482 info->eax_1.stepping, 483 info->eax_1.features); 484 } else if ((sys_info->cpu_type & B_CPU_x86_VENDOR_MASK) 485 == B_CPU_INTEL_x86) { 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); 498 } 499 } 500 501 #endif // __INTEL__ || __x86_64__ 502 503 504 static void 505 dump_platform(system_info *info) 506 { 507 printf("%s\n", 508 info->platform_type == B_AT_CLONE_PLATFORM ? "IntelArchitecture" : 509 info->platform_type == B_MAC_PLATFORM ? "Macintosh" : 510 info->platform_type == B_BEBOX_PLATFORM ? "BeBox" : "unknown"); 511 } 512 513 514 #if defined(__INTEL__) || defined(__x86_64__) 515 516 static void 517 dump_cpu(system_info *info, int32 cpu) 518 { 519 // References: 520 // http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html 521 // http://www.sandpile.org/ia32/cpuid.htm 522 // http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/TN13.pdf (Duron erratum) 523 524 cpuid_info baseInfo; 525 if (get_cpuid(&baseInfo, 0, cpu) != B_OK) { 526 // this CPU doesn't support cpuid 527 return; 528 } 529 530 int32 maxStandardFunction = baseInfo.eax_0.max_eax; 531 if (maxStandardFunction >= 500) { 532 // old Pentium sample chips has cpu signature here 533 maxStandardFunction = 0; 534 } 535 536 // Extended cpuid 537 538 cpuid_info cpuInfo; 539 get_cpuid(&cpuInfo, 0x80000000, cpu); 540 541 // Extended cpuid is only supported if max_eax is greater than the 542 // service id 543 int32 maxExtendedFunction = 0; 544 if (cpuInfo.eax_0.max_eax > 0x80000000) 545 maxExtendedFunction = cpuInfo.eax_0.max_eax & 0xff; 546 547 if (maxExtendedFunction >=4 ) { 548 char buffer[49]; 549 char *name = buffer; 550 551 memset(buffer, 0, sizeof(buffer)); 552 553 for (int32 i = 0; i < 3; i++) { 554 cpuid_info nameInfo; 555 get_cpuid(&nameInfo, 0x80000002 + i, cpu); 556 557 memcpy(name, &nameInfo.regs.eax, 4); 558 memcpy(name + 4, &nameInfo.regs.ebx, 4); 559 memcpy(name + 8, &nameInfo.regs.ecx, 4); 560 memcpy(name + 12, &nameInfo.regs.edx, 4); 561 name += 16; 562 } 563 564 // cut off leading spaces (names are right aligned) 565 name = buffer; 566 while (name[0] == ' ') 567 name++; 568 569 // the BIOS may not have set the processor name 570 if (name[0]) 571 printf("CPU #%" B_PRId32 ": \"%s\"\n", cpu, name); 572 else { 573 // Intel CPUs don't seem to have the genuine vendor field 574 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, 575 (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86 ? 576 baseInfo.eax_0.vendor_id : cpuInfo.eax_0.vendor_id); 577 } 578 } else { 579 printf("CPU #%" B_PRId32 ": %.12s\n", cpu, baseInfo.eax_0.vendor_id); 580 if (maxStandardFunction == 0) 581 return; 582 } 583 584 get_cpuid(&cpuInfo, 1, cpu); 585 print_processor_signature(info, &cpuInfo, NULL); 586 print_features(cpuInfo.eax_1.features); 587 588 if (maxStandardFunction >= 1) { 589 /* Extended features */ 590 printf("\tExtended Intel: 0x%08" B_PRIx32 "\n", cpuInfo.eax_1.extended_features); 591 print_extended_features(cpuInfo.eax_1.extended_features); 592 } 593 594 /* Extended CPUID */ 595 if (maxExtendedFunction >= 1) { 596 get_cpuid(&cpuInfo, 0x80000001, cpu); 597 print_processor_signature(info, &cpuInfo, "Extended AMD: "); 598 599 if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_AMD_x86 600 || (info->cpu_type & B_CPU_x86_VENDOR_MASK) == B_CPU_INTEL_x86) { 601 print_amd_features(cpuInfo.regs.edx); 602 if (maxExtendedFunction >= 7) { 603 get_cpuid(&cpuInfo, 0x80000007, cpu); 604 print_amd_power_management_features(cpuInfo.regs.edx); 605 } 606 } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) 607 == B_CPU_TRANSMETA_x86) 608 print_transmeta_features(cpuInfo.regs.edx); 609 } 610 611 /* Cache/TLB descriptors */ 612 if (maxExtendedFunction >= 5) { 613 if (!strncmp(baseInfo.eax_0.vendor_id, "CyrixInstead", 12)) { 614 get_cpuid(&cpuInfo, 0x00000002, cpu); 615 print_intel_cache_descriptors(info->cpu_type, &cpuInfo); 616 } else if ((info->cpu_type & B_CPU_x86_VENDOR_MASK) 617 == B_CPU_INTEL_x86) { 618 // Intel does not support extended function 5 (but it does 6 hmm) 619 print_intel_cache_desc(cpu); 620 } else { 621 print_cache_desc(cpu); 622 } 623 } 624 625 if (maxStandardFunction >= 2) { 626 do { 627 get_cpuid(&cpuInfo, 2, cpu); 628 629 if (cpuInfo.eax_2.call_num > 0) 630 print_intel_cache_descriptors(info->cpu_type, &cpuInfo); 631 } while (cpuInfo.eax_2.call_num > 1); 632 } 633 634 /* Serial number */ 635 if (maxStandardFunction >= 3) { 636 cpuid_info flagsInfo; 637 get_cpuid(&flagsInfo, 1, cpu); 638 639 if (flagsInfo.eax_1.features & (1UL << 18)) { 640 get_cpuid(&cpuInfo, 3, cpu); 641 printf("Serial number: %04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 642 "-%04" B_PRIx32 "-%04" B_PRIx32 "-%04" B_PRIx32 "\n", 643 flagsInfo.eax_1.features >> 16, 644 flagsInfo.eax_1.features & 0xffff, 645 cpuInfo.regs.edx >> 16, cpuInfo.regs.edx & 0xffff, 646 cpuInfo.regs.ecx >> 16, cpuInfo.regs.edx & 0xffff); 647 } 648 } 649 650 putchar('\n'); 651 } 652 653 #endif // __INTEL__ || __x86_64__ 654 655 656 static void 657 dump_cpus(system_info *info) 658 { 659 const char *vendor = get_cpu_vendor_string(info->cpu_type); 660 const char *model = get_cpu_model_string(info); 661 char modelString[32]; 662 663 if (model == NULL && vendor == NULL) 664 model = "(Unknown)"; 665 else if (model == NULL) { 666 model = modelString; 667 snprintf(modelString, 32, "(Unknown %x)", info->cpu_type); 668 } 669 670 printf("%" B_PRId32 " %s%s%s, revision %04" B_PRIx32 " running at %" 671 B_PRId64 "MHz (ID: 0x%08" B_PRIx32 " 0x%08" B_PRIx32 ")\n\n", 672 info->cpu_count, 673 vendor ? vendor : "", vendor ? " " : "", model, 674 info->cpu_revision, 675 info->cpu_clock_speed / 1000000, 676 info->id[0], info->id[1]); 677 678 #if defined(__INTEL__) || defined(__x86_64__) 679 for (int32 cpu = 0; cpu < info->cpu_count; cpu++) 680 dump_cpu(info, cpu); 681 #endif // __INTEL__ || __x86_64__ 682 } 683 684 685 static void 686 dump_mem(system_info *info) 687 { 688 printf("%10" B_PRIu32 " bytes free (used/max %10" B_PRIu32 " / %10" 689 B_PRIu32 ")\n", 690 B_PAGE_SIZE * (uint32)(info->max_pages - info->used_pages), 691 B_PAGE_SIZE * (uint32)info->used_pages, 692 B_PAGE_SIZE * (uint32)info->max_pages); 693 printf(" (cached %10" B_PRIu32 ")\n", 694 B_PAGE_SIZE * (uint32)info->cached_pages); 695 } 696 697 698 static void 699 dump_sem(system_info *info) 700 { 701 printf("%10" B_PRId32 " semaphores free (used/max %10" B_PRId32 " / %10" 702 B_PRId32 ")\n", 703 info->max_sems - info->used_sems, 704 info->used_sems, info->max_sems); 705 } 706 707 708 static void 709 dump_ports(system_info *info) 710 { 711 printf("%10" B_PRId32 " ports free (used/max %10" B_PRId32 " / %10" 712 B_PRId32 ")\n", 713 info->max_ports - info->used_ports, 714 info->used_ports, info->max_ports); 715 } 716 717 718 static void 719 dump_thread(system_info *info) 720 { 721 printf("%10" B_PRId32 " threads free (used/max %10" B_PRId32 " / %10" 722 B_PRId32 ")\n", 723 info->max_threads - info->used_threads, 724 info->used_threads, info->max_threads); 725 } 726 727 728 static void 729 dump_team(system_info *info) 730 { 731 printf("%10" B_PRId32 " teams free (used/max %10" B_PRId32 " / %10" 732 B_PRId32 ")\n", 733 info->max_teams - info->used_teams, 734 info->used_teams, info->max_teams); 735 } 736 737 738 static void 739 dump_kinfo(system_info *info) 740 { 741 printf("Kernel name: %s built on: %s %s version 0x%" B_PRIx64 "\n", 742 info->kernel_name, 743 info->kernel_build_date, info->kernel_build_time, 744 info->kernel_version ); 745 } 746 747 748 static void 749 dump_system_info(system_info *info) 750 { 751 dump_kinfo(info); 752 dump_cpus(info); 753 dump_mem(info); 754 dump_sem(info); 755 dump_ports(info); 756 dump_thread(info); 757 dump_team(info); 758 } 759 760 761 int 762 main(int argc, char *argv[]) 763 { 764 if (!is_computer_on()) { 765 printf("The computer is not on! No info available\n"); 766 exit(EXIT_FAILURE); 767 } 768 769 system_info info; 770 if (get_system_info(&info) != B_OK) { 771 printf("Error getting system information!\n"); 772 return 1; 773 } 774 775 if (argc <= 1) { 776 dump_system_info(&info); 777 } else { 778 for (int i = 1; i < argc; i++) { 779 const char *opt = argv[i]; 780 if (strncmp(opt, "-id", strlen(opt)) == 0) { 781 /* note: the original also assumes this option on "sysinfo -" */ 782 printf("0x%.8" B_PRIx32 " 0x%.8" B_PRIx32 "\n", info.id[0], 783 info.id[1]); 784 } else if (strncmp(opt, "-cpu", strlen(opt)) == 0) { 785 dump_cpus(&info); 786 } else if (strncmp(opt, "-mem", strlen(opt)) == 0) { 787 dump_mem(&info); 788 } else if (strncmp(opt, "-semaphores", strlen(opt)) == 0) { 789 dump_sem(&info); 790 } else if (strncmp(opt, "-ports", strlen(opt)) == 0) { 791 dump_ports(&info); 792 } else if (strncmp(opt, "-threads", strlen(opt)) == 0) { 793 dump_thread(&info); 794 } else if (strncmp(opt, "-teams", strlen(opt)) == 0) { 795 dump_team(&info); 796 } else if (strncmp(opt, "-kinfo", strlen(opt)) == 0) { 797 dump_kinfo(&info); 798 } else if (strncmp(opt, "-platform", strlen(opt)) == 0) { 799 dump_platform(&info); 800 } else if (strncmp(opt, "-disable_cpu_sn", strlen(opt)) == 0) { 801 /* TODO: printf("CPU #%d serial number: old state: %s, new state: %s\n", ... ); */ 802 fprintf(stderr, "Sorry, not yet implemented\n"); 803 } else { 804 const char *name = strrchr(argv[0], '/'); 805 if (name == NULL) 806 name = argv[0]; 807 else 808 name++; 809 810 fprintf(stderr, "Usage:\n"); 811 fprintf(stderr, " %s [-id|-cpu|-mem|-semaphore|-ports|-threads|-teams|-platform|-disable_cpu_sn|-kinfo]\n", name); 812 return 0; 813 } 814 } 815 } 816 return 0; 817 } 818