cpuid.cc
1 #include "version.h" 2 #include "config.h" 3 #include "cpuid.h" 4 #include <stdio.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <sys/stat.h> 9 #include <sys/time.h> 10 #include <cstring> 11 12 __ID("@(#) $Id$"); 13 14 #if defined(__i386__) || defined(__alpha__) 15 16 static hwNode *getcache(hwNode & node, 17 int n = 0) 18 { 19 char cachename[10]; 20 hwNode *cache = NULL; 21 22 if (n < 0) 23 n = 0; 24 25 snprintf(cachename, sizeof(cachename), "cache:%d", n); 26 cache = node.getChild(string(cachename)); 27 28 if (cache) 29 return cache; 30 31 // "cache:0" is equivalent to "cache" if we only have L1 cache 32 if ((n == 0) && (node.countChildren(hw::memory) <= 1)) 33 cache = node.getChild(string("cache")); 34 if (cache) 35 return cache; 36 else 37 return NULL; 38 } 39 40 41 static hwNode *getcpu(hwNode & node, 42 int n = 0) 43 { 44 char cpubusinfo[10]; 45 hwNode *cpu = NULL; 46 47 if (n < 0) 48 n = 0; 49 50 snprintf(cpubusinfo, sizeof(cpubusinfo), "cpu@%d", n); 51 cpu = node.findChildByBusInfo(cpubusinfo); 52 53 if (cpu) 54 return cpu; 55 56 if (n > 0) 57 return NULL; 58 59 hwNode *core = node.getChild("core"); 60 61 if (core) 62 { 63 hwNode cpu("cpu", hw::processor); 64 65 cpu.setBusInfo(cpubusinfo); 66 cpu.addHint("icon", string("cpu")); 67 cpu.claim(); 68 69 return core->addChild(cpu); 70 } 71 else 72 return NULL; 73 } 74 #endif // __i386__ || __alpha__ 75 76 #ifdef __i386__ 77 78 /* %ebx may be the PIC register. */ 79 #define cpuid_up(in,a,b,c,d)\ 80 __asm__ ("xchgl\t%%ebx, %1\n\t" \ 81 "cpuid\n\t" \ 82 "xchgl\t%%ebx, %1\n\t" \ 83 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ 84 : "0" (in)) 85 86 static void cpuid(int cpunumber, 87 unsigned long idx, 88 unsigned long &eax, 89 unsigned long &ebx, 90 unsigned long &ecx, 91 unsigned long &edx) 92 { 93 char cpuname[50]; 94 int fd = -1; 95 unsigned char buffer[16]; 96 97 snprintf(cpuname, sizeof(cpuname), "/dev/cpu/%d/cpuid", cpunumber); 98 fd = open(cpuname, O_RDONLY); 99 if (fd >= 0) 100 { 101 lseek(fd, idx, SEEK_CUR); 102 memset(buffer, 0, sizeof(buffer)); 103 if(read(fd, buffer, sizeof(buffer)) == sizeof(buffer)) 104 { 105 eax = (*(unsigned long *) buffer); 106 ebx = (*(unsigned long *) (buffer + 4)); 107 ecx = (*(unsigned long *) (buffer + 8)); 108 edx = (*(unsigned long *) (buffer + 12)); 109 } 110 close(fd); 111 } 112 else 113 cpuid_up(idx, eax, ebx, ecx, edx); 114 } 115 116 117 /* Decode Intel TLB and cache info descriptors */ 118 static void decode_intel_tlb(int x, 119 long long &l1cache, 120 long long &l2cache) 121 { 122 x &= 0xff; 123 switch (x) 124 { 125 case 0: 126 break; 127 case 0x1: 128 // Instruction TLB: 4KB pages, 4-way set assoc, 32 entries 129 break; 130 case 0x2: 131 // Instruction TLB: 4MB pages, 4-way set assoc, 2 entries 132 break; 133 case 0x3: 134 // Data TLB: 4KB pages, 4-way set assoc, 64 entries 135 break; 136 case 0x4: 137 // Data TLB: 4MB pages, 4-way set assoc, 8 entries 138 break; 139 case 0x6: 140 // 1st-level instruction cache: 8KB, 4-way set assoc, 32 byte line size 141 l1cache += 8 * 1024; 142 break; 143 case 0x8: 144 // 1st-level instruction cache: 16KB, 4-way set assoc, 32 byte line size 145 l1cache += 16 * 1024; 146 break; 147 case 0xa: 148 // 1st-level data cache: 8KB, 2-way set assoc, 32 byte line size 149 l1cache += 8 * 1024; 150 break; 151 case 0xc: 152 // 1st-level data cache: 16KB, 4-way set assoc, 32 byte line size 153 l1cache += 16 * 1024; 154 break; 155 case 0x40: 156 // No 2nd-level cache, or if 2nd-level cache exists, no 3rd-level cache 157 break; 158 case 0x41: 159 // 2nd-level cache: 128KB, 4-way set assoc, 32 byte line size 160 l2cache = 128 * 1024; 161 break; 162 case 0x42: 163 // 2nd-level cache: 256KB, 4-way set assoc, 32 byte line size 164 l2cache = 256 * 1024; 165 break; 166 case 0x43: 167 // 2nd-level cache: 512KB, 4-way set assoc, 32 byte line size 168 l2cache = 512 * 1024; 169 break; 170 case 0x44: 171 // 2nd-level cache: 1MB, 4-way set assoc, 32 byte line size 172 l2cache = 1024 * 1024; 173 break; 174 case 0x45: 175 // 2nd-level cache: 2MB, 4-way set assoc, 32 byte line size 176 l2cache = 2 * 1024 * 1024; 177 break; 178 case 0x50: 179 // Instruction TLB: 4KB and 2MB or 4MB pages, 64 entries 180 break; 181 case 0x51: 182 // Instruction TLB: 4KB and 2MB or 4MB pages, 128 entries 183 break; 184 case 0x52: 185 // Instruction TLB: 4KB and 2MB or 4MB pages, 256 entries 186 break; 187 case 0x5b: 188 // Data TLB: 4KB and 4MB pages, 64 entries 189 break; 190 case 0x5c: 191 // Data TLB: 4KB and 4MB pages, 128 entries 192 break; 193 case 0x5d: 194 // Data TLB: 4KB and 4MB pages, 256 entries 195 break; 196 case 0x66: 197 // 1st-level data cache: 8KB, 4-way set assoc, 64 byte line size 198 l1cache += 8 * 1024; 199 break; 200 case 0x67: 201 // 1st-level data cache: 16KB, 4-way set assoc, 64 byte line size 202 l1cache += 16 * 1024; 203 break; 204 case 0x68: 205 // 1st-level data cache: 32KB, 4-way set assoc, 64 byte line size 206 l1cache += 32 * 1024; 207 break; 208 case 0x70: 209 // Trace cache: 12K-micro-op, 4-way set assoc 210 break; 211 case 0x71: 212 // Trace cache: 16K-micro-op, 4-way set assoc 213 break; 214 case 0x72: 215 // Trace cache: 32K-micro-op, 4-way set assoc 216 break; 217 case 0x79: 218 // 2nd-level cache: 128KB, 8-way set assoc, sectored, 64 byte line size 219 l2cache += 128 * 1024; 220 break; 221 case 0x7a: 222 // 2nd-level cache: 256KB, 8-way set assoc, sectored, 64 byte line size 223 l2cache += 256 * 1024; 224 break; 225 case 0x7b: 226 // 2nd-level cache: 512KB, 8-way set assoc, sectored, 64 byte line size 227 l2cache += 512 * 1024; 228 break; 229 case 0x7c: 230 // 2nd-level cache: 1MB, 8-way set assoc, sectored, 64 byte line size 231 l2cache += 1024 * 1024; 232 break; 233 case 0x82: 234 // 2nd-level cache: 256KB, 8-way set assoc, 32 byte line size 235 l2cache += 256 * 1024; 236 break; 237 case 0x83: 238 // 2nd-level cache: 512KB, 8-way set assoc 32 byte line size 239 l2cache += 512 * 1024; 240 break; 241 case 0x84: 242 // 2nd-level cache: 1MB, 8-way set assoc, 32 byte line size 243 l2cache += 1024 * 1024; 244 break; 245 case 0x85: 246 // 2nd-level cache: 2MB, 8-way set assoc, 32 byte line size 247 l2cache += 2 * 1024 * 1024; 248 break; 249 default: 250 // unknown TLB/cache descriptor 251 break; 252 } 253 } 254 255 256 static bool dointel(unsigned long maxi, 257 hwNode * cpu, 258 int cpunumber = 0) 259 { 260 char buffer[1024]; 261 unsigned long signature = 0, flags = 0, bflags = 0, eax = 0, ebx = 0, ecx = 0, edx = 0, unused = 0; 262 int stepping, model, family; 263 264 if (!cpu) 265 return false; 266 267 cpu->addHint("logo", string("intel")); 268 269 if (maxi >= 1) 270 { 271 cpuid(cpunumber, 1, eax, ebx, ecx, edx); 272 273 signature = eax; 274 275 stepping = eax & 0xf; 276 model = (eax >> 4) & 0xf; 277 family = (eax >> 8) & 0xf; 278 flags = edx; 279 bflags = ebx; 280 281 snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping); 282 cpu->setVersion(buffer); 283 284 if(ecx & (1 << 5)) 285 cpu->addCapability("vmx", _("CPU virtualization (Vanderpool)")); 286 287 /* Hyper-Threading Technology */ 288 if (flags & (1 << 28)) 289 { 290 char buff[20]; 291 unsigned int nr_ht = (bflags >> 16) & 0xFF; 292 unsigned int phys_id = (bflags >> 24) & 0xFF; 293 294 snprintf(buff, sizeof(buff), "%d", phys_id); 295 cpu->setConfig("id", buff); 296 297 hwNode logicalcpu("logicalcpu", hw::processor); 298 logicalcpu.setDescription(_("Logical CPU")); 299 logicalcpu.addCapability("logical", _("Logical CPU")); 300 logicalcpu.setWidth(cpu->getWidth()); 301 logicalcpu.claim(); 302 cpu->addCapability("ht", _("HyperThreading")); 303 304 if(nr_ht>1) 305 for(unsigned int i=0; i< nr_ht; i++) 306 { 307 snprintf(buff, sizeof(buff), "CPU:%d.%d", phys_id, i); 308 logicalcpu.setHandle(buff); 309 logicalcpu.setPhysId(phys_id, i+1); 310 cpu->addChild(logicalcpu); 311 cpu->claim(); 312 } 313 } 314 315 } 316 317 if (maxi >= 2) 318 { 319 /* 320 * Decode TLB and cache info 321 */ 322 int ntlb, i; 323 long long l1cache = 0, l2cache = 0; 324 325 ntlb = 255; 326 for (i = 0; i < ntlb; i++) 327 { 328 cpuid(cpunumber, 2, eax, ebx, ecx, edx); 329 ntlb = eax & 0xff; 330 decode_intel_tlb(eax >> 8, l1cache, l2cache); 331 decode_intel_tlb(eax >> 16, l1cache, l2cache); 332 decode_intel_tlb(eax >> 24, l1cache, l2cache); 333 334 if ((ebx & 0x80000000) == 0) 335 { 336 decode_intel_tlb(ebx, l1cache, l2cache); 337 decode_intel_tlb(ebx >> 8, l1cache, l2cache); 338 decode_intel_tlb(ebx >> 16, l1cache, l2cache); 339 decode_intel_tlb(ebx >> 24, l1cache, l2cache); 340 } 341 if ((ecx & 0x80000000) == 0) 342 { 343 decode_intel_tlb(ecx, l1cache, l2cache); 344 decode_intel_tlb(ecx >> 8, l1cache, l2cache); 345 decode_intel_tlb(ecx >> 16, l1cache, l2cache); 346 decode_intel_tlb(ecx >> 24, l1cache, l2cache); 347 } 348 if ((edx & 0x80000000) == 0) 349 { 350 decode_intel_tlb(edx, l1cache, l2cache); 351 decode_intel_tlb(edx >> 8, l1cache, l2cache); 352 decode_intel_tlb(edx >> 16, l1cache, l2cache); 353 decode_intel_tlb(edx >> 24, l1cache, l2cache); 354 } 355 } 356 357 if (l1cache != 0) 358 { 359 hwNode *l1 = getcache(*cpu, 0); 360 hwNode *l2 = getcache(*cpu, 1); 361 362 if (l1) 363 { 364 l1->setSize(l1cache); 365 if (l1->getDescription() == "") 366 l1->setDescription(_("L1 cache")); 367 } 368 else 369 { 370 hwNode cache("cache", 371 hw::memory); 372 cache.setSize(l1cache); 373 cache.setDescription(_("L1 cache")); 374 375 cpu->addChild(cache); 376 } 377 378 if (l2cache != 0) 379 { 380 if (l2 && (l2cache != 0)) 381 { 382 l2->setSize(l2cache); 383 if (l2->getDescription() == "") 384 l2->setDescription(_("L2 cache")); 385 } 386 else 387 { 388 hwNode cache("cache", 389 hw::memory); 390 cache.setSize(l2cache); 391 cache.setDescription(_("L2 cache")); 392 393 cpu->addChild(cache); 394 } 395 } 396 } 397 } 398 399 if (maxi >= 3) 400 { 401 cpuid(cpunumber, 3, unused, unused, ecx, edx); 402 403 snprintf(buffer, sizeof(buffer), 404 "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX", 405 signature >> 16, 406 signature & 0xffff, 407 edx >> 16, edx & 0xffff, ecx >> 16, ecx & 0xffff); 408 409 cpu->setSerial(buffer); 410 } 411 else 412 cpu->setSerial(""); 413 414 return true; 415 } 416 417 418 static bool doamd(unsigned long maxi, 419 hwNode * cpu, 420 int cpunumber = 0) 421 { 422 unsigned long maxei = 0, eax, ebx, ecx, edx; 423 long long l1cache = 0, l2cache = 0; 424 unsigned int family = 0, model = 0, stepping = 0; 425 char buffer[1024]; 426 427 if (maxi < 1) 428 return false; 429 430 cpu->addHint("logo", string("amd")); 431 432 cpuid(cpunumber, 1, eax, ebx, ecx, edx); 433 stepping = eax & 0xf; 434 model = (eax >> 4) & 0xf; 435 family = (eax >> 8) & 0xf; 436 snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping); 437 cpu->setVersion(buffer); 438 439 cpuid(cpunumber, 0x80000000, maxei, ebx, ecx, edx); 440 441 if (maxei >= 0x80000005) 442 { 443 cpuid(cpunumber, 0x80000005, eax, ebx, ecx, edx); 444 445 l1cache = (ecx >> 24) * 1024; // data cache 446 l1cache += (edx >> 24) * 1024; // instruction cache 447 } 448 if (maxei >= 0x80000006) 449 { 450 cpuid(cpunumber, 0x80000006, eax, ebx, ecx, edx); 451 452 l2cache = (ecx >> 16) * 1024; 453 } 454 455 if (l1cache != 0) 456 { 457 hwNode *l1 = cpu->getChild("cache:0"); 458 hwNode *l2 = cpu->getChild("cache:1"); 459 460 if (l1) 461 l1->setSize(l1cache); 462 else 463 { 464 hwNode newl1("cache", 465 hw::memory); 466 467 newl1.setDescription(_("L1 cache")); 468 newl1.setSize(l1cache); 469 470 cpu->addChild(newl1); 471 } 472 if (l2 && l2cache) 473 l2->setSize(l2cache); 474 else 475 { 476 hwNode newl2("cache", 477 hw::memory); 478 479 newl2.setDescription(_("L2 cache")); 480 newl2.setSize(l2cache); 481 482 if (l2cache) 483 cpu->addChild(newl2); 484 } 485 } 486 487 return true; 488 } 489 490 491 static bool docyrix(unsigned long maxi, 492 hwNode * cpu, 493 int cpunumber = 0) 494 { 495 unsigned long eax, ebx, ecx, edx; 496 unsigned int family = 0, model = 0, stepping = 0; 497 char buffer[1024]; 498 499 if (maxi < 1) 500 return false; 501 502 cpuid(cpunumber, 1, eax, ebx, ecx, edx); 503 stepping = eax & 0xf; 504 model = (eax >> 4) & 0xf; 505 family = (eax >> 8) & 0xf; 506 snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping); 507 cpu->setVersion(buffer); 508 509 return true; 510 } 511 512 513 static __inline__ bool flag_is_changeable_p(unsigned int flag) 514 { 515 unsigned int f1, f2; 516 __asm__ volatile ("pushfl\n\t" 517 "pushfl\n\t" 518 "popl %0\n\t" 519 "movl %0,%1\n\t" 520 "xorl %2,%0\n\t" 521 "pushl %0\n\t" 522 "popfl\n\t" 523 "pushfl\n\t" "popl %0\n\t" "popfl\n\t":"=&r" (f1), 524 "=&r"(f2):"ir"(flag)); 525 return ((f1 ^ f2) & flag) != 0; 526 } 527 528 529 static bool haveCPUID() 530 { 531 return flag_is_changeable_p(0x200000); 532 } 533 534 535 /* 536 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de> 537 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> 538 * 539 */ 540 541 static __inline__ unsigned long long int rdtsc() 542 { 543 unsigned long long int x; 544 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x)); 545 return x; 546 } 547 548 549 static float estimate_MHz(int cpunum, 550 long sleeptime = 250000) 551 { 552 struct timezone tz; 553 struct timeval tvstart, tvstop; 554 unsigned long long int cycles[2]; /* gotta be 64 bit */ 555 float microseconds; /* total time taken */ 556 unsigned long eax, ebx, ecx, edx; 557 double freq = 1.0f; 558 559 /* 560 * Make sure we have a TSC (and hence RDTSC) 561 */ 562 cpuid(cpunum, 1, eax, ebx, ecx, edx); 563 if ((edx & (1 << 4)) == 0) 564 { 565 return 0; // can't estimate frequency 566 } 567 568 memset(&tz, 0, sizeof(tz)); 569 570 /* 571 * get this function in cached memory 572 */ 573 gettimeofday(&tvstart, &tz); 574 cycles[0] = rdtsc(); 575 gettimeofday(&tvstart, &tz); 576 577 /* 578 * we don't trust that this is any specific length of time 579 */ 580 usleep(sleeptime); 581 582 gettimeofday(&tvstop, &tz); 583 cycles[1] = rdtsc(); 584 gettimeofday(&tvstop, &tz); 585 586 microseconds = (tvstop.tv_sec - tvstart.tv_sec) * 1000000 + 587 (tvstop.tv_usec - tvstart.tv_usec); 588 589 return (float) (cycles[1] - cycles[0]) / (microseconds / freq); 590 } 591 592 593 static float average_MHz(int cpunum, 594 int tries = 2) 595 { 596 float frequency = 0; 597 598 for (int i = 1; i <= tries; i++) 599 frequency += estimate_MHz(cpunum, i * 150000); 600 601 if (tries > 0) 602 return frequency / (float) tries; 603 else 604 return 0; 605 } 606 607 608 static long round_MHz(float fMHz) 609 { 610 long MHz = (long)fMHz; 611 612 if ((MHz % 50) > 15) 613 return ((MHz / 50) * 50) + 50; 614 else 615 return ((MHz / 50) * 50); 616 } 617 618 619 bool scan_cpuid(hwNode & n) 620 { 621 unsigned long maxi, ebx, ecx, edx; 622 hwNode *cpu = NULL; 623 int currentcpu = 0; 624 625 if (!haveCPUID()) 626 return false; 627 628 while ((cpu = getcpu(n, currentcpu))) 629 { 630 cpu->claim(true); // claim the cpu and all its children 631 cpuid(currentcpu, 0, maxi, ebx, ecx, edx); 632 maxi &= 0xffff; 633 634 switch (ebx) 635 { 636 case 0x756e6547: /* Intel */ 637 dointel(maxi, cpu, currentcpu); 638 break; 639 case 0x68747541: /* AMD */ 640 doamd(maxi, cpu, currentcpu); 641 break; 642 case 0x69727943: /* Cyrix */ 643 docyrix(maxi, cpu, currentcpu); 644 break; 645 default: 646 return false; 647 } 648 649 cpu->claim(true); // claim the cpu and all its children 650 if (cpu->getSize() == 0) 651 cpu->setSize((unsigned long long) (1000000uL * round_MHz(average_MHz(currentcpu)))); 652 653 currentcpu++; 654 } 655 656 return true; 657 } 658 659 660 #else 661 662 #ifdef __alpha__ 663 664 #define BWX (1 << 0) 665 #define FIX (1 << 1) 666 #define CIX (1 << 2) 667 #define MVI (1 << 8) 668 #define PAT (1 << 9) 669 #define PMI (1 << 12) 670 671 bool scan_cpuid(hwNode & n) 672 { 673 hwNode *cpu = NULL; 674 int currentcpu = 0; 675 unsigned long ver = 0, mask = 0; 676 677 while (cpu = getcpu(n, currentcpu)) 678 { 679 asm("implver %0":"=r"(ver)); 680 asm("amask %1, %0": "=r"(mask):"r"(-1)); 681 682 cpu->setVendor("Digital Equipment Corporation"); 683 cpu->setProduct("Alpha"); 684 cpu->setWidth(64); 685 686 if ((~mask) & BWX) 687 cpu->addCapability("BWX"); 688 if ((~mask) & FIX) 689 cpu->addCapability("FIX"); 690 if ((~mask) & CIX) 691 cpu->addCapability("CIX"); 692 if ((~mask) & MVI) 693 cpu->addCapability("MVI"); 694 if ((~mask) & PAT) 695 cpu->addCapability("PAT"); 696 if ((~mask) & PMI) 697 cpu->addCapability("PMI"); 698 699 switch (ver) 700 { 701 case 0: 702 cpu->setVersion("EV4"); 703 break; 704 case 1: 705 switch (~mask) 706 { 707 case 0: 708 cpu->setVersion("EV5"); 709 break; 710 case BWX: 711 cpu->setVersion("EV56"); 712 break; 713 case BWX | MVI: 714 cpu->setVersion("PCA56"); 715 break; 716 default: 717 cpu->setVersion("EV5 unknown"); 718 } 719 break; 720 case 2: 721 switch (~mask) 722 { 723 case BWX | FIX | MVI | PAT: 724 cpu->setVersion("EV6"); 725 break; 726 case BWX | FIX | MVI | PAT | CIX: 727 cpu->setVersion("EV67"); 728 break; 729 case BWX | FIX | MVI | PAT | CIX | PMI: 730 cpu->setVersion("EV68"); 731 break; 732 default: 733 cpu->setVersion("EV6 unknown"); 734 } 735 break; 736 case 3: 737 switch (~mask) 738 { 739 case BWX | FIX | MVI | PAT | CIX | PMI: 740 cpu->setVersion("EV7x"); 741 break; 742 default: 743 cpu->setVersion("EV7 unknown"); 744 } 745 break; 746 } 747 748 currentcpu++; 749 } 750 751 return true; 752 } 753 754 755 #else 756 757 bool scan_cpuid(hwNode & n) 758 { 759 return true; 760 } 761 #endif /* __alpha__ */ 762 #endif /* __i386__ */