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(leaf: 0, eax: &Eax, ebx: &Ebx, ecx: &Ecx, edx: &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(leaf: 1, eax: &Eax, ebx: &Ebx, ecx: &Ecx, edx: &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 | |