Skip to content

Commit 0102817

Browse files
mikignzlbg
miki
authored andcommitted
Add std_detect for FreeBSD armv6, armv7 and powerpc64
1 parent e923c9e commit 0102817

File tree

4 files changed

+148
-0
lines changed

4 files changed

+148
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Run-time feature detection for ARM on FreeBSD
2+
3+
use crate::detect::{Feature, cache};
4+
use super::{auxvec};
5+
6+
/// Performs run-time feature detection.
7+
#[inline]
8+
pub fn check_for(x: Feature) -> bool {
9+
cache::test(x as u32, detect_features)
10+
}
11+
12+
/// Try to read the features from the auxiliary vector
13+
fn detect_features() -> cache::Initializer {
14+
let mut value = cache::Initializer::default();
15+
let enable_feature = |value: &mut cache::Initializer, f, enable| {
16+
if enable {
17+
value.set(f as u32);
18+
}
19+
};
20+
21+
if let Ok(auxv) = auxvec::auxv() {
22+
enable_feature(&mut value, Feature::neon, auxv.hwcap & 0x00001000 != 0);
23+
enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & 0x00000002 != 0);
24+
return value;
25+
}
26+
value
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//! Parses ELF auxiliary vectors.
2+
#![cfg_attr(any(target_arch = "arm", target_arch = "powerpc64"), allow(dead_code))]
3+
4+
/// Key to access the CPU Hardware capabilities bitfield.
5+
pub(crate) const AT_HWCAP: usize = 25;
6+
/// Key to access the CPU Hardware capabilities 2 bitfield.
7+
pub(crate) const AT_HWCAP2: usize = 26;
8+
9+
/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
10+
///
11+
/// If an entry cannot be read all the bits in the bitfield are set to zero.
12+
/// This should be interpreted as all the features being disabled.
13+
#[derive(Debug, Copy, Clone)]
14+
pub(crate) struct AuxVec {
15+
pub hwcap: usize,
16+
pub hwcap2: usize,
17+
}
18+
19+
/// ELF Auxiliary Vector
20+
///
21+
/// The auxiliary vector is a memory region in a running ELF program's stack
22+
/// composed of (key: usize, value: usize) pairs.
23+
///
24+
/// The keys used in the aux vector are platform dependent. For FreeBSD, they are
25+
/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given
26+
/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys.
27+
///
28+
/// Note that run-time feature detection is not invoked for features that can
29+
/// be detected at compile-time.
30+
///
31+
/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
32+
pub(crate) fn auxv() -> Result<AuxVec, ()> {
33+
if let Ok(hwcap) = archauxv(AT_HWCAP) {
34+
if let Ok(hwcap2) = archauxv(AT_HWCAP2) {
35+
if hwcap != 0 && hwcap2 != 0 {
36+
return Ok(AuxVec { hwcap, hwcap2 });
37+
}
38+
}
39+
}
40+
Err(())
41+
}
42+
43+
/// Tries to read the `key` from the auxiliary vector.
44+
fn archauxv(key: usize) -> Result<usize, ()> {
45+
use mem;
46+
47+
#[derive (Copy, Clone)]
48+
#[repr(C)]
49+
pub struct Elf_Auxinfo {
50+
pub a_type: usize,
51+
pub a_un: unnamed,
52+
}
53+
#[derive (Copy, Clone)]
54+
#[repr(C)]
55+
pub union unnamed {
56+
pub a_val: libc::c_long,
57+
pub a_ptr: *mut libc::c_void,
58+
pub a_fcn: Option<unsafe extern "C" fn() -> ()>,
59+
}
60+
61+
let mut auxv: [Elf_Auxinfo; 27] =
62+
[Elf_Auxinfo{a_type: 0, a_un: unnamed{a_val: 0,},}; 27];
63+
64+
let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint;
65+
66+
unsafe {
67+
let mut mib = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_AUXV, libc::getpid()];
68+
69+
let ret = libc::sysctl(mib.as_mut_ptr(),
70+
mib.len() as u32,
71+
&mut auxv as *mut _ as *mut _,
72+
&mut len as *mut _ as *mut _,
73+
0 as *mut libc::c_void,
74+
0,
75+
);
76+
77+
if ret != -1 {
78+
for i in 0..auxv.len() {
79+
if auxv[i].a_type == key {
80+
return Ok(auxv[i].a_un.a_val as usize);
81+
}
82+
}
83+
}
84+
}
85+
return Ok(0);
86+
}

crates/std_detect/src/detect/os/freebsd/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
//! Run-time feature detection on FreeBSD
22
3+
mod auxvec;
4+
35
cfg_if! {
46
if #[cfg(target_arch = "aarch64")] {
57
mod aarch64;
68
pub use self::aarch64::check_for;
9+
} else if #[cfg(target_arch = "arm")] {
10+
mod arm;
11+
pub use self::arm::check_for;
12+
} else if #[cfg(target_arch = "powerpc64")] {
13+
mod powerpc;
14+
pub use self::powerpc::check_for;
715
} else {
816
use crate::arch::detect::Feature;
917
/// Performs run-time feature detection.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Run-time feature detection for PowerPC on FreeBSD.
2+
3+
use crate::detect::{Feature, cache};
4+
use super::{auxvec};
5+
6+
/// Performs run-time feature detection.
7+
#[inline]
8+
pub fn check_for(x: Feature) -> bool {
9+
cache::test(x as u32, detect_features)
10+
}
11+
12+
fn detect_features() -> cache::Initializer {
13+
let mut value = cache::Initializer::default();
14+
let enable_feature = |value: &mut cache::Initializer, f, enable| {
15+
if enable {
16+
value.set(f as u32);
17+
}
18+
};
19+
20+
if let Ok(auxv) = auxvec::auxv() {
21+
enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0);
22+
enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0);
23+
enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0);
24+
return value;
25+
}
26+
value
27+
}

0 commit comments

Comments
 (0)