1 //===-- checksum.cpp --------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "checksum.h" 10 #include "atomic_helpers.h" 11 #include "chunk.h" 12 13 #if defined(__x86_64__) || defined(__i386__) 14 #include <cpuid.h> 15 #elif defined(__arm__) || defined(__aarch64__) 16 #if SCUDO_FUCHSIA 17 #include <zircon/features.h> 18 #include <zircon/syscalls.h> 19 #else 20 #include <sys/auxv.h> 21 #endif 22 #elif defined(__loongarch__) 23 #include <sys/auxv.h> 24 #endif 25 26 namespace scudo { 27 28 Checksum HashAlgorithm = {Checksum::BSD}; 29 30 #if defined(__x86_64__) || defined(__i386__) 31 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID. 32 // CRC32 requires the SSE 4.2 instruction set. 33 #ifndef bit_SSE4_2 34 #define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. 35 #endif 36 37 #ifndef signature_HYGON_ebx // They are not defined in gcc. 38 // HYGON: "HygonGenuine". 39 #define signature_HYGON_ebx 0x6f677948 40 #define signature_HYGON_edx 0x6e65476e 41 #define signature_HYGON_ecx 0x656e6975 42 #endif 43 44 bool hasHardwareCRC32() { 45 u32 Eax, Ebx = 0, Ecx = 0, Edx = 0; 46 __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx); 47 const bool IsIntel = (Ebx == signature_INTEL_ebx) && 48 (Edx == signature_INTEL_edx) && 49 (Ecx == signature_INTEL_ecx); 50 const bool IsAMD = (Ebx == signature_AMD_ebx) && (Edx == signature_AMD_edx) && 51 (Ecx == signature_AMD_ecx); 52 const bool IsHygon = (Ebx == signature_HYGON_ebx) && 53 (Edx == signature_HYGON_edx) && 54 (Ecx == signature_HYGON_ecx); 55 if (!IsIntel && !IsAMD && !IsHygon) 56 return false; 57 __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx); 58 return !!(Ecx & bit_SSE4_2); 59 } 60 #elif defined(__arm__) || defined(__aarch64__) 61 #ifndef AT_HWCAP 62 #define AT_HWCAP 16 63 #endif 64 #ifndef HWCAP_CRC32 65 #define HWCAP_CRC32 (1U << 7) // HWCAP_CRC32 is missing on older platforms. 66 #endif 67 68 bool hasHardwareCRC32() { 69 #if SCUDO_FUCHSIA 70 u32 HWCap; 71 const zx_status_t Status = 72 zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap); 73 if (Status != ZX_OK) 74 return false; 75 return !!(HWCap & ZX_ARM64_FEATURE_ISA_CRC32); 76 #else 77 return !!(getauxval(AT_HWCAP) & HWCAP_CRC32); 78 #endif // SCUDO_FUCHSIA 79 } 80 #elif defined(__loongarch__) 81 // The definition is only pulled in by <sys/auxv.h> since glibc 2.38, so 82 // supply it if missing. 83 #ifndef HWCAP_LOONGARCH_CRC32 84 #define HWCAP_LOONGARCH_CRC32 (1 << 6) 85 #endif 86 // Query HWCAP for platform capability, according to *Software Development and 87 // Build Convention for LoongArch Architectures* v0.1, Section 9.1. 88 // 89 // Link: 90 // https://github.com/loongson/la-softdev-convention/blob/v0.1/la-softdev-convention.adoc#kernel-development 91 bool hasHardwareCRC32() { 92 return !!(getauxval(AT_HWCAP) & HWCAP_LOONGARCH_CRC32); 93 } 94 #else 95 // No hardware CRC32 implemented in Scudo for other architectures. 96 bool hasHardwareCRC32() { return false; } 97 #endif // defined(__x86_64__) || defined(__i386__) 98 99 } // namespace scudo 100