1353944Sdim//===-- checksum.cpp --------------------------------------------*- C++ -*-===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim
9353944Sdim#include "checksum.h"
10353944Sdim#include "atomic_helpers.h"
11353944Sdim
12353944Sdim#if defined(__x86_64__) || defined(__i386__)
13353944Sdim#include <cpuid.h>
14353944Sdim#elif defined(__arm__) || defined(__aarch64__)
15353944Sdim#if SCUDO_FUCHSIA
16353944Sdim#include <zircon/features.h>
17353944Sdim#include <zircon/syscalls.h>
18353944Sdim#else
19353944Sdim#include <sys/auxv.h>
20353944Sdim#endif
21353944Sdim#endif
22353944Sdim
23353944Sdimnamespace scudo {
24353944Sdim
25353944SdimChecksum HashAlgorithm = {Checksum::BSD};
26353944Sdim
27353944Sdim#if defined(__x86_64__) || defined(__i386__)
28353944Sdim// i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
29353944Sdim// CRC32 requires the SSE 4.2 instruction set.
30353944Sdim#ifndef bit_SSE4_2
31353944Sdim#define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
32353944Sdim#endif
33353944Sdim
34353944Sdimbool hasHardwareCRC32() {
35353944Sdim  u32 Eax, Ebx = 0, Ecx = 0, Edx = 0;
36353944Sdim  __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
37353944Sdim  const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
38353944Sdim                       (Edx == signature_INTEL_edx) &&
39353944Sdim                       (Ecx == signature_INTEL_ecx);
40353944Sdim  const bool IsAMD = (Ebx == signature_AMD_ebx) && (Edx == signature_AMD_edx) &&
41353944Sdim                     (Ecx == signature_AMD_ecx);
42353944Sdim  if (!IsIntel && !IsAMD)
43353944Sdim    return false;
44353944Sdim  __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
45353944Sdim  return !!(Ecx & bit_SSE4_2);
46353944Sdim}
47353944Sdim#elif defined(__arm__) || defined(__aarch64__)
48353944Sdim#ifndef AT_HWCAP
49353944Sdim#define AT_HWCAP 16
50353944Sdim#endif
51353944Sdim#ifndef HWCAP_CRC32
52353944Sdim#define HWCAP_CRC32 (1U << 7) // HWCAP_CRC32 is missing on older platforms.
53353944Sdim#endif
54353944Sdim
55353944Sdimbool hasHardwareCRC32() {
56353944Sdim#if SCUDO_FUCHSIA
57353944Sdim  u32 HWCap;
58353944Sdim  const zx_status_t Status =
59353944Sdim      zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
60353944Sdim  if (Status != ZX_OK)
61353944Sdim    return false;
62353944Sdim  return !!(HWCap & ZX_ARM64_FEATURE_ISA_CRC32);
63353944Sdim#else
64353944Sdim  return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
65353944Sdim#endif // SCUDO_FUCHSIA
66353944Sdim}
67357095Sdim#else
68357095Sdim// No hardware CRC32 implemented in Scudo for other architectures.
69357095Sdimbool hasHardwareCRC32() { return false; }
70353944Sdim#endif // defined(__x86_64__) || defined(__i386__)
71353944Sdim
72353944Sdim} // namespace scudo
73