cpuinfo.cc
1 #include "version.h" 2 #include "cpuinfo.h" 3 #include "osutils.h" 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 #include <unistd.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <vector> 11 12 __ID("@(#) $Id$"); 13 14 static int currentcpu = 0; 15 16 static inline bool is_system_ppc_ibm(hwNode & node) 17 { 18 string desc = node.getDescription(); 19 20 return (desc == "PowerNV" || desc == "pSeries Guest" || desc == "pSeries LPAR"); 21 } 22 23 static hwNode *getcpu(hwNode & node, 24 int n = 0) 25 { 26 char cpubusinfo[15]; 27 hwNode *cpu = NULL; 28 29 if (n < 0) 30 n = 0; 31 32 snprintf(cpubusinfo, sizeof(cpubusinfo), "cpu@%d", n); 33 cpu = node.findChildByBusInfo(cpubusinfo); 34 35 if (cpu) 36 { 37 cpu->addHint("icon", string("cpu")); 38 cpu->claim(true); // claim the cpu and all its children 39 if (!is_system_ppc_ibm(node)) 40 cpu->enable(); // enable it 41 42 return cpu; 43 } 44 45 /* 46 * device-tree.cc creates all CPU nodes on Power Systems. 47 * Hence do not create new CPU nodes here. 48 */ 49 if (is_system_ppc_ibm(node)) 50 return NULL; 51 52 hwNode *core = node.getChild("core"); 53 54 if (core) 55 { 56 hwNode newcpu("cpu", hw::processor); 57 58 newcpu.setBusInfo(cpubusinfo); 59 newcpu.claim(); 60 return core->addChild(newcpu); 61 } 62 else 63 return NULL; 64 } 65 66 67 static void cpuinfo_ppc_ibm(hwNode & node, 68 const string & description, const string & version) 69 { 70 hwNode *cpu = getcpu(node, currentcpu); 71 72 while (cpu) 73 { 74 cpu->setDescription(description); 75 cpu->setVersion(version); 76 77 cpu = getcpu(node, ++currentcpu); 78 } 79 } 80 81 static void cpuinfo_ppc(hwNode & node, 82 string id, 83 string value) 84 { 85 if (id == "processor") 86 currentcpu++; 87 88 hwNode *cpu = getcpu(node, currentcpu); 89 90 if (cpu) 91 { 92 cpu->addHint("logo", string("powerpc")); 93 cpu->claim(true); 94 if (id == "revision") 95 cpu->setVersion(value); 96 if (id == "cpu") 97 cpu->setProduct(value); 98 if (id == "clock") 99 { 100 double frequency = 0.0; 101 102 frequency = atof(value.c_str()); 103 cpu->setSize((unsigned long long) (frequency * 1E6)); 104 } 105 } 106 } 107 108 static vector <string> s390x_features; 109 static string s390x_vendor; 110 static void cpuinfo_s390x(hwNode & node, 111 string id, 112 string value) 113 { 114 if (id == "features") 115 { 116 while (value.length() > 0) 117 { 118 size_t pos = value.find(' '); 119 string capability = (pos==string::npos)?value:value.substr(0, pos); 120 s390x_features.push_back(capability); 121 if (pos == string::npos) 122 value = ""; 123 else 124 value = hw::strip(value.substr(pos)); 125 } 126 } 127 128 if (id == "vendor_id") 129 s390x_vendor = value; 130 131 if (matches(id, "^processor")) 132 currentcpu++; 133 134 hwNode *cpu = getcpu(node, currentcpu); 135 if (cpu) 136 { 137 cpu->addHint("logo", string("s390x")); 138 cpu->claim(true); 139 cpu->setVendor(s390x_vendor); 140 141 for(size_t i=0; i < s390x_features.size(); i++) 142 cpu->addCapability(s390x_features[i]); 143 /* many thanks to Martin Schwidefsky for communicating the descriptions 144 of the feature flags 145 */ 146 cpu->describeCapability("esan3", "ESA new instructions 3 (N3)"); 147 cpu->describeCapability("zarch", "x/Architecture (64-bit) mode)"); 148 cpu->describeCapability("stfle", "store facility list extended instruction"); 149 cpu->describeCapability("msa", "message security assist facility"); 150 cpu->describeCapability("ldisp", "long displacement facility"); 151 cpu->describeCapability("eimm", "extended immediate facility"); 152 cpu->describeCapability("dfp", "decimal floating point facility"); 153 cpu->describeCapability("edat", "enhanced DAT facility"); 154 cpu->describeCapability("etf3eh", "ETF3 enhancement facility"); 155 cpu->describeCapability("highgprs", "support for 64-bit registers for 31-bit programs"); 156 cpu->describeCapability("te", "transactional/constraint transactional execution facilities"); 157 } 158 } 159 160 static void cpuinfo_arm(hwNode & node, 161 string id, 162 string value) 163 { 164 165 if (id.substr(0, string("processor").size())=="processor") 166 currentcpu++; 167 168 hwNode *cpu = getcpu(node, currentcpu); 169 if (cpu) 170 { 171 cpu->addHint("logo", string("arm")); 172 if (id == "model name" && node.getDescription() == "") 173 node.setDescription(value); 174 cpu->claim(true); 175 if (id == "Features") 176 { 177 while (value.length() > 0) 178 { 179 size_t pos = value.find(' '); 180 string capability = (pos==string::npos)?value:value.substr(0, pos); 181 cpu->addCapability(capability); 182 if (pos == string::npos) 183 value = ""; 184 else 185 value = hw::strip(value.substr(pos)); 186 } 187 } 188 /* With help from: 189 http://infocenter.arm.com/help/index.jsp 190 http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean 191 http://en.wikipedia.org/wiki/ARM_architecture 192 */ 193 cpu->describeCapability("swp", "Swap instruction"); 194 cpu->describeCapability("swpb", "Swap Byte instruction"); 195 cpu->describeCapability("half", "Unknown"); 196 cpu->describeCapability("thumb", "Thumb instruction set"); 197 cpu->describeCapability("26bit", "26-bit Model"); 198 cpu->describeCapability("fastmult", "Fast Multiplication"); 199 cpu->describeCapability("fpa", "Floating point accelerator"); 200 cpu->describeCapability("vfp", "VFP (vector floating point instructions)"); 201 cpu->describeCapability("vfpv3", "VFP version 3"); 202 cpu->describeCapability("vfpv3d16", "VFP version 3 with 16 64-bit FPU registers"); 203 cpu->describeCapability("vfpv4", "VFP version 4"); 204 cpu->describeCapability("vfpd32", "Unknown"); 205 cpu->describeCapability("edsp", "DSP extensions"); 206 cpu->describeCapability("java", "Jazelle (Java bytecode accelerator)"); 207 cpu->describeCapability("thumbee", "Thumb Execution Environment"); 208 cpu->describeCapability("neon", "NEON aka MPE - Media Processing Engine"); 209 cpu->describeCapability("tls", "TLS register"); 210 cpu->describeCapability("iwmmxt", "SIMD instructions"); 211 cpu->describeCapability("crunch", "MaverickCrunch coprocessor"); 212 cpu->describeCapability("idiva", "SDIV and UDIV hardware division in ARM mode"); 213 cpu->describeCapability("idivt", "SDIV and UDIV hardware division in Thumb mode"); 214 cpu->describeCapability("lpae", "Large Physical Address Extension architecture"); 215 cpu->describeCapability("evtstrm", "Unknown"); 216 } 217 } 218 219 static vector <string> aarch64_features; 220 static string aarch64_processor_name; 221 static void cpuinfo_aarch64(hwNode & node, 222 string id, 223 string value) 224 { 225 226 /* 227 * If we already have CPU info extracted from SMBIOS, ignore /proc/cpuinfo 228 * entirely. This is because the kernel's /proc/cpuinfo output on aarch64 229 * does not distinguish between cores and physical processors (every core is 230 * treated as a separate processor) so we may end up creating too many CPU 231 * nodes. 232 */ 233 if (getcpu(node)->getHandle().compare(0, 4, "DMI:") == 0) 234 return; 235 236 if (id.substr(0, string("processor").size())=="processor") 237 currentcpu++; 238 239 if (id.substr(0, string("Processor").size())=="Processor") 240 aarch64_processor_name = value; 241 242 if (id == "Features") 243 { 244 hwNode *cpu = getcpu(node, currentcpu); 245 if (cpu) 246 { 247 cpu->addHint("logo", string("aarch64")); 248 if (node.getDescription() == "") 249 node.setDescription(aarch64_processor_name); 250 cpu->claim(true); 251 252 while (value.length() > 0) 253 { 254 size_t pos = value.find(' '); 255 string capability = (pos==string::npos)?value:value.substr(0, pos); 256 aarch64_features.push_back(capability); 257 if (pos == string::npos) 258 value = ""; 259 else 260 value = hw::strip(value.substr(pos)); 261 } 262 263 for(size_t i=0; i < aarch64_features.size(); i++) 264 { 265 cpu->addCapability(aarch64_features[i]); 266 cpu->describeCapability("fp", "Floating point instructions"); 267 cpu->describeCapability("asimd", "Advanced SIMD"); 268 cpu->describeCapability("evtstrm", "Event stream"); 269 cpu->describeCapability("aes", "AES instructions"); 270 cpu->describeCapability("pmull", "PMULL instruction"); 271 cpu->describeCapability("sha1", "SHA1 instructions"); 272 cpu->describeCapability("sha2", "SHA2 instructions"); 273 cpu->describeCapability("crc32", "CRC extension"); 274 } 275 } 276 } 277 } 278 279 static void cpuinfo_ia64(hwNode & node, 280 string id, 281 string value) 282 { 283 284 if (id == "processor") 285 currentcpu++; 286 287 hwNode *cpu = getcpu(node, currentcpu); 288 289 if (cpu) 290 { 291 cpu->claim(true); 292 293 if (id == "cpu number") 294 { 295 int physicalcpu = 0; 296 297 physicalcpu = atoi(value.c_str()); 298 299 if (physicalcpu != currentcpu) 300 { 301 cpu->addCapability("emulated"); 302 cpu->addCapability("hyperthreading"); 303 } 304 } 305 306 if (id == "vendor") 307 { 308 if (value == "GenuineIntel") 309 value = "Intel Corp."; 310 cpu->setVendor(value); 311 } 312 313 if (id == "revision") 314 cpu->setVersion(value); 315 316 if (id == "family") 317 cpu->setProduct(value); 318 319 if (id == "cpu MHz" && cpu->getSize() == 0) 320 { 321 double frequency = 0.0; 322 323 frequency = atof(value.c_str()); 324 cpu->setSize((unsigned long long) (frequency * 1E6)); 325 } 326 } 327 } 328 329 static void cpuinfo_hppa(hwNode & node, 330 string id, 331 string value) 332 { 333 if (id == "processor") 334 currentcpu++; 335 336 hwNode *cpu = getcpu(node, currentcpu); 337 338 if (id == "model" && node.getProduct() == "") 339 node.setProduct(value); 340 if (id == "model name" && node.getDescription() == "") 341 node.setDescription(value); 342 if (id == "software id" && node.getSerial() == "") 343 node.setSerial(value); 344 345 if (cpu) 346 { 347 cpu->claim(true); 348 349 if (id == "cpu family" && cpu->getVersion() == "") 350 cpu->setVersion(value); 351 if (id == "cpu" && cpu->getProduct() == "") 352 cpu->setProduct(value); 353 if (id == "cpu MHz" && cpu->getSize() == 0) 354 { 355 double frequency = 0.0; 356 357 frequency = atof(value.c_str()); 358 cpu->setSize((unsigned long long) (frequency * 1E6)); 359 } 360 } 361 } 362 363 static void cpuinfo_alpha(hwNode & node, 364 string id, 365 string value) 366 { 367 static int cpusdetected = 0; 368 static int cpusactive = 0; 369 unsigned long long frequency = 0; 370 int i; 371 372 hwNode *cpu = getcpu(node, 0); 373 374 if (id == "platform string" && node.getProduct() == "") 375 node.setProduct(value); 376 if (id == "system serial number" && node.getSerial() == "") 377 node.setSerial(value); 378 if (id == "system type") 379 node.setVersion(node.getVersion() + " " + value); 380 if (id == "system variation") 381 node.setVersion(node.getVersion() + " " + value); 382 if (id == "system revision") 383 node.setVersion(node.getVersion() + " " + value); 384 385 if (id == "cpus detected") 386 cpusdetected = atoi(value.c_str()); 387 if (id == "cpus active") 388 cpusactive = atoi(value.c_str()); 389 if (id == "cycle frequency [Hz]") 390 frequency = atoll(value.c_str()); 391 392 if (cpu) 393 { 394 cpu->claim(true); 395 396 if (frequency) 397 cpu->setSize(frequency); 398 } 399 400 for (i = 1; i < cpusdetected; i++) 401 { 402 hwNode *mycpu = getcpu(node, i); 403 404 if (mycpu) 405 { 406 mycpu->disable(); 407 408 if (cpu) 409 mycpu->setSize(cpu->getSize()); 410 } 411 } 412 for (i = 1; i < cpusactive; i++) 413 { 414 hwNode *mycpu = getcpu(node, i); 415 416 if (mycpu) 417 mycpu->enable(); 418 } 419 } 420 421 static void cpuinfo_x86(hwNode & node, 422 string id, 423 string value) 424 { 425 static int siblings = -1; 426 427 if(currentcpu < 0) siblings = -1; 428 429 if ((siblings<0) && (id == "siblings")) 430 { 431 siblings = atoi(value.c_str()); 432 siblings--; 433 } 434 435 if (id == "processor") 436 { 437 siblings--; 438 439 if(siblings >= 0) 440 return; 441 else 442 currentcpu++; 443 } 444 445 hwNode *cpu = getcpu(node, currentcpu); 446 447 if (cpu) 448 { 449 hw::value family, model, stepping; 450 451 // x86 CPUs are assumed to be 32 bits per default 452 if(cpu->getWidth()==0) cpu->setWidth(32); 453 454 cpu->claim(true); 455 if (id == "vendor_id") 456 { 457 if (value == "AuthenticAMD") 458 value = "Advanced Micro Devices [AMD]"; 459 if (value == "HygonGenuine") 460 value = "Hygon"; 461 if (value == "GenuineIntel") 462 value = "Intel Corp."; 463 cpu->setVendor(value); 464 } 465 if (id == "model name") 466 cpu->setProduct(value); 467 if (id == "microcode") 468 cpu->setConfig(id, stoll(value, NULL, 0)); 469 if (id == "cpu family") 470 cpu->addHint(id, stoll(value, NULL, 0)); 471 if (id == "model") 472 cpu->addHint(id, stoll(value, NULL, 0)); 473 if (id == "stepping") 474 cpu->addHint(id, stoll(value, NULL, 0)); 475 476 family = cpu->getHint("cpu family"); 477 model = cpu->getHint("model"); 478 stepping = cpu->getHint("stepping"); 479 if(family.defined() && model.defined() && stepping.defined()) 480 cpu->setVersion(tostring(family.asInteger())+"."+tostring(model.asInteger())+"."+tostring(stepping.asInteger())); 481 482 //if ((id == "cpu MHz") && (cpu->getSize() == 0)) 483 //{ 484 //cpu->setSize((long long) (1000000L * atof(value.c_str()))); 485 //} 486 if (id == "Physical processor ID") 487 cpu->setSerial(value); 488 if ((id == "fdiv_bug") && (value == "yes")) 489 cpu->addCapability("fdiv_bug"); 490 if ((id == "hlt_bug") && (value == "yes")) 491 cpu->addCapability("hlt_bug"); 492 if ((id == "f00f_bug") && (value == "yes")) 493 cpu->addCapability("f00f_bug"); 494 if ((id == "coma_bug") && (value == "yes")) 495 cpu->addCapability("coma_bug"); 496 if ((id == "fpu") && (value == "yes")) 497 cpu->addCapability("fpu"); 498 if ((id == "wp") && (value == "yes")) 499 cpu->addCapability("wp"); 500 if ((id == "fpu_exception") && (value == "yes")) 501 cpu->addCapability("fpu_exception", "FPU exceptions reporting"); 502 if (id == "flags") 503 while (value.length() > 0) 504 { 505 size_t pos = value.find(' '); 506 string capability = (pos==string::npos)?value:value.substr(0, pos); 507 508 if(capability == "lm") capability = "x86-64"; 509 510 cpu->addCapability(capability); 511 512 if (pos == string::npos) 513 value = ""; 514 else 515 value = hw::strip(value.substr(pos)); 516 } 517 518 cpu->describeCapability("fpu", "mathematical co-processor"); 519 cpu->describeCapability("vme", "virtual mode extensions"); 520 cpu->describeCapability("de", "debugging extensions"); 521 cpu->describeCapability("pse", "page size extensions"); 522 cpu->describeCapability("tsc", "time stamp counter"); 523 cpu->describeCapability("msr", "model-specific registers"); 524 cpu->describeCapability("mce", "machine check exceptions"); 525 cpu->describeCapability("cx8", "compare and exchange 8-byte"); 526 cpu->describeCapability("apic", "on-chip advanced programmable interrupt controller (APIC)"); 527 cpu->describeCapability("sep", "fast system calls"); 528 cpu->describeCapability("mtrr", "memory type range registers"); 529 cpu->describeCapability("pge", "page global enable"); 530 cpu->describeCapability("mca", "machine check architecture"); 531 cpu->describeCapability("cmov", "conditional move instruction"); 532 cpu->describeCapability("pat", "page attribute table"); 533 cpu->describeCapability("pse36", "36-bit page size extensions"); 534 cpu->describeCapability("pn", "processor serial number"); 535 cpu->describeCapability("psn", "processor serial number"); 536 cpu->describeCapability("clflush", "CLFLUSH instruction"); 537 cpu->describeCapability("dts", "debug trace and EMON store MSRs"); 538 cpu->describeCapability("acpi", "thermal control (ACPI)"); 539 cpu->describeCapability("fxsr", "fast floating point save/restore"); 540 cpu->describeCapability("sse", "streaming SIMD extensions (SSE)"); 541 cpu->describeCapability("sse2", "streaming SIMD extensions (SSE2)"); 542 cpu->describeCapability("ss", "self-snoop"); 543 cpu->describeCapability("tm", "thermal interrupt and status"); 544 cpu->describeCapability("ia64", "IA-64 (64-bit Intel CPU)"); 545 cpu->describeCapability("pbe", "pending break event"); 546 cpu->describeCapability("syscall", "fast system calls"); 547 cpu->describeCapability("mp", "multi-processor capable"); 548 cpu->describeCapability("nx", "no-execute bit (NX)"); 549 cpu->describeCapability("mmxext", "multimedia extensions (MMXExt)"); 550 cpu->describeCapability("3dnowext", "multimedia extensions (3DNow!Ext)"); 551 cpu->describeCapability("3dnow", "multimedia extensions (3DNow!)"); 552 cpu->describeCapability("recovery", "CPU in recovery mode"); 553 cpu->describeCapability("longrun", "LongRun Dynamic Power/Thermal Management"); 554 cpu->describeCapability("lrti", "LongRun Table Interface"); 555 cpu->describeCapability("cxmmx", "multimedia extensions (Cyrix MMX)"); 556 cpu->describeCapability("k6_mtrr", "AMD K6 MTRRs"); 557 cpu->describeCapability("cyrix_arr", "Cyrix ARRs (= MTRRs)"); 558 cpu->describeCapability("centaur_mcr", "Centaur MCRs (= MTRRs)"); 559 cpu->describeCapability("pni", "SSE-3"); 560 cpu->describeCapability("monitor", "MONITOR/MWAIT support"); 561 //cpu->describeCapability("ds_cpl", ""); 562 //cpu->describeCapability("est", ""); 563 //cpu->describeCapability("tm2", ""); 564 //cpu->describeCapability("cid", ""); 565 //cpu->describeCapability("xtpr", ""); 566 cpu->describeCapability("rng", "random number generator"); 567 cpu->describeCapability("rng_en", "random number generator (enhanced)"); 568 cpu->describeCapability("ace", "advanced cryptography engine"); 569 cpu->describeCapability("ace_en", "advanced cryptography engine (enhanced)"); 570 cpu->describeCapability("ht", "HyperThreading"); 571 cpu->describeCapability("lm", "64bits extensions (x86-64)"); 572 cpu->describeCapability("x86-64", "64bits extensions (x86-64)"); 573 cpu->describeCapability("mmx", "multimedia extensions (MMX)"); 574 cpu->describeCapability("pae", "4GB+ memory addressing (Physical Address Extension)"); 575 576 if(cpu->isCapable("ia64") || cpu->isCapable("lm") || cpu->isCapable("x86-64")) 577 cpu->setWidth(64); 578 579 if(node.getWidth()==0) node.setWidth(cpu->getWidth()); 580 } 581 } 582 583 bool scan_cpuinfo(hwNode & n) 584 { 585 hwNode *core = n.getChild("core"); 586 int cpuinfo = open("/proc/cpuinfo", O_RDONLY); 587 588 if (cpuinfo < 0) 589 return false; 590 591 if (!core) 592 { 593 n.addChild(hwNode("core", hw::bus)); 594 core = n.getChild("core"); 595 } 596 597 if (core) 598 { 599 char buffer[1024]; 600 ssize_t count; 601 string cpuinfo_str = ""; 602 string description = "", version = ""; 603 string plat = platform(); 604 605 while ((count = read(cpuinfo, buffer, sizeof(buffer))) > 0) 606 { 607 cpuinfo_str += string(buffer, count); 608 } 609 close(cpuinfo); 610 611 vector < string > cpuinfo_lines; 612 splitlines(cpuinfo_str, cpuinfo_lines); 613 cpuinfo_str = ""; // free memory 614 currentcpu = -1; 615 616 for (unsigned int i = 0; i < cpuinfo_lines.size(); i++) 617 { 618 string id = ""; 619 string value = ""; 620 size_t pos = 0; 621 622 pos = cpuinfo_lines[i].find(':'); 623 624 if (pos != string::npos) 625 { 626 id = hw::strip(cpuinfo_lines[i].substr(0, pos)); 627 value = hw::strip(cpuinfo_lines[i].substr(pos + 1)); 628 629 if (plat == "ppc" || plat == "ppc64" || plat == "ppc64le") 630 { 631 // All cores have same product name and version on power systems 632 if (is_system_ppc_ibm(n)) 633 { 634 if (id == "cpu") 635 description = value; 636 if (id == "revision") 637 version = value; 638 639 if (description != "" && version != "") 640 { 641 cpuinfo_ppc_ibm(n, description, version); 642 break; 643 } 644 } 645 else 646 cpuinfo_ppc(n, id, value); 647 } 648 else if (plat == "hppa") 649 { 650 cpuinfo_hppa(n, id, value); 651 } 652 else if (plat == "alpha") 653 { 654 cpuinfo_alpha(n, id, value); 655 } 656 else if (plat == "ia64") 657 { 658 cpuinfo_ia64(n, id, value); 659 } 660 else if (plat == "s390" || plat == "s390x") 661 { 662 cpuinfo_s390x(n, id, value); 663 } 664 else if (plat.compare(0, 3, "arm") == 0) 665 { 666 cpuinfo_arm(n, id, value); 667 } 668 else if (plat == "aarch64") 669 { 670 cpuinfo_aarch64(n, id, value); 671 } 672 else 673 { 674 cpuinfo_x86(n, id, value); 675 } 676 } 677 } 678 } 679 else 680 { 681 close(cpuinfo); 682 return false; 683 } 684 685 hwNode *cpu = getcpu(n, 0); 686 if(cpu && (n.getWidth()==0)) 687 n.setWidth(cpu->getWidth()); 688 689 return true; 690 }