Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion library/std_detect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ crate from working on applications in which `std` is not available.

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

* OpenBSD:
* `powerpc64`: `std_detect` supports these on OpenBSD by querying ELF auxiliary
vectors using `elf_aux_info`.
* `arm64`: run-time feature detection is implemented by querying `sysctl`.

* Windows:
Expand Down
5 changes: 3 additions & 2 deletions library/std_detect/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ cfg_select! {
#[path = "os/freebsd/mod.rs"]
mod os;
}
all(target_os = "openbsd", target_arch = "aarch64", feature = "libc") => {
all(target_os = "openbsd", feature = "libc") => {
#[allow(dead_code)] // we don't use code that calls the mrs instruction.
#[cfg(target_arch = "aarch64")]
#[path = "os/aarch64.rs"]
mod aarch64;
#[path = "os/openbsd/aarch64.rs"]
#[path = "os/openbsd/mod.rs"]
mod os;
}
all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")) => {
Expand Down
54 changes: 54 additions & 0 deletions library/std_detect/src/detect/os/openbsd/auxvec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Parses ELF auxiliary vectors.
#![cfg_attr(
any(target_arch = "aarch64", target_arch = "powerpc64", target_arch = "riscv64"),
allow(dead_code)
)]

/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
///
/// If an entry cannot be read all the bits in the bitfield are set to zero.
/// This should be interpreted as all the features being disabled.
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
pub hwcap: usize,
pub hwcap2: usize,
}

/// ELF Auxiliary Vector
///
/// The auxiliary vector is a memory region in a running ELF program's stack
/// composed of (key: usize, value: usize) pairs.
///
/// The keys used in the aux vector are platform dependent. For OpenBSD, they are
/// defined in [machine/elf.h][elfh]. The hardware capabilities of a given CPU
/// can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys.
///
/// Note that run-time feature detection is not invoked for features that can
/// be detected at compile-time.
///
/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/arm64/include/elf.h
/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/powerpc64/include/elf.h
pub(crate) fn auxv() -> Result<AuxVec, ()> {
let hwcap = archauxv(libc::AT_HWCAP);
let hwcap2 = archauxv(libc::AT_HWCAP2);
// Zero could indicate that no features were detected, but it's also used to
// indicate an error. In particular, on many platforms AT_HWCAP2 will be
// legitimately zero, since it contains the most recent feature flags.
if hwcap != 0 || hwcap2 != 0 {
return Ok(AuxVec { hwcap, hwcap2 });
}
Err(())
}

/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: libc::c_int) -> usize {
const OUT_LEN: libc::c_int = core::mem::size_of::<libc::c_ulong>() as libc::c_int;
let mut out: libc::c_ulong = 0;
unsafe {
let res =
libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN);
// If elf_aux_info fails, `out` will be left at zero (which is the proper default value).
debug_assert!(res == 0 || out == 0);
}
out as usize
}
21 changes: 21 additions & 0 deletions library/std_detect/src/detect/os/openbsd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Run-time feature detection on OpenBSD

mod auxvec;

cfg_select! {
target_arch = "aarch64" => {
mod aarch64;
pub(crate) use self::aarch64::detect_features;
}
target_arch = "powerpc64" => {
mod powerpc;
pub(crate) use self::powerpc::detect_features;
}
_ => {
use crate::detect::cache;
/// Performs run-time feature detection.
pub(crate) fn detect_features() -> cache::Initializer {
cache::Initializer::default()
}
}
}
21 changes: 21 additions & 0 deletions library/std_detect/src/detect/os/openbsd/powerpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Run-time feature detection for PowerPC on OpenBSD.

use super::auxvec;
use crate::detect::{Feature, cache};

pub(crate) fn detect_features() -> cache::Initializer {
let mut value = cache::Initializer::default();
let enable_feature = |value: &mut cache::Initializer, f, enable| {
if enable {
value.set(f as u32);
}
};

if let Ok(auxv) = auxvec::auxv() {
enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0);
enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0);
enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0);
return value;
}
value
}
7 changes: 5 additions & 2 deletions library/std_detect/tests/cpu-detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,11 @@ fn powerpc_linux() {
}

#[test]
#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd"),))]
fn powerpc64_linux_or_freebsd() {
#[cfg(all(
target_arch = "powerpc64",
any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"),
))]
fn powerpc64_linux_or_bsd() {
println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
println!("power8: {}", is_powerpc64_feature_detected!("power8"));
Expand Down
Loading