1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
/*
* Runtime CPU detection for ARM
* (C) 2009,2010,2013,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/cpuid.h>
#include <botan/internal/os_utils.h>
#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
/*
* On ARM, use getauxval if available, otherwise fall back to
* running probe functions with a SIGILL handler.
*/
#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
#include <sys/auxv.h>
#endif
#endif
namespace Botan {
#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
uint64_t CPUID::detect_cpu_features(size_t* cache_line_size)
{
uint64_t detected_features = 0;
#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
/*
* On systems with getauxval these bits should normally be defined
* in bits/auxv.h but some buggy? glibc installs seem to miss them.
* These following values are all fixed, for the Linux ELF format,
* so we just hardcode them in ARM_hwcap_bit enum.
*/
enum ARM_hwcap_bit {
#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
NEON_bit = (1 << 12),
AES_bit = (1 << 0),
PMULL_bit = (1 << 1),
SHA1_bit = (1 << 2),
SHA2_bit = (1 << 3),
ARCH_hwcap_neon = 16, // AT_HWCAP
ARCH_hwcap_crypto = 26, // AT_HWCAP2
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
NEON_bit = (1 << 1),
AES_bit = (1 << 3),
PMULL_bit = (1 << 4),
SHA1_bit = (1 << 5),
SHA2_bit = (1 << 6),
ARCH_hwcap_neon = 16, // AT_HWCAP
ARCH_hwcap_crypto = 16, // AT_HWCAP
#endif
};
const unsigned long hwcap_neon = ::getauxval(ARM_hwcap_bit::ARCH_hwcap_neon);
if(hwcap_neon & ARM_hwcap_bit::NEON_bit)
detected_features |= CPUID::CPUID_ARM_NEON_BIT;
/*
On aarch64 this ends up calling getauxval twice with AT_HWCAP
It doesn't seem worth optimizing this out, since getauxval is
just reading a field in the ELF header.
*/
const unsigned long hwcap_crypto = ::getauxval(ARM_hwcap_bit::ARCH_hwcap_crypto);
if(hwcap_crypto & ARM_hwcap_bit::AES_bit)
detected_features |= CPUID::CPUID_ARM_AES_BIT;
if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit)
detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit)
detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit)
detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
#if defined(AT_DCACHEBSIZE)
const unsigned long dcache_line = ::getauxval(AT_DCACHEBSIZE);
// plausibility check
if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128)
*cache_line_size = static_cast<size_t>(dcache_line);
#endif
#else
// No getauxval API available, fall back on probe functions
// TODO: probe functions
#endif
return detected_features;
}
#endif
}
|