Skip to content

Add std_detect for FreeBSD armv6, armv7 and powerpc64 #747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2019
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
27 changes: 27 additions & 0 deletions crates/std_detect/src/detect/os/freebsd/arm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! Run-time feature detection for ARM on FreeBSD

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

/// Performs run-time feature detection.
#[inline]
pub fn check_for(x: Feature) -> bool {
cache::test(x as u32, detect_features)
}

/// Try to read the features from the auxiliary vector
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::neon, auxv.hwcap & 0x00001000 != 0);
enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & 0x00000002 != 0);
return value;
}
value
}
86 changes: 86 additions & 0 deletions crates/std_detect/src/detect/os/freebsd/auxvec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! Parses ELF auxiliary vectors.
#![cfg_attr(any(target_arch = "arm", target_arch = "powerpc64"), allow(dead_code))]

/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 25;
/// Key to access the CPU Hardware capabilities 2 bitfield.
pub(crate) const AT_HWCAP2: usize = 26;

/// 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 FreeBSD, they are
/// defined in [sys/elf_common.h][elf_common_h]. 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_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
pub(crate) fn auxv() -> Result<AuxVec, ()> {
if let Ok(hwcap) = archauxv(AT_HWCAP) {
if let Ok(hwcap2) = archauxv(AT_HWCAP2) {
if hwcap != 0 && hwcap2 != 0 {
return Ok(AuxVec { hwcap, hwcap2 });
}
}
}
Err(())
}

/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
use mem;

#[derive (Copy, Clone)]
#[repr(C)]
pub struct Elf_Auxinfo {
pub a_type: usize,
pub a_un: unnamed,
}
#[derive (Copy, Clone)]
#[repr(C)]
pub union unnamed {
pub a_val: libc::c_long,
pub a_ptr: *mut libc::c_void,
pub a_fcn: Option<unsafe extern "C" fn() -> ()>,
}

let mut auxv: [Elf_Auxinfo; 27] =
[Elf_Auxinfo{a_type: 0, a_un: unnamed{a_val: 0,},}; 27];

let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint;

unsafe {
let mut mib = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_AUXV, libc::getpid()];

let ret = libc::sysctl(mib.as_mut_ptr(),
mib.len() as u32,
&mut auxv as *mut _ as *mut _,
&mut len as *mut _ as *mut _,
0 as *mut libc::c_void,
0,
);

if ret != -1 {
for i in 0..auxv.len() {
if auxv[i].a_type == key {
return Ok(auxv[i].a_un.a_val as usize);
}
}
}
}
return Ok(0);
}
8 changes: 8 additions & 0 deletions crates/std_detect/src/detect/os/freebsd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
//! Run-time feature detection on FreeBSD

mod auxvec;

cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::check_for;
} else if #[cfg(target_arch = "arm")] {
mod arm;
pub use self::arm::check_for;
} else if #[cfg(target_arch = "powerpc64")] {
mod powerpc;
pub use self::powerpc::check_for;
} else {
use crate::arch::detect::Feature;
/// Performs run-time feature detection.
Expand Down
27 changes: 27 additions & 0 deletions crates/std_detect/src/detect/os/freebsd/powerpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! Run-time feature detection for PowerPC on FreeBSD.

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

/// Performs run-time feature detection.
#[inline]
pub fn check_for(x: Feature) -> bool {
cache::test(x as u32, detect_features)
}

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
}