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