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