Skip to content

Commit de02c4e

Browse files
committed
Add HWCAP2 support for AArch64.
This doesn't extend the set of recognised features, but corrects some existing ones to refer to HWCAP2. Change-Id: Ic16705bdb9baa4034f926f2a4d5c65a34813bfee
1 parent 8ff3803 commit de02c4e

File tree

7 files changed

+174
-78
lines changed

7 files changed

+174
-78
lines changed

crates/std_detect/src/detect/os/linux/aarch64.rs

Lines changed: 153 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,58 +23,62 @@ pub(crate) fn detect_features() -> cache::Initializer {
2323
/// The names match those used for cpuinfo.
2424
///
2525
/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
26+
#[derive(Debug, Default, PartialEq)]
2627
struct AtHwcap {
27-
fp: bool, // 0
28-
asimd: bool, // 1
29-
// evtstrm: bool, // 2 No LLVM support
30-
aes: bool, // 3
31-
pmull: bool, // 4
32-
sha1: bool, // 5
33-
sha2: bool, // 6
34-
crc32: bool, // 7
35-
atomics: bool, // 8
36-
fphp: bool, // 9
37-
asimdhp: bool, // 10
38-
// cpuid: bool, // 11 No LLVM support
39-
asimdrdm: bool, // 12
40-
jscvt: bool, // 13
41-
fcma: bool, // 14
42-
lrcpc: bool, // 15
43-
dcpop: bool, // 16
44-
sha3: bool, // 17
45-
sm3: bool, // 18
46-
sm4: bool, // 19
47-
asimddp: bool, // 20
48-
sha512: bool, // 21
49-
sve: bool, // 22
50-
fhm: bool, // 23
51-
dit: bool, // 24
52-
uscat: bool, // 25
53-
ilrcpc: bool, // 26
54-
flagm: bool, // 27
55-
ssbs: bool, // 28
56-
sb: bool, // 29
57-
paca: bool, // 30
58-
pacg: bool, // 31
59-
dcpodp: bool, // 32
60-
sve2: bool, // 33
61-
sveaes: bool, // 34
62-
// svepmull: bool, // 35 No LLVM support
63-
svebitperm: bool, // 36
64-
svesha3: bool, // 37
65-
svesm4: bool, // 38
66-
// flagm2: bool, // 39 No LLVM support
67-
frint: bool, // 40
68-
// svei8mm: bool, // 41 See i8mm feature
69-
svef32mm: bool, // 42
70-
svef64mm: bool, // 43
71-
// svebf16: bool, // 44 See bf16 feature
72-
i8mm: bool, // 45
73-
bf16: bool, // 46
74-
// dgh: bool, // 47 No LLVM support
75-
rng: bool, // 48
76-
bti: bool, // 49
77-
mte: bool, // 50
28+
// AT_HWCAP
29+
fp: bool,
30+
asimd: bool,
31+
// evtstrm: No LLVM support.
32+
aes: bool,
33+
pmull: bool,
34+
sha1: bool,
35+
sha2: bool,
36+
crc32: bool,
37+
atomics: bool,
38+
fphp: bool,
39+
asimdhp: bool,
40+
// cpuid: No LLVM support.
41+
asimdrdm: bool,
42+
jscvt: bool,
43+
fcma: bool,
44+
lrcpc: bool,
45+
dcpop: bool,
46+
sha3: bool,
47+
sm3: bool,
48+
sm4: bool,
49+
asimddp: bool,
50+
sha512: bool,
51+
sve: bool,
52+
fhm: bool,
53+
dit: bool,
54+
uscat: bool,
55+
ilrcpc: bool,
56+
flagm: bool,
57+
ssbs: bool,
58+
sb: bool,
59+
paca: bool,
60+
pacg: bool,
61+
62+
// AT_HWCAP2
63+
dcpodp: bool,
64+
sve2: bool,
65+
sveaes: bool,
66+
// svepmull: No LLVM support.
67+
svebitperm: bool,
68+
svesha3: bool,
69+
svesm4: bool,
70+
// flagm2: No LLVM support.
71+
frint: bool,
72+
// svei8mm: See i8mm feature.
73+
svef32mm: bool,
74+
svef64mm: bool,
75+
// svebf16: See bf16 feature.
76+
i8mm: bool,
77+
bf16: bool,
78+
// dgh: No LLVM support.
79+
rng: bool,
80+
bti: bool,
81+
mte: bool,
7882
}
7983

8084
impl From<auxvec::AuxVec> for AtHwcap {
@@ -113,25 +117,25 @@ impl From<auxvec::AuxVec> for AtHwcap {
113117
sb: bit::test(auxv.hwcap, 29),
114118
paca: bit::test(auxv.hwcap, 30),
115119
pacg: bit::test(auxv.hwcap, 31),
116-
dcpodp: bit::test(auxv.hwcap, 32),
117-
sve2: bit::test(auxv.hwcap, 33),
118-
sveaes: bit::test(auxv.hwcap, 34),
119-
// svepmull: bit::test(auxv.hwcap, 35),
120-
svebitperm: bit::test(auxv.hwcap, 36),
121-
svesha3: bit::test(auxv.hwcap, 37),
122-
svesm4: bit::test(auxv.hwcap, 38),
123-
// flagm2: bit::test(auxv.hwcap, 39),
124-
frint: bit::test(auxv.hwcap, 40),
125-
// svei8mm: bit::test(auxv.hwcap, 41),
126-
svef32mm: bit::test(auxv.hwcap, 42),
127-
svef64mm: bit::test(auxv.hwcap, 43),
128-
// svebf16: bit::test(auxv.hwcap, 44),
129-
i8mm: bit::test(auxv.hwcap, 45),
130-
bf16: bit::test(auxv.hwcap, 46),
131-
// dgh: bit::test(auxv.hwcap, 47),
132-
rng: bit::test(auxv.hwcap, 48),
133-
bti: bit::test(auxv.hwcap, 49),
134-
mte: bit::test(auxv.hwcap, 50),
120+
dcpodp: bit::test(auxv.hwcap2, 0),
121+
sve2: bit::test(auxv.hwcap2, 1),
122+
sveaes: bit::test(auxv.hwcap2, 2),
123+
// svepmull: bit::test(auxv.hwcap2, 3),
124+
svebitperm: bit::test(auxv.hwcap2, 4),
125+
svesha3: bit::test(auxv.hwcap2, 5),
126+
svesm4: bit::test(auxv.hwcap2, 6),
127+
// flagm2: bit::test(auxv.hwcap2, 7),
128+
frint: bit::test(auxv.hwcap2, 8),
129+
// svei8mm: bit::test(auxv.hwcap2, 9),
130+
svef32mm: bit::test(auxv.hwcap2, 10),
131+
svef64mm: bit::test(auxv.hwcap2, 11),
132+
// svebf16: bit::test(auxv.hwcap2, 12),
133+
i8mm: bit::test(auxv.hwcap2, 13),
134+
bf16: bit::test(auxv.hwcap2, 14),
135+
// dgh: bit::test(auxv.hwcap2, 15),
136+
rng: bit::test(auxv.hwcap2, 16),
137+
bti: bit::test(auxv.hwcap2, 17),
138+
mte: bit::test(auxv.hwcap2, 18),
135139
}
136140
}
137141
}
@@ -288,3 +292,82 @@ impl AtHwcap {
288292
value
289293
}
290294
}
295+
296+
#[cfg(test)]
297+
mod tests {
298+
use super::auxvec::auxv_from_file;
299+
use super::*;
300+
301+
// The baseline hwcaps used in the (artificial) auxv test files.
302+
fn baseline_hwcaps() -> AtHwcap {
303+
AtHwcap {
304+
fp: true,
305+
asimd: true,
306+
aes: true,
307+
pmull: true,
308+
sha1: true,
309+
sha2: true,
310+
crc32: true,
311+
atomics: true,
312+
fphp: true,
313+
asimdhp: true,
314+
asimdrdm: true,
315+
lrcpc: true,
316+
dcpop: true,
317+
asimddp: true,
318+
ssbs: true,
319+
..AtHwcap::default()
320+
}
321+
}
322+
323+
#[test]
324+
fn linux_empty_hwcap2_aarch64() {
325+
let file = concat!(
326+
env!("CARGO_MANIFEST_DIR"),
327+
"/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv"
328+
);
329+
println!("file: {}", file);
330+
let v = auxv_from_file(file).unwrap();
331+
println!("HWCAP : 0x{:0x}", v.hwcap);
332+
println!("HWCAP2: 0x{:0x}", v.hwcap2);
333+
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
334+
}
335+
#[test]
336+
fn linux_no_hwcap2_aarch64() {
337+
let file = concat!(
338+
env!("CARGO_MANIFEST_DIR"),
339+
"/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"
340+
);
341+
println!("file: {}", file);
342+
let v = auxv_from_file(file).unwrap();
343+
println!("HWCAP : 0x{:0x}", v.hwcap);
344+
println!("HWCAP2: 0x{:0x}", v.hwcap2);
345+
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
346+
}
347+
#[test]
348+
fn linux_hwcap2_aarch64() {
349+
let file = concat!(
350+
env!("CARGO_MANIFEST_DIR"),
351+
"/src/detect/test_data/linux-hwcap2-aarch64.auxv"
352+
);
353+
println!("file: {}", file);
354+
let v = auxv_from_file(file).unwrap();
355+
println!("HWCAP : 0x{:0x}", v.hwcap);
356+
println!("HWCAP2: 0x{:0x}", v.hwcap2);
357+
assert_eq!(
358+
AtHwcap::from(v),
359+
AtHwcap {
360+
// Some other HWCAP bits.
361+
paca: true,
362+
pacg: true,
363+
// HWCAP2-only bits.
364+
dcpodp: true,
365+
frint: true,
366+
rng: true,
367+
bti: true,
368+
mte: true,
369+
..baseline_hwcaps()
370+
}
371+
);
372+
}
373+
}

crates/std_detect/src/detect/os/linux/auxvec.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub(crate) const AT_NULL: usize = 0;
77
pub(crate) const AT_HWCAP: usize = 16;
88
/// Key to access the CPU Hardware capabilities 2 bitfield.
99
#[cfg(any(
10+
target_arch = "aarch64",
1011
target_arch = "arm",
1112
target_arch = "powerpc",
1213
target_arch = "powerpc64"
@@ -21,6 +22,7 @@ pub(crate) const AT_HWCAP2: usize = 26;
2122
pub(crate) struct AuxVec {
2223
pub hwcap: usize,
2324
#[cfg(any(
25+
target_arch = "aarch64",
2426
target_arch = "arm",
2527
target_arch = "powerpc",
2628
target_arch = "powerpc64"
@@ -64,7 +66,6 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
6466
if let Ok(hwcap) = getauxval(AT_HWCAP) {
6567
// Targets with only AT_HWCAP:
6668
#[cfg(any(
67-
target_arch = "aarch64",
6869
target_arch = "riscv32",
6970
target_arch = "riscv64",
7071
target_arch = "mips",
@@ -80,6 +81,7 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
8081

8182
// Targets with AT_HWCAP and AT_HWCAP2:
8283
#[cfg(any(
84+
target_arch = "aarch64",
8385
target_arch = "arm",
8486
target_arch = "powerpc",
8587
target_arch = "powerpc64"
@@ -103,7 +105,6 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
103105
{
104106
// Targets with only AT_HWCAP:
105107
#[cfg(any(
106-
target_arch = "aarch64",
107108
target_arch = "riscv32",
108109
target_arch = "riscv64",
109110
target_arch = "mips",
@@ -120,6 +121,7 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
120121

121122
// Targets with AT_HWCAP and AT_HWCAP2:
122123
#[cfg(any(
124+
target_arch = "aarch64",
123125
target_arch = "arm",
124126
target_arch = "powerpc",
125127
target_arch = "powerpc64"
@@ -170,7 +172,7 @@ fn getauxval(key: usize) -> Result<usize, ()> {
170172
/// Tries to read the auxiliary vector from the `file`. If this fails, this
171173
/// function returns `Err`.
172174
#[cfg(feature = "std_detect_file_io")]
173-
fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
175+
pub(super) fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
174176
let file = super::read_file(file)?;
175177

176178
// See <https://github.com/torvalds/linux/blob/v3.19/include/uapi/linux/auxvec.h>.
@@ -193,7 +195,6 @@ fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
193195
fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
194196
// Targets with only AT_HWCAP:
195197
#[cfg(any(
196-
target_arch = "aarch64",
197198
target_arch = "riscv32",
198199
target_arch = "riscv64",
199200
target_arch = "mips",
@@ -210,6 +211,7 @@ fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
210211
}
211212
// Targets with AT_HWCAP and AT_HWCAP2:
212213
#[cfg(any(
214+
target_arch = "aarch64",
213215
target_arch = "arm",
214216
target_arch = "powerpc",
215217
target_arch = "powerpc64"
@@ -269,7 +271,6 @@ mod tests {
269271
// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
270272
// does not always contain the AT_HWCAP key under qemu.
271273
#[cfg(any(
272-
target_arch = "aarch64",
273274
target_arch = "arm",
274275
target_arch = "powerpc",
275276
target_arch = "powerpc64"
@@ -284,6 +285,7 @@ mod tests {
284285

285286
// Targets with AT_HWCAP and AT_HWCAP2:
286287
#[cfg(any(
288+
target_arch = "aarch64",
287289
target_arch = "arm",
288290
target_arch = "powerpc",
289291
target_arch = "powerpc64"
@@ -331,11 +333,21 @@ mod tests {
331333
}
332334
} else if #[cfg(target_arch = "aarch64")] {
333335
#[test]
334-
fn linux_x64() {
335-
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-x64-i7-6850k.auxv");
336+
fn linux_artificial_aarch64() {
337+
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv");
336338
println!("file: {}", file);
337339
let v = auxv_from_file(file).unwrap();
338-
assert_eq!(v.hwcap, 3219913727);
340+
assert_eq!(v.hwcap, 0x0123456789abcdef);
341+
assert_eq!(v.hwcap2, 0x02468ace13579bdf);
342+
}
343+
#[test]
344+
fn linux_no_hwcap2_aarch64() {
345+
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv");
346+
println!("file: {}", file);
347+
let v = auxv_from_file(file).unwrap();
348+
// An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP.
349+
assert_ne!(v.hwcap, 0);
350+
assert_eq!(v.hwcap2, 0);
339351
}
340352
}
341353
}
@@ -366,6 +378,7 @@ mod tests {
366378

367379
// Targets with AT_HWCAP and AT_HWCAP2:
368380
#[cfg(any(
381+
target_arch = "aarch64",
369382
target_arch = "arm",
370383
target_arch = "powerpc",
371384
target_arch = "powerpc64"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)