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