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