1 //===-- cpu_model.c - Support for __cpu_model builtin ------------*- C -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is based on LLVM's lib/Support/Host.cpp. 11 // It implements the operating system Host concept and builtin 12 // __cpu_model for the compiler_rt library, for x86 only. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #if (defined(__i386__) || defined(_M_IX86) || \ 17 defined(__x86_64__) || defined(_M_X64)) && \ 18 (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)) 19 20 #include <assert.h> 21 22 #define bool int 23 #define true 1 24 #define false 0 25 26 #ifdef _MSC_VER 27 #include <intrin.h> 28 #endif 29 30 #ifndef __has_attribute 31 #define __has_attribute(attr) 0 32 #endif 33 34 enum VendorSignatures { 35 SIG_INTEL = 0x756e6547 /* Genu */, 36 SIG_AMD = 0x68747541 /* Auth */ 37 }; 38 39 enum ProcessorVendors { 40 VENDOR_INTEL = 1, 41 VENDOR_AMD, 42 VENDOR_OTHER, 43 VENDOR_MAX 44 }; 45 46 enum ProcessorTypes { 47 INTEL_BONNELL = 1, 48 INTEL_CORE2, 49 INTEL_COREI7, 50 AMDFAM10H, 51 AMDFAM15H, 52 INTEL_SILVERMONT, 53 INTEL_KNL, 54 AMD_BTVER1, 55 AMD_BTVER2, 56 AMDFAM17H, 57 INTEL_KNM, 58 INTEL_GOLDMONT, 59 INTEL_GOLDMONT_PLUS, 60 INTEL_TREMONT, 61 CPU_TYPE_MAX 62 }; 63 64 enum ProcessorSubtypes { 65 INTEL_COREI7_NEHALEM = 1, 66 INTEL_COREI7_WESTMERE, 67 INTEL_COREI7_SANDYBRIDGE, 68 AMDFAM10H_BARCELONA, 69 AMDFAM10H_SHANGHAI, 70 AMDFAM10H_ISTANBUL, 71 AMDFAM15H_BDVER1, 72 AMDFAM15H_BDVER2, 73 AMDFAM15H_BDVER3, 74 AMDFAM15H_BDVER4, 75 AMDFAM17H_ZNVER1, 76 INTEL_COREI7_IVYBRIDGE, 77 INTEL_COREI7_HASWELL, 78 INTEL_COREI7_BROADWELL, 79 INTEL_COREI7_SKYLAKE, 80 INTEL_COREI7_SKYLAKE_AVX512, 81 INTEL_COREI7_CANNONLAKE, 82 INTEL_COREI7_ICELAKE_CLIENT, 83 INTEL_COREI7_ICELAKE_SERVER, 84 CPU_SUBTYPE_MAX 85 }; 86 87 enum ProcessorFeatures { 88 FEATURE_CMOV = 0, 89 FEATURE_MMX, 90 FEATURE_POPCNT, 91 FEATURE_SSE, 92 FEATURE_SSE2, 93 FEATURE_SSE3, 94 FEATURE_SSSE3, 95 FEATURE_SSE4_1, 96 FEATURE_SSE4_2, 97 FEATURE_AVX, 98 FEATURE_AVX2, 99 FEATURE_SSE4_A, 100 FEATURE_FMA4, 101 FEATURE_XOP, 102 FEATURE_FMA, 103 FEATURE_AVX512F, 104 FEATURE_BMI, 105 FEATURE_BMI2, 106 FEATURE_AES, 107 FEATURE_PCLMUL, 108 FEATURE_AVX512VL, 109 FEATURE_AVX512BW, 110 FEATURE_AVX512DQ, 111 FEATURE_AVX512CD, 112 FEATURE_AVX512ER, 113 FEATURE_AVX512PF, 114 FEATURE_AVX512VBMI, 115 FEATURE_AVX512IFMA, 116 FEATURE_AVX5124VNNIW, 117 FEATURE_AVX5124FMAPS, 118 FEATURE_AVX512VPOPCNTDQ, 119 FEATURE_AVX512VBMI2, 120 FEATURE_GFNI, 121 FEATURE_VPCLMULQDQ, 122 FEATURE_AVX512VNNI, 123 FEATURE_AVX512BITALG 124 }; 125 126 // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). 127 // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID 128 // support. Consequently, for i386, the presence of CPUID is checked first 129 // via the corresponding eflags bit. 130 static bool isCpuIdSupported() { 131 #if defined(__GNUC__) || defined(__clang__) 132 #if defined(__i386__) 133 int __cpuid_supported; 134 __asm__(" pushfl\n" 135 " popl %%eax\n" 136 " movl %%eax,%%ecx\n" 137 " xorl $0x00200000,%%eax\n" 138 " pushl %%eax\n" 139 " popfl\n" 140 " pushfl\n" 141 " popl %%eax\n" 142 " movl $0,%0\n" 143 " cmpl %%eax,%%ecx\n" 144 " je 1f\n" 145 " movl $1,%0\n" 146 "1:" 147 : "=r"(__cpuid_supported) 148 : 149 : "eax", "ecx"); 150 if (!__cpuid_supported) 151 return false; 152 #endif 153 return true; 154 #endif 155 return true; 156 } 157 158 // This code is copied from lib/Support/Host.cpp. 159 // Changes to either file should be mirrored in the other. 160 161 /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in 162 /// the specified arguments. If we can't run cpuid on the host, return true. 163 static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, 164 unsigned *rECX, unsigned *rEDX) { 165 #if defined(__GNUC__) || defined(__clang__) 166 #if defined(__x86_64__) 167 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 168 // FIXME: should we save this for Clang? 169 __asm__("movq\t%%rbx, %%rsi\n\t" 170 "cpuid\n\t" 171 "xchgq\t%%rbx, %%rsi\n\t" 172 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 173 : "a"(value)); 174 return false; 175 #elif defined(__i386__) 176 __asm__("movl\t%%ebx, %%esi\n\t" 177 "cpuid\n\t" 178 "xchgl\t%%ebx, %%esi\n\t" 179 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 180 : "a"(value)); 181 return false; 182 #else 183 return true; 184 #endif 185 #elif defined(_MSC_VER) 186 // The MSVC intrinsic is portable across x86 and x64. 187 int registers[4]; 188 __cpuid(registers, value); 189 *rEAX = registers[0]; 190 *rEBX = registers[1]; 191 *rECX = registers[2]; 192 *rEDX = registers[3]; 193 return false; 194 #else 195 return true; 196 #endif 197 } 198 199 /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return 200 /// the 4 values in the specified arguments. If we can't run cpuid on the host, 201 /// return true. 202 static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, 203 unsigned *rEAX, unsigned *rEBX, unsigned *rECX, 204 unsigned *rEDX) { 205 #if defined(__GNUC__) || defined(__clang__) 206 #if defined(__x86_64__) 207 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 208 // FIXME: should we save this for Clang? 209 __asm__("movq\t%%rbx, %%rsi\n\t" 210 "cpuid\n\t" 211 "xchgq\t%%rbx, %%rsi\n\t" 212 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 213 : "a"(value), "c"(subleaf)); 214 return false; 215 #elif defined(__i386__) 216 __asm__("movl\t%%ebx, %%esi\n\t" 217 "cpuid\n\t" 218 "xchgl\t%%ebx, %%esi\n\t" 219 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 220 : "a"(value), "c"(subleaf)); 221 return false; 222 #else 223 return true; 224 #endif 225 #elif defined(_MSC_VER) 226 int registers[4]; 227 __cpuidex(registers, value, subleaf); 228 *rEAX = registers[0]; 229 *rEBX = registers[1]; 230 *rECX = registers[2]; 231 *rEDX = registers[3]; 232 return false; 233 #else 234 return true; 235 #endif 236 } 237 238 // Read control register 0 (XCR0). Used to detect features such as AVX. 239 static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { 240 #if defined(__GNUC__) || defined(__clang__) 241 // Check xgetbv; this uses a .byte sequence instead of the instruction 242 // directly because older assemblers do not include support for xgetbv and 243 // there is no easy way to conditionally compile based on the assembler used. 244 __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); 245 return false; 246 #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 247 unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 248 *rEAX = Result; 249 *rEDX = Result >> 32; 250 return false; 251 #else 252 return true; 253 #endif 254 } 255 256 static void detectX86FamilyModel(unsigned EAX, unsigned *Family, 257 unsigned *Model) { 258 *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 259 *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 260 if (*Family == 6 || *Family == 0xf) { 261 if (*Family == 0xf) 262 // Examine extended family ID if family ID is F. 263 *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 264 // Examine extended model ID if family ID is 6 or F. 265 *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 266 } 267 } 268 269 static void 270 getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, 271 unsigned Brand_id, unsigned Features, 272 unsigned *Type, unsigned *Subtype) { 273 if (Brand_id != 0) 274 return; 275 switch (Family) { 276 case 6: 277 switch (Model) { 278 case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile 279 // processor, Intel Core 2 Quad processor, Intel Core 2 Quad 280 // mobile processor, Intel Core 2 Extreme processor, Intel 281 // Pentium Dual-Core processor, Intel Xeon processor, model 282 // 0Fh. All processors are manufactured using the 65 nm process. 283 case 0x16: // Intel Celeron processor model 16h. All processors are 284 // manufactured using the 65 nm process 285 case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model 286 // 17h. All processors are manufactured using the 45 nm process. 287 // 288 // 45nm: Penryn , Wolfdale, Yorkfield (XE) 289 case 0x1d: // Intel Xeon processor MP. All processors are manufactured using 290 // the 45 nm process. 291 *Type = INTEL_CORE2; // "penryn" 292 break; 293 case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All 294 // processors are manufactured using the 45 nm process. 295 case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. 296 // As found in a Summer 2010 model iMac. 297 case 0x1f: 298 case 0x2e: // Nehalem EX 299 *Type = INTEL_COREI7; // "nehalem" 300 *Subtype = INTEL_COREI7_NEHALEM; 301 break; 302 case 0x25: // Intel Core i7, laptop version. 303 case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All 304 // processors are manufactured using the 32 nm process. 305 case 0x2f: // Westmere EX 306 *Type = INTEL_COREI7; // "westmere" 307 *Subtype = INTEL_COREI7_WESTMERE; 308 break; 309 case 0x2a: // Intel Core i7 processor. All processors are manufactured 310 // using the 32 nm process. 311 case 0x2d: 312 *Type = INTEL_COREI7; //"sandybridge" 313 *Subtype = INTEL_COREI7_SANDYBRIDGE; 314 break; 315 case 0x3a: 316 case 0x3e: // Ivy Bridge EP 317 *Type = INTEL_COREI7; // "ivybridge" 318 *Subtype = INTEL_COREI7_IVYBRIDGE; 319 break; 320 321 // Haswell: 322 case 0x3c: 323 case 0x3f: 324 case 0x45: 325 case 0x46: 326 *Type = INTEL_COREI7; // "haswell" 327 *Subtype = INTEL_COREI7_HASWELL; 328 break; 329 330 // Broadwell: 331 case 0x3d: 332 case 0x47: 333 case 0x4f: 334 case 0x56: 335 *Type = INTEL_COREI7; // "broadwell" 336 *Subtype = INTEL_COREI7_BROADWELL; 337 break; 338 339 // Skylake: 340 case 0x4e: // Skylake mobile 341 case 0x5e: // Skylake desktop 342 case 0x8e: // Kaby Lake mobile 343 case 0x9e: // Kaby Lake desktop 344 *Type = INTEL_COREI7; // "skylake" 345 *Subtype = INTEL_COREI7_SKYLAKE; 346 break; 347 348 // Skylake Xeon: 349 case 0x55: 350 *Type = INTEL_COREI7; 351 *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" 352 break; 353 354 // Cannonlake: 355 case 0x66: 356 *Type = INTEL_COREI7; 357 *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake" 358 break; 359 360 case 0x1c: // Most 45 nm Intel Atom processors 361 case 0x26: // 45 nm Atom Lincroft 362 case 0x27: // 32 nm Atom Medfield 363 case 0x35: // 32 nm Atom Midview 364 case 0x36: // 32 nm Atom Midview 365 *Type = INTEL_BONNELL; 366 break; // "bonnell" 367 368 // Atom Silvermont codes from the Intel software optimization guide. 369 case 0x37: 370 case 0x4a: 371 case 0x4d: 372 case 0x5a: 373 case 0x5d: 374 case 0x4c: // really airmont 375 *Type = INTEL_SILVERMONT; 376 break; // "silvermont" 377 // Goldmont: 378 case 0x5c: // Apollo Lake 379 case 0x5f: // Denverton 380 *Type = INTEL_GOLDMONT; 381 break; // "goldmont" 382 case 0x7a: 383 *Type = INTEL_GOLDMONT_PLUS; 384 break; 385 386 case 0x57: 387 *Type = INTEL_KNL; // knl 388 break; 389 390 case 0x85: 391 *Type = INTEL_KNM; // knm 392 break; 393 394 default: // Unknown family 6 CPU. 395 break; 396 break; 397 } 398 default: 399 break; // Unknown. 400 } 401 } 402 403 static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, 404 unsigned Features, unsigned *Type, 405 unsigned *Subtype) { 406 // FIXME: this poorly matches the generated SubtargetFeatureKV table. There 407 // appears to be no way to generate the wide variety of AMD-specific targets 408 // from the information returned from CPUID. 409 switch (Family) { 410 case 16: 411 *Type = AMDFAM10H; // "amdfam10" 412 switch (Model) { 413 case 2: 414 *Subtype = AMDFAM10H_BARCELONA; 415 break; 416 case 4: 417 *Subtype = AMDFAM10H_SHANGHAI; 418 break; 419 case 8: 420 *Subtype = AMDFAM10H_ISTANBUL; 421 break; 422 } 423 break; 424 case 20: 425 *Type = AMD_BTVER1; 426 break; // "btver1"; 427 case 21: 428 *Type = AMDFAM15H; 429 if (Model >= 0x60 && Model <= 0x7f) { 430 *Subtype = AMDFAM15H_BDVER4; 431 break; // "bdver4"; 60h-7Fh: Excavator 432 } 433 if (Model >= 0x30 && Model <= 0x3f) { 434 *Subtype = AMDFAM15H_BDVER3; 435 break; // "bdver3"; 30h-3Fh: Steamroller 436 } 437 if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { 438 *Subtype = AMDFAM15H_BDVER2; 439 break; // "bdver2"; 02h, 10h-1Fh: Piledriver 440 } 441 if (Model <= 0x0f) { 442 *Subtype = AMDFAM15H_BDVER1; 443 break; // "bdver1"; 00h-0Fh: Bulldozer 444 } 445 break; 446 case 22: 447 *Type = AMD_BTVER2; 448 break; // "btver2" 449 case 23: 450 *Type = AMDFAM17H; 451 *Subtype = AMDFAM17H_ZNVER1; 452 break; 453 default: 454 break; // "generic" 455 } 456 } 457 458 static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, 459 unsigned *FeaturesOut, 460 unsigned *Features2Out) { 461 unsigned Features = 0; 462 unsigned Features2 = 0; 463 unsigned EAX, EBX; 464 465 #define setFeature(F) \ 466 do { \ 467 if (F < 32) \ 468 Features |= 1 << F; \ 469 else if (F < 64) \ 470 Features2 |= 1 << (F - 32); \ 471 } while (0) 472 473 if ((EDX >> 15) & 1) 474 setFeature(FEATURE_CMOV); 475 if ((EDX >> 23) & 1) 476 setFeature(FEATURE_MMX); 477 if ((EDX >> 25) & 1) 478 setFeature(FEATURE_SSE); 479 if ((EDX >> 26) & 1) 480 setFeature(FEATURE_SSE2); 481 482 if ((ECX >> 0) & 1) 483 setFeature(FEATURE_SSE3); 484 if ((ECX >> 1) & 1) 485 setFeature(FEATURE_PCLMUL); 486 if ((ECX >> 9) & 1) 487 setFeature(FEATURE_SSSE3); 488 if ((ECX >> 12) & 1) 489 setFeature(FEATURE_FMA); 490 if ((ECX >> 19) & 1) 491 setFeature(FEATURE_SSE4_1); 492 if ((ECX >> 20) & 1) 493 setFeature(FEATURE_SSE4_2); 494 if ((ECX >> 23) & 1) 495 setFeature(FEATURE_POPCNT); 496 if ((ECX >> 25) & 1) 497 setFeature(FEATURE_AES); 498 499 // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 500 // indicates that the AVX registers will be saved and restored on context 501 // switch, then we have full AVX support. 502 const unsigned AVXBits = (1 << 27) | (1 << 28); 503 bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && 504 ((EAX & 0x6) == 0x6); 505 bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); 506 507 if (HasAVX) 508 setFeature(FEATURE_AVX); 509 510 bool HasLeaf7 = 511 MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); 512 513 if (HasLeaf7 && ((EBX >> 3) & 1)) 514 setFeature(FEATURE_BMI); 515 if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) 516 setFeature(FEATURE_AVX2); 517 if (HasLeaf7 && ((EBX >> 9) & 1)) 518 setFeature(FEATURE_BMI2); 519 if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) 520 setFeature(FEATURE_AVX512F); 521 if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) 522 setFeature(FEATURE_AVX512DQ); 523 if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) 524 setFeature(FEATURE_AVX512IFMA); 525 if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) 526 setFeature(FEATURE_AVX512PF); 527 if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) 528 setFeature(FEATURE_AVX512ER); 529 if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) 530 setFeature(FEATURE_AVX512CD); 531 if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) 532 setFeature(FEATURE_AVX512BW); 533 if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) 534 setFeature(FEATURE_AVX512VL); 535 536 if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) 537 setFeature(FEATURE_AVX512VBMI); 538 if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) 539 setFeature(FEATURE_AVX512VBMI2); 540 if (HasLeaf7 && ((ECX >> 8) & 1)) 541 setFeature(FEATURE_GFNI); 542 if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX) 543 setFeature(FEATURE_VPCLMULQDQ); 544 if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) 545 setFeature(FEATURE_AVX512VNNI); 546 if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) 547 setFeature(FEATURE_AVX512BITALG); 548 if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) 549 setFeature(FEATURE_AVX512VPOPCNTDQ); 550 551 if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) 552 setFeature(FEATURE_AVX5124VNNIW); 553 if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) 554 setFeature(FEATURE_AVX5124FMAPS); 555 556 unsigned MaxExtLevel; 557 getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); 558 559 bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && 560 !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); 561 if (HasExtLeaf1 && ((ECX >> 6) & 1)) 562 setFeature(FEATURE_SSE4_A); 563 if (HasExtLeaf1 && ((ECX >> 11) & 1)) 564 setFeature(FEATURE_XOP); 565 if (HasExtLeaf1 && ((ECX >> 16) & 1)) 566 setFeature(FEATURE_FMA4); 567 568 *FeaturesOut = Features; 569 *Features2Out = Features2; 570 #undef setFeature 571 } 572 573 #if defined(HAVE_INIT_PRIORITY) 574 #define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) 575 #elif __has_attribute(__constructor__) 576 #define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) 577 #else 578 // FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that 579 // this runs during initialization. 580 #define CONSTRUCTOR_ATTRIBUTE 581 #endif 582 583 int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; 584 585 struct __processor_model { 586 unsigned int __cpu_vendor; 587 unsigned int __cpu_type; 588 unsigned int __cpu_subtype; 589 unsigned int __cpu_features[1]; 590 } __cpu_model = {0, 0, 0, {0}}; 591 unsigned int __cpu_features2; 592 593 /* A constructor function that is sets __cpu_model and __cpu_features2 with 594 the right values. This needs to run only once. This constructor is 595 given the highest priority and it should run before constructors without 596 the priority set. However, it still runs after ifunc initializers and 597 needs to be called explicitly there. */ 598 599 int CONSTRUCTOR_ATTRIBUTE 600 __cpu_indicator_init(void) { 601 unsigned EAX, EBX, ECX, EDX; 602 unsigned MaxLeaf = 5; 603 unsigned Vendor; 604 unsigned Model, Family, Brand_id; 605 unsigned Features = 0; 606 unsigned Features2 = 0; 607 608 /* This function needs to run just once. */ 609 if (__cpu_model.__cpu_vendor) 610 return 0; 611 612 if (!isCpuIdSupported()) 613 return -1; 614 615 /* Assume cpuid insn present. Run in level 0 to get vendor id. */ 616 if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { 617 __cpu_model.__cpu_vendor = VENDOR_OTHER; 618 return -1; 619 } 620 getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); 621 detectX86FamilyModel(EAX, &Family, &Model); 622 Brand_id = EBX & 0xff; 623 624 /* Find available features. */ 625 getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2); 626 __cpu_model.__cpu_features[0] = Features; 627 __cpu_features2 = Features2; 628 629 if (Vendor == SIG_INTEL) { 630 /* Get CPU type. */ 631 getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, 632 &(__cpu_model.__cpu_type), 633 &(__cpu_model.__cpu_subtype)); 634 __cpu_model.__cpu_vendor = VENDOR_INTEL; 635 } else if (Vendor == SIG_AMD) { 636 /* Get CPU type. */ 637 getAMDProcessorTypeAndSubtype(Family, Model, Features, 638 &(__cpu_model.__cpu_type), 639 &(__cpu_model.__cpu_subtype)); 640 __cpu_model.__cpu_vendor = VENDOR_AMD; 641 } else 642 __cpu_model.__cpu_vendor = VENDOR_OTHER; 643 644 assert(__cpu_model.__cpu_vendor < VENDOR_MAX); 645 assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); 646 assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 647 648 return 0; 649 } 650 651 #endif 652