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