1// Copyright 2013 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/base/cpu.h" 6 7#if defined(V8_OS_STARBOARD) 8#include "starboard/cpu_features.h" 9#endif 10 11#if V8_LIBC_MSVCRT 12#include <intrin.h> // __cpuid() 13#endif 14#if V8_OS_LINUX 15#include <linux/auxvec.h> // AT_HWCAP 16#endif 17#if V8_GLIBC_PREREQ(2, 16) 18#include <sys/auxv.h> // getauxval() 19#endif 20#if V8_OS_QNX 21#include <sys/syspage.h> // cpuinfo 22#endif 23#if V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_PPC64) 24#include <elf.h> 25#endif 26#if V8_OS_AIX 27#include <sys/systemcfg.h> // _system_configuration 28#ifndef POWER_8 29#define POWER_8 0x10000 30#endif 31#ifndef POWER_9 32#define POWER_9 0x20000 33#endif 34#ifndef POWER_10 35#define POWER_10 0x40000 36#endif 37#endif 38#if V8_OS_POSIX 39#include <unistd.h> // sysconf() 40#endif 41 42#include <ctype.h> 43#include <limits.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47 48#include <algorithm> 49 50#include "src/base/logging.h" 51#include "src/base/platform/wrappers.h" 52#if V8_OS_WIN 53#include <windows.h> 54 55#include "src/base/win32-headers.h" 56#endif 57 58namespace v8 { 59namespace base { 60 61#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 62 63// Define __cpuid() for non-MSVC libraries. 64#if !V8_LIBC_MSVCRT 65 66static V8_INLINE void __cpuid(int cpu_info[4], int info_type) { 67// Clear ecx to align with __cpuid() of MSVC: 68// https://msdn.microsoft.com/en-us/library/hskdteyh.aspx 69#if defined(__i386__) && defined(__pic__) 70 // Make sure to preserve ebx, which contains the pointer 71 // to the GOT in case we're generating PIC. 72 __asm__ volatile( 73 "mov %%ebx, %%edi\n\t" 74 "cpuid\n\t" 75 "xchg %%edi, %%ebx\n\t" 76 : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), 77 "=d"(cpu_info[3]) 78 : "a"(info_type), "c"(0)); 79#else 80 __asm__ volatile("cpuid \n\t" 81 : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), 82 "=d"(cpu_info[3]) 83 : "a"(info_type), "c"(0)); 84#endif // defined(__i386__) && defined(__pic__) 85} 86 87#endif // !V8_LIBC_MSVCRT 88 89#elif V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 || V8_HOST_ARCH_MIPS || \ 90 V8_HOST_ARCH_MIPS64 || V8_HOST_ARCH_RISCV64 91 92#if V8_OS_LINUX 93 94#if V8_HOST_ARCH_ARM 95 96// See <uapi/asm/hwcap.h> kernel header. 97/* 98 * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP 99 */ 100#define HWCAP_SWP (1 << 0) 101#define HWCAP_HALF (1 << 1) 102#define HWCAP_THUMB (1 << 2) 103#define HWCAP_26BIT (1 << 3) /* Play it safe */ 104#define HWCAP_FAST_MULT (1 << 4) 105#define HWCAP_FPA (1 << 5) 106#define HWCAP_VFP (1 << 6) 107#define HWCAP_EDSP (1 << 7) 108#define HWCAP_JAVA (1 << 8) 109#define HWCAP_IWMMXT (1 << 9) 110#define HWCAP_CRUNCH (1 << 10) 111#define HWCAP_THUMBEE (1 << 11) 112#define HWCAP_NEON (1 << 12) 113#define HWCAP_VFPv3 (1 << 13) 114#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */ 115#define HWCAP_TLS (1 << 15) 116#define HWCAP_VFPv4 (1 << 16) 117#define HWCAP_IDIVA (1 << 17) 118#define HWCAP_IDIVT (1 << 18) 119#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ 120#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) 121#define HWCAP_LPAE (1 << 20) 122 123#endif // V8_HOST_ARCH_ARM 124 125#if V8_HOST_ARCH_ARM64 126 127// See <uapi/asm/hwcap.h> kernel header. 128/* 129 * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP 130 */ 131#define HWCAP_FP (1 << 0) 132#define HWCAP_ASIMD (1 << 1) 133#define HWCAP_EVTSTRM (1 << 2) 134#define HWCAP_AES (1 << 3) 135#define HWCAP_PMULL (1 << 4) 136#define HWCAP_SHA1 (1 << 5) 137#define HWCAP_SHA2 (1 << 6) 138#define HWCAP_CRC32 (1 << 7) 139#define HWCAP_ATOMICS (1 << 8) 140#define HWCAP_FPHP (1 << 9) 141#define HWCAP_ASIMDHP (1 << 10) 142#define HWCAP_CPUID (1 << 11) 143#define HWCAP_ASIMDRDM (1 << 12) 144#define HWCAP_JSCVT (1 << 13) 145#define HWCAP_FCMA (1 << 14) 146#define HWCAP_LRCPC (1 << 15) 147#define HWCAP_DCPOP (1 << 16) 148#define HWCAP_SHA3 (1 << 17) 149#define HWCAP_SM3 (1 << 18) 150#define HWCAP_SM4 (1 << 19) 151#define HWCAP_ASIMDDP (1 << 20) 152#define HWCAP_SHA512 (1 << 21) 153#define HWCAP_SVE (1 << 22) 154#define HWCAP_ASIMDFHM (1 << 23) 155#define HWCAP_DIT (1 << 24) 156#define HWCAP_USCAT (1 << 25) 157#define HWCAP_ILRCPC (1 << 26) 158#define HWCAP_FLAGM (1 << 27) 159#define HWCAP_SSBS (1 << 28) 160#define HWCAP_SB (1 << 29) 161#define HWCAP_PACA (1 << 30) 162#define HWCAP_PACG (1UL << 31) 163 164#endif // V8_HOST_ARCH_ARM64 165 166#if V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 167 168static uint32_t ReadELFHWCaps() { 169 uint32_t result = 0; 170#if V8_GLIBC_PREREQ(2, 16) 171 result = static_cast<uint32_t>(getauxval(AT_HWCAP)); 172#else 173 // Read the ELF HWCAP flags by parsing /proc/self/auxv. 174 FILE* fp = base::Fopen("/proc/self/auxv", "r"); 175 if (fp != nullptr) { 176 struct { 177 uint32_t tag; 178 uint32_t value; 179 } entry; 180 for (;;) { 181 size_t n = fread(&entry, sizeof(entry), 1, fp); 182 if (n == 0 || (entry.tag == 0 && entry.value == 0)) { 183 break; 184 } 185 if (entry.tag == AT_HWCAP) { 186 result = entry.value; 187 break; 188 } 189 } 190 base::Fclose(fp); 191 } 192#endif 193 return result; 194} 195 196#endif // V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 197 198#if V8_HOST_ARCH_MIPS 199int __detect_fp64_mode(void) { 200 double result = 0; 201 // Bit representation of (double)1 is 0x3FF0000000000000. 202 __asm__ volatile( 203 ".set push\n\t" 204 ".set noreorder\n\t" 205 ".set oddspreg\n\t" 206 "lui $t0, 0x3FF0\n\t" 207 "ldc1 $f0, %0\n\t" 208 "mtc1 $t0, $f1\n\t" 209 "sdc1 $f0, %0\n\t" 210 ".set pop\n\t" 211 : "+m"(result) 212 : 213 : "t0", "$f0", "$f1", "memory"); 214 215 return !(result == 1); 216} 217 218 219int __detect_mips_arch_revision(void) { 220 // TODO(dusmil): Do the specific syscall as soon as it is implemented in mips 221 // kernel. 222 uint32_t result = 0; 223 __asm__ volatile( 224 "move $v0, $zero\n\t" 225 // Encoding for "addi $v0, $v0, 1" on non-r6, 226 // which is encoding for "bovc $v0, %v0, 1" on r6. 227 // Use machine code directly to avoid compilation errors with different 228 // toolchains and maintain compatibility. 229 ".word 0x20420001\n\t" 230 "sw $v0, %0\n\t" 231 : "=m"(result) 232 : 233 : "v0", "memory"); 234 // Result is 0 on r6 architectures, 1 on other architecture revisions. 235 // Fall-back to the least common denominator which is mips32 revision 1. 236 return result ? 1 : 6; 237} 238#endif // V8_HOST_ARCH_MIPS 239 240// Extract the information exposed by the kernel via /proc/cpuinfo. 241class CPUInfo final { 242 public: 243 CPUInfo() : datalen_(0) { 244 // Get the size of the cpuinfo file by reading it until the end. This is 245 // required because files under /proc do not always return a valid size 246 // when using fseek(0, SEEK_END) + ftell(). Nor can the be mmap()-ed. 247 static const char PATHNAME[] = "/proc/cpuinfo"; 248 FILE* fp = base::Fopen(PATHNAME, "r"); 249 if (fp != nullptr) { 250 for (;;) { 251 char buffer[256]; 252 size_t n = fread(buffer, 1, sizeof(buffer), fp); 253 if (n == 0) { 254 break; 255 } 256 datalen_ += n; 257 } 258 base::Fclose(fp); 259 } 260 261 // Read the contents of the cpuinfo file. 262 data_ = new char[datalen_ + 1]; 263 fp = base::Fopen(PATHNAME, "r"); 264 if (fp != nullptr) { 265 for (size_t offset = 0; offset < datalen_; ) { 266 size_t n = fread(data_ + offset, 1, datalen_ - offset, fp); 267 if (n == 0) { 268 break; 269 } 270 offset += n; 271 } 272 base::Fclose(fp); 273 } 274 275 // Zero-terminate the data. 276 data_[datalen_] = '\0'; 277 } 278 279 ~CPUInfo() { 280 delete[] data_; 281 } 282 283 // Extract the content of a the first occurrence of a given field in 284 // the content of the cpuinfo file and return it as a heap-allocated 285 // string that must be freed by the caller using delete[]. 286 // Return nullptr if not found. 287 char* ExtractField(const char* field) const { 288 DCHECK_NOT_NULL(field); 289 290 // Look for first field occurrence, and ensure it starts the line. 291 size_t fieldlen = strlen(field); 292 char* p = data_; 293 for (;;) { 294 p = strstr(p, field); 295 if (p == nullptr) { 296 return nullptr; 297 } 298 if (p == data_ || p[-1] == '\n') { 299 break; 300 } 301 p += fieldlen; 302 } 303 304 // Skip to the first colon followed by a space. 305 p = strchr(p + fieldlen, ':'); 306 if (p == nullptr || !isspace(p[1])) { 307 return nullptr; 308 } 309 p += 2; 310 311 // Find the end of the line. 312 char* q = strchr(p, '\n'); 313 if (q == nullptr) { 314 q = data_ + datalen_; 315 } 316 317 // Copy the line into a heap-allocated buffer. 318 size_t len = q - p; 319 char* result = new char[len + 1]; 320 if (result != nullptr) { 321 memcpy(result, p, len); 322 result[len] = '\0'; 323 } 324 return result; 325 } 326 327 private: 328 char* data_; 329 size_t datalen_; 330}; 331 332// Checks that a space-separated list of items contains one given 'item'. 333static bool HasListItem(const char* list, const char* item) { 334 ssize_t item_len = strlen(item); 335 const char* p = list; 336 if (p != nullptr) { 337 while (*p != '\0') { 338 // Skip whitespace. 339 while (isspace(*p)) ++p; 340 341 // Find end of current list item. 342 const char* q = p; 343 while (*q != '\0' && !isspace(*q)) ++q; 344 345 if (item_len == q - p && memcmp(p, item, item_len) == 0) { 346 return true; 347 } 348 349 // Skip to next item. 350 p = q; 351 } 352 } 353 return false; 354} 355 356#endif // V8_OS_LINUX 357 358#endif // V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 || 359 // V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64 || V8_HOST_ARCH_RISCV64 360 361#if defined(V8_OS_STARBOARD) 362 363bool CPU::StarboardDetectCPU() { 364 SbCPUFeatures features; 365 if (!SbCPUFeaturesGet(&features)) { 366 return false; 367 } 368 architecture_ = features.arm.architecture_generation; 369 switch (features.architecture) { 370 case kSbCPUFeaturesArchitectureArm: 371 case kSbCPUFeaturesArchitectureArm64: 372 has_neon_ = features.arm.has_neon; 373 has_thumb2_ = features.arm.has_thumb2; 374 has_vfp_ = features.arm.has_vfp; 375 has_vfp3_ = features.arm.has_vfp3; 376 has_vfp3_d32_ = features.arm.has_vfp3_d32; 377 has_idiva_ = features.arm.has_idiva; 378 break; 379 case kSbCPUFeaturesArchitectureX86: 380 case kSbCPUFeaturesArchitectureX86_64: 381 // Following flags are mandatory for V8 382 has_cmov_ = features.x86.has_cmov; 383 has_sse2_ = features.x86.has_sse2; 384 // These flags are optional 385 has_sse3_ = features.x86.has_sse3; 386 has_ssse3_ = features.x86.has_ssse3; 387 has_sse41_ = features.x86.has_sse41; 388 has_sahf_ = features.x86.has_sahf; 389 has_avx_ = features.x86.has_avx; 390 has_avx2_ = features.x86.has_avx2; 391 has_fma3_ = features.x86.has_fma3; 392 has_bmi1_ = features.x86.has_bmi1; 393 has_bmi2_ = features.x86.has_bmi2; 394 has_lzcnt_ = features.x86.has_lzcnt; 395 has_popcnt_ = features.x86.has_popcnt; 396 break; 397 default: 398 return false; 399 } 400 401 return true; 402} 403 404#endif 405 406CPU::CPU() 407 : stepping_(0), 408 model_(0), 409 ext_model_(0), 410 family_(0), 411 ext_family_(0), 412 type_(0), 413 implementer_(0), 414 architecture_(0), 415 variant_(-1), 416 part_(0), 417 icache_line_size_(kUnknownCacheLineSize), 418 dcache_line_size_(kUnknownCacheLineSize), 419 num_virtual_address_bits_(kUnknownNumVirtualAddressBits), 420 has_fpu_(false), 421 has_cmov_(false), 422 has_sahf_(false), 423 has_mmx_(false), 424 has_sse_(false), 425 has_sse2_(false), 426 has_sse3_(false), 427 has_ssse3_(false), 428 has_sse41_(false), 429 has_sse42_(false), 430 is_atom_(false), 431 has_osxsave_(false), 432 has_avx_(false), 433 has_avx2_(false), 434 has_fma3_(false), 435 has_bmi1_(false), 436 has_bmi2_(false), 437 has_lzcnt_(false), 438 has_popcnt_(false), 439 has_idiva_(false), 440 has_neon_(false), 441 has_thumb2_(false), 442 has_vfp_(false), 443 has_vfp3_(false), 444 has_vfp3_d32_(false), 445 has_jscvt_(false), 446 is_fp64_mode_(false), 447 has_non_stop_time_stamp_counter_(false), 448 is_running_in_vm_(false), 449 has_msa_(false), 450 has_rvv_(false) { 451 memcpy(vendor_, "Unknown", 8); 452 453#if defined(V8_OS_STARBOARD) 454 if (StarboardDetectCPU()) { 455 return; 456 } 457#endif 458 459#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 460 int cpu_info[4]; 461 462 // __cpuid with an InfoType argument of 0 returns the number of 463 // valid Ids in CPUInfo[0] and the CPU identification string in 464 // the other three array elements. The CPU identification string is 465 // not in linear order. The code below arranges the information 466 // in a human readable form. The human readable order is CPUInfo[1] | 467 // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped 468 // before using memcpy to copy these three array elements to cpu_string. 469 __cpuid(cpu_info, 0); 470 unsigned num_ids = cpu_info[0]; 471 std::swap(cpu_info[2], cpu_info[3]); 472 memcpy(vendor_, cpu_info + 1, 12); 473 vendor_[12] = '\0'; 474 475 // Interpret CPU feature information. 476 if (num_ids > 0) { 477 __cpuid(cpu_info, 1); 478 479 int cpu_info7[4] = {0}; 480 if (num_ids >= 7) { 481 __cpuid(cpu_info7, 7); 482 } 483 484 stepping_ = cpu_info[0] & 0xF; 485 model_ = ((cpu_info[0] >> 4) & 0xF) + ((cpu_info[0] >> 12) & 0xF0); 486 family_ = (cpu_info[0] >> 8) & 0xF; 487 type_ = (cpu_info[0] >> 12) & 0x3; 488 ext_model_ = (cpu_info[0] >> 16) & 0xF; 489 ext_family_ = (cpu_info[0] >> 20) & 0xFF; 490 has_fpu_ = (cpu_info[3] & 0x00000001) != 0; 491 has_cmov_ = (cpu_info[3] & 0x00008000) != 0; 492 has_mmx_ = (cpu_info[3] & 0x00800000) != 0; 493 has_sse_ = (cpu_info[3] & 0x02000000) != 0; 494 has_sse2_ = (cpu_info[3] & 0x04000000) != 0; 495 has_sse3_ = (cpu_info[2] & 0x00000001) != 0; 496 has_ssse3_ = (cpu_info[2] & 0x00000200) != 0; 497 has_sse41_ = (cpu_info[2] & 0x00080000) != 0; 498 has_sse42_ = (cpu_info[2] & 0x00100000) != 0; 499 has_popcnt_ = (cpu_info[2] & 0x00800000) != 0; 500 has_osxsave_ = (cpu_info[2] & 0x08000000) != 0; 501 has_avx_ = (cpu_info[2] & 0x10000000) != 0; 502 has_avx2_ = (cpu_info7[1] & 0x00000020) != 0; 503 has_fma3_ = (cpu_info[2] & 0x00001000) != 0; 504 // CET shadow stack feature flag. See 505 // https://en.wikipedia.org/wiki/CPUID#EAX=7,_ECX=0:_Extended_Features 506 has_cetss_ = (cpu_info7[2] & 0x00000080) != 0; 507 // "Hypervisor Present Bit: Bit 31 of ECX of CPUID leaf 0x1." 508 // See https://lwn.net/Articles/301888/ 509 // This is checking for any hypervisor. Hypervisors may choose not to 510 // announce themselves. Hypervisors trap CPUID and sometimes return 511 // different results to underlying hardware. 512 is_running_in_vm_ = (cpu_info[2] & 0x80000000) != 0; 513 514 if (family_ == 0x6) { 515 switch (model_) { 516 case 0x1C: // SLT 517 case 0x26: 518 case 0x36: 519 case 0x27: 520 case 0x35: 521 case 0x37: // SLM 522 case 0x4A: 523 case 0x4D: 524 case 0x4C: // AMT 525 case 0x6E: 526 is_atom_ = true; 527 } 528 } 529 } 530 531 // There are separate feature flags for VEX-encoded GPR instructions. 532 if (num_ids >= 7) { 533 __cpuid(cpu_info, 7); 534 has_bmi1_ = (cpu_info[1] & 0x00000008) != 0; 535 has_bmi2_ = (cpu_info[1] & 0x00000100) != 0; 536 } 537 538 // Query extended IDs. 539 __cpuid(cpu_info, 0x80000000); 540 unsigned num_ext_ids = cpu_info[0]; 541 542 // Interpret extended CPU feature information. 543 if (num_ext_ids > 0x80000000) { 544 __cpuid(cpu_info, 0x80000001); 545 has_lzcnt_ = (cpu_info[2] & 0x00000020) != 0; 546 // SAHF must be probed in long mode. 547 has_sahf_ = (cpu_info[2] & 0x00000001) != 0; 548 } 549 550 // Check if CPU has non stoppable time stamp counter. 551 const unsigned parameter_containing_non_stop_time_stamp_counter = 0x80000007; 552 if (num_ext_ids >= parameter_containing_non_stop_time_stamp_counter) { 553 __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); 554 has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; 555 } 556 557 const unsigned virtual_physical_address_bits = 0x80000008; 558 if (num_ext_ids >= virtual_physical_address_bits) { 559 __cpuid(cpu_info, virtual_physical_address_bits); 560 num_virtual_address_bits_ = (cpu_info[0] >> 8) & 0xff; 561 } 562 563 // This logic is replicated from cpu.cc present in chromium.src 564 if (!has_non_stop_time_stamp_counter_ && is_running_in_vm_) { 565 int cpu_info_hv[4] = {}; 566 __cpuid(cpu_info_hv, 0x40000000); 567 if (cpu_info_hv[1] == 0x7263694D && // Micr 568 cpu_info_hv[2] == 0x666F736F && // osof 569 cpu_info_hv[3] == 0x76482074) { // t Hv 570 // If CPUID says we have a variant TSC and a hypervisor has identified 571 // itself and the hypervisor says it is Microsoft Hyper-V, then treat 572 // TSC as invariant. 573 // 574 // Microsoft Hyper-V hypervisor reports variant TSC as there are some 575 // scenarios (eg. VM live migration) where the TSC is variant, but for 576 // our purposes we can treat it as invariant. 577 has_non_stop_time_stamp_counter_ = true; 578 } 579 } 580#elif V8_HOST_ARCH_ARM 581 582#if V8_OS_LINUX 583 584 CPUInfo cpu_info; 585 586 // Extract implementor from the "CPU implementer" field. 587 char* implementer = cpu_info.ExtractField("CPU implementer"); 588 if (implementer != nullptr) { 589 char* end; 590 implementer_ = strtol(implementer, &end, 0); 591 if (end == implementer) { 592 implementer_ = 0; 593 } 594 delete[] implementer; 595 } 596 597 char* variant = cpu_info.ExtractField("CPU variant"); 598 if (variant != nullptr) { 599 char* end; 600 variant_ = strtol(variant, &end, 0); 601 if (end == variant) { 602 variant_ = -1; 603 } 604 delete[] variant; 605 } 606 607 // Extract part number from the "CPU part" field. 608 char* part = cpu_info.ExtractField("CPU part"); 609 if (part != nullptr) { 610 char* end; 611 part_ = strtol(part, &end, 0); 612 if (end == part) { 613 part_ = 0; 614 } 615 delete[] part; 616 } 617 618 // Extract architecture from the "CPU Architecture" field. 619 // The list is well-known, unlike the the output of 620 // the 'Processor' field which can vary greatly. 621 // See the definition of the 'proc_arch' array in 622 // $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in 623 // same file. 624 char* architecture = cpu_info.ExtractField("CPU architecture"); 625 if (architecture != nullptr) { 626 char* end; 627 architecture_ = strtol(architecture, &end, 10); 628 if (end == architecture) { 629 // Kernels older than 3.18 report "CPU architecture: AArch64" on ARMv8. 630 if (strcmp(architecture, "AArch64") == 0) { 631 architecture_ = 8; 632 } else { 633 architecture_ = 0; 634 } 635 } 636 delete[] architecture; 637 638 // Unfortunately, it seems that certain ARMv6-based CPUs 639 // report an incorrect architecture number of 7! 640 // 641 // See http://code.google.com/p/android/issues/detail?id=10812 642 // 643 // We try to correct this by looking at the 'elf_platform' 644 // field reported by the 'Processor' field, which is of the 645 // form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for 646 // an ARMv6-one. For example, the Raspberry Pi is one popular 647 // ARMv6 device that reports architecture 7. 648 if (architecture_ == 7) { 649 char* processor = cpu_info.ExtractField("Processor"); 650 if (HasListItem(processor, "(v6l)")) { 651 architecture_ = 6; 652 } 653 delete[] processor; 654 } 655 656 // elf_platform moved to the model name field in Linux v3.8. 657 if (architecture_ == 7) { 658 char* processor = cpu_info.ExtractField("model name"); 659 if (HasListItem(processor, "(v6l)")) { 660 architecture_ = 6; 661 } 662 delete[] processor; 663 } 664 } 665 666 // Try to extract the list of CPU features from ELF hwcaps. 667 uint32_t hwcaps = ReadELFHWCaps(); 668 if (hwcaps != 0) { 669 has_idiva_ = (hwcaps & HWCAP_IDIVA) != 0; 670 has_neon_ = (hwcaps & HWCAP_NEON) != 0; 671 has_vfp_ = (hwcaps & HWCAP_VFP) != 0; 672 has_vfp3_ = (hwcaps & (HWCAP_VFPv3 | HWCAP_VFPv3D16 | HWCAP_VFPv4)) != 0; 673 has_vfp3_d32_ = (has_vfp3_ && ((hwcaps & HWCAP_VFPv3D16) == 0 || 674 (hwcaps & HWCAP_VFPD32) != 0)); 675 } else { 676 // Try to fallback to "Features" CPUInfo field. 677 char* features = cpu_info.ExtractField("Features"); 678 has_idiva_ = HasListItem(features, "idiva"); 679 has_neon_ = HasListItem(features, "neon"); 680 has_thumb2_ = HasListItem(features, "thumb2"); 681 has_vfp_ = HasListItem(features, "vfp"); 682 if (HasListItem(features, "vfpv3d16")) { 683 has_vfp3_ = true; 684 } else if (HasListItem(features, "vfpv3")) { 685 has_vfp3_ = true; 686 has_vfp3_d32_ = true; 687 } 688 delete[] features; 689 } 690 691 // Some old kernels will report vfp not vfpv3. Here we make an attempt 692 // to detect vfpv3 by checking for vfp *and* neon, since neon is only 693 // available on architectures with vfpv3. Checking neon on its own is 694 // not enough as it is possible to have neon without vfp. 695 if (has_vfp_ && has_neon_) { 696 has_vfp3_ = true; 697 } 698 699 // VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6. 700 if (architecture_ < 7 && has_vfp3_) { 701 architecture_ = 7; 702 } 703 704 // ARMv7 implies Thumb2. 705 if (architecture_ >= 7) { 706 has_thumb2_ = true; 707 } 708 709 // The earliest architecture with Thumb2 is ARMv6T2. 710 if (has_thumb2_ && architecture_ < 6) { 711 architecture_ = 6; 712 } 713 714 // We don't support any FPUs other than VFP. 715 has_fpu_ = has_vfp_; 716 717#elif V8_OS_QNX 718 719 uint32_t cpu_flags = SYSPAGE_ENTRY(cpuinfo)->flags; 720 if (cpu_flags & ARM_CPU_FLAG_V7) { 721 architecture_ = 7; 722 has_thumb2_ = true; 723 } else if (cpu_flags & ARM_CPU_FLAG_V6) { 724 architecture_ = 6; 725 // QNX doesn't say if Thumb2 is available. 726 // Assume false for the architectures older than ARMv7. 727 } 728 DCHECK_GE(architecture_, 6); 729 has_fpu_ = (cpu_flags & CPU_FLAG_FPU) != 0; 730 has_vfp_ = has_fpu_; 731 if (cpu_flags & ARM_CPU_FLAG_NEON) { 732 has_neon_ = true; 733 has_vfp3_ = has_vfp_; 734#ifdef ARM_CPU_FLAG_VFP_D32 735 has_vfp3_d32_ = (cpu_flags & ARM_CPU_FLAG_VFP_D32) != 0; 736#endif 737 } 738 has_idiva_ = (cpu_flags & ARM_CPU_FLAG_IDIV) != 0; 739 740#endif // V8_OS_LINUX 741 742#elif V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64 743 744 // Simple detection of FPU at runtime for Linux. 745 // It is based on /proc/cpuinfo, which reveals hardware configuration 746 // to user-space applications. According to MIPS (early 2010), no similar 747 // facility is universally available on the MIPS architectures, 748 // so it's up to individual OSes to provide such. 749 CPUInfo cpu_info; 750 char* cpu_model = cpu_info.ExtractField("cpu model"); 751 has_fpu_ = HasListItem(cpu_model, "FPU"); 752 char* ASEs = cpu_info.ExtractField("ASEs implemented"); 753 has_msa_ = HasListItem(ASEs, "msa"); 754 delete[] cpu_model; 755 delete[] ASEs; 756#ifdef V8_HOST_ARCH_MIPS 757 is_fp64_mode_ = __detect_fp64_mode(); 758 architecture_ = __detect_mips_arch_revision(); 759#endif 760 761#elif V8_HOST_ARCH_ARM64 762#ifdef V8_OS_WIN 763 // Windows makes high-resolution thread timing information available in 764 // user-space. 765 has_non_stop_time_stamp_counter_ = true; 766 767 // Defined in winnt.h, but only in 10.0.20348.0 version of the Windows SDK. 768 // Copy the value here to support older versions as well. 769#if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) 770 constexpr int PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44; 771#endif 772 773 has_jscvt_ = 774 IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); 775 776#elif V8_OS_LINUX 777 // Try to extract the list of CPU features from ELF hwcaps. 778 uint32_t hwcaps = ReadELFHWCaps(); 779 if (hwcaps != 0) { 780 has_jscvt_ = (hwcaps & HWCAP_JSCVT) != 0; 781 } else { 782 // Try to fallback to "Features" CPUInfo field 783 CPUInfo cpu_info; 784 char* features = cpu_info.ExtractField("Features"); 785 has_jscvt_ = HasListItem(features, "jscvt"); 786 delete[] features; 787 } 788#elif V8_OS_DARWIN 789 // ARM64 Macs always have JSCVT. 790 has_jscvt_ = true; 791#endif // V8_OS_WIN 792 793#elif V8_HOST_ARCH_PPC || V8_HOST_ARCH_PPC64 794 795#ifndef USE_SIMULATOR 796#if V8_OS_LINUX 797 // Read processor info from /proc/self/auxv. 798 char* auxv_cpu_type = nullptr; 799 FILE* fp = base::Fopen("/proc/self/auxv", "r"); 800 if (fp != nullptr) { 801#if V8_TARGET_ARCH_PPC64 802 Elf64_auxv_t entry; 803#else 804 Elf32_auxv_t entry; 805#endif 806 for (;;) { 807 size_t n = fread(&entry, sizeof(entry), 1, fp); 808 if (n == 0 || entry.a_type == AT_NULL) { 809 break; 810 } 811 switch (entry.a_type) { 812 case AT_PLATFORM: 813 auxv_cpu_type = reinterpret_cast<char*>(entry.a_un.a_val); 814 break; 815 case AT_ICACHEBSIZE: 816 icache_line_size_ = entry.a_un.a_val; 817 break; 818 case AT_DCACHEBSIZE: 819 dcache_line_size_ = entry.a_un.a_val; 820 break; 821 } 822 } 823 base::Fclose(fp); 824 } 825 826 part_ = -1; 827 if (auxv_cpu_type) { 828 if (strcmp(auxv_cpu_type, "power10") == 0) { 829 part_ = kPPCPower10; 830 } else if (strcmp(auxv_cpu_type, "power9") == 0) { 831 part_ = kPPCPower9; 832 } else if (strcmp(auxv_cpu_type, "power8") == 0) { 833 part_ = kPPCPower8; 834 } else if (strcmp(auxv_cpu_type, "power7") == 0) { 835 part_ = kPPCPower7; 836 } else if (strcmp(auxv_cpu_type, "power6") == 0) { 837 part_ = kPPCPower6; 838 } else if (strcmp(auxv_cpu_type, "power5") == 0) { 839 part_ = kPPCPower5; 840 } else if (strcmp(auxv_cpu_type, "ppc970") == 0) { 841 part_ = kPPCG5; 842 } else if (strcmp(auxv_cpu_type, "ppc7450") == 0) { 843 part_ = kPPCG4; 844 } else if (strcmp(auxv_cpu_type, "pa6t") == 0) { 845 part_ = kPPCPA6T; 846 } 847 } 848 849#elif V8_OS_AIX 850 switch (_system_configuration.implementation) { 851 case POWER_10: 852 part_ = kPPCPower10; 853 break; 854 case POWER_9: 855 part_ = kPPCPower9; 856 break; 857 case POWER_8: 858 part_ = kPPCPower8; 859 break; 860 case POWER_7: 861 part_ = kPPCPower7; 862 break; 863 case POWER_6: 864 part_ = kPPCPower6; 865 break; 866 case POWER_5: 867 part_ = kPPCPower5; 868 break; 869 } 870#endif // V8_OS_AIX 871#endif // !USE_SIMULATOR 872 873#elif V8_HOST_ARCH_RISCV64 874 CPUInfo cpu_info; 875 char* features = cpu_info.ExtractField("isa"); 876 877 if (HasListItem(features, "rv64imafdc")) { 878 has_fpu_ = true; 879 } 880 if (HasListItem(features, "rv64imafdcv")) { 881 has_fpu_ = true; 882 has_rvv_ = true; 883 } 884#endif // V8_HOST_ARCH_RISCV64 885} 886 887} // namespace base 888} // namespace v8 889