Skip to content

Commit 429f929

Browse files
committed
std_detect: Support run-time detection on OpenBSD using elf_aux_info
1 parent caccb4d commit 429f929

File tree

7 files changed

+152
-7
lines changed

7 files changed

+152
-7
lines changed

library/std_detect/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ crate from working on applications in which `std` is not available.
6666

6767
* FreeBSD:
6868
* `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF
69-
auxiliary vectors using `sysctl`.
69+
auxiliary vectors using `elf_aux_info`.
7070
* `arm64`: run-time feature detection is implemented by directly querying `mrs`.
7171

7272
* OpenBSD:
73+
* `arm32`, `powerpc64`: `std_detect` supports these on OpenBSD by querying ELF
74+
auxiliary vectors using `elf_aux_info`.
7375
* `arm64`: run-time feature detection is implemented by querying `sysctl`.
7476

7577
* Windows:

library/std_detect/src/detect/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ cfg_select! {
6161
#[path = "os/freebsd/mod.rs"]
6262
mod os;
6363
}
64-
all(target_os = "openbsd", target_arch = "aarch64", feature = "libc") => {
64+
all(target_os = "openbsd", feature = "libc") => {
6565
#[allow(dead_code)] // we don't use code that calls the mrs instruction.
66+
#[cfg(target_arch = "aarch64")]
6667
#[path = "os/aarch64.rs"]
6768
mod aarch64;
68-
#[path = "os/openbsd/aarch64.rs"]
69+
#[path = "os/openbsd/mod.rs"]
6970
mod os;
7071
}
7172
all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")) => {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! Run-time feature detection for ARM on OpenBSD
2+
3+
use super::auxvec;
4+
use crate::detect::{Feature, cache};
5+
6+
// Defined in machine/elf.h.
7+
// https://github.com/openbsd/src/blob/master/sys/arch/arm/include/elf.h
8+
const HWCAP_NEON: usize = 0x00001000;
9+
const HWCAP2_AES: usize = 0x00000001;
10+
const HWCAP2_PMULL: usize = 0x00000002;
11+
const HWCAP2_SHA1: usize = 0x00000004;
12+
const HWCAP2_SHA2: usize = 0x00000008;
13+
const HWCAP2_CRC32: usize = 0x00000010;
14+
15+
/// Try to read the features from the auxiliary vector
16+
pub(crate) fn detect_features() -> cache::Initializer {
17+
let mut value = cache::Initializer::default();
18+
let enable_feature = |value: &mut cache::Initializer, f, enable| {
19+
if enable {
20+
value.set(f as u32);
21+
}
22+
};
23+
24+
if let Ok(auxv) = auxvec::auxv() {
25+
enable_feature(&mut value, Feature::neon, auxv.hwcap & HWCAP_NEON != 0);
26+
enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & HWCAP2_PMULL != 0);
27+
enable_feature(&mut value, Feature::crc, auxv.hwcap2 & HWCAP2_CRC32 != 0);
28+
enable_feature(&mut value, Feature::aes, auxv.hwcap2 & HWCAP2_AES != 0);
29+
// SHA2 requires SHA1 & SHA2 features
30+
let sha1 = auxv.hwcap2 & HWCAP2_SHA1 != 0;
31+
let sha2 = auxv.hwcap2 & HWCAP2_SHA2 != 0;
32+
enable_feature(&mut value, Feature::sha2, sha1 && sha2);
33+
return value;
34+
}
35+
value
36+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! Parses ELF auxiliary vectors.
2+
#![cfg_attr(
3+
any(
4+
target_arch = "aarch64",
5+
target_arch = "arm",
6+
target_arch = "powerpc64",
7+
target_arch = "riscv64"
8+
),
9+
allow(dead_code)
10+
)]
11+
12+
/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
13+
///
14+
/// If an entry cannot be read all the bits in the bitfield are set to zero.
15+
/// This should be interpreted as all the features being disabled.
16+
#[derive(Debug, Copy, Clone)]
17+
pub(crate) struct AuxVec {
18+
pub hwcap: usize,
19+
pub hwcap2: usize,
20+
}
21+
22+
/// ELF Auxiliary Vector
23+
///
24+
/// The auxiliary vector is a memory region in a running ELF program's stack
25+
/// composed of (key: usize, value: usize) pairs.
26+
///
27+
/// The keys used in the aux vector are platform dependent. For OpenBSD, they are
28+
/// defined in [machine/elf.h][elfh]. The hardware capabilities of a given CPU
29+
/// can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys.
30+
///
31+
/// Note that run-time feature detection is not invoked for features that can
32+
/// be detected at compile-time.
33+
///
34+
/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/arm64/include/elf.h
35+
/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/arm/include/elf.h
36+
/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/powerpc64/include/elf.h
37+
pub(crate) fn auxv() -> Result<AuxVec, ()> {
38+
let hwcap = archauxv(libc::AT_HWCAP);
39+
let hwcap2 = archauxv(libc::AT_HWCAP2);
40+
// Zero could indicate that no features were detected, but it's also used to
41+
// indicate an error. In particular, on many platforms AT_HWCAP2 will be
42+
// legitimately zero, since it contains the most recent feature flags.
43+
if hwcap != 0 || hwcap2 != 0 {
44+
return Ok(AuxVec { hwcap, hwcap2 });
45+
}
46+
Err(())
47+
}
48+
49+
/// Tries to read the `key` from the auxiliary vector.
50+
fn archauxv(key: libc::c_int) -> usize {
51+
const OUT_LEN: libc::c_int = core::mem::size_of::<libc::c_ulong>() as libc::c_int;
52+
let mut out: libc::c_ulong = 0;
53+
unsafe {
54+
let res =
55+
libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN);
56+
// If elf_aux_info fails, `out` will be left at zero (which is the proper default value).
57+
debug_assert!(res == 0 || out == 0);
58+
}
59+
out as usize
60+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! Run-time feature detection on OpenBSD
2+
3+
mod auxvec;
4+
5+
cfg_select! {
6+
target_arch = "aarch64" => {
7+
mod aarch64;
8+
pub(crate) use self::aarch64::detect_features;
9+
}
10+
target_arch = "arm" => {
11+
mod arm;
12+
pub(crate) use self::arm::detect_features;
13+
}
14+
target_arch = "powerpc64" => {
15+
mod powerpc;
16+
pub(crate) use self::powerpc::detect_features;
17+
}
18+
_ => {
19+
use crate::detect::cache;
20+
/// Performs run-time feature detection.
21+
pub(crate) fn detect_features() -> cache::Initializer {
22+
cache::Initializer::default()
23+
}
24+
}
25+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Run-time feature detection for PowerPC on OpenBSD.
2+
3+
use super::auxvec;
4+
use crate::detect::{Feature, cache};
5+
6+
pub(crate) fn detect_features() -> cache::Initializer {
7+
let mut value = cache::Initializer::default();
8+
let enable_feature = |value: &mut cache::Initializer, f, enable| {
9+
if enable {
10+
value.set(f as u32);
11+
}
12+
};
13+
14+
if let Ok(auxv) = auxvec::auxv() {
15+
enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0);
16+
enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0);
17+
enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0);
18+
return value;
19+
}
20+
value
21+
}

library/std_detect/tests/cpu-detection.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ fn all() {
4747
}
4848

4949
#[test]
50-
#[cfg(all(target_arch = "arm", target_os = "freebsd"))]
51-
fn arm_freebsd() {
50+
#[cfg(all(target_arch = "arm", any(target_os = "freebsd", target_os = "openbsd")))]
51+
fn arm_bsd() {
5252
println!("neon: {}", is_arm_feature_detected!("neon"));
5353
println!("pmull: {}", is_arm_feature_detected!("pmull"));
5454
println!("crc: {}", is_arm_feature_detected!("crc"));
@@ -320,8 +320,8 @@ fn powerpc_linux() {
320320
}
321321

322322
#[test]
323-
#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd"),))]
324-
fn powerpc64_linux_or_freebsd() {
323+
#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"),))]
324+
fn powerpc64_linux_or_bsd() {
325325
println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
326326
println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
327327
println!("power8: {}", is_powerpc64_feature_detected!("power8"));

0 commit comments

Comments
 (0)