summaryrefslogtreecommitdiffstats
path: root/library/stdarch/crates/std_detect/src/detect/os/freebsd
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates/std_detect/src/detect/os/freebsd')
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs21
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs21
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs102
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs22
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs21
5 files changed, 187 insertions, 0 deletions
diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs
new file mode 100644
index 000000000..7d972b373
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs
@@ -0,0 +1,21 @@
+//! Run-time feature detection for Aarch64 on FreeBSD.
+
+pub(crate) use super::super::aarch64::detect_features;
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn dump() {
+ println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
+ println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
+ println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
+ println!("fp16: {:?}", is_aarch64_feature_detected!("fp16"));
+ println!("sve: {:?}", is_aarch64_feature_detected!("sve"));
+ println!("crc: {:?}", is_aarch64_feature_detected!("crc"));
+ println!("lse: {:?}", is_aarch64_feature_detected!("lse"));
+ println!("rdm: {:?}", is_aarch64_feature_detected!("rdm"));
+ println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc"));
+ println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod"));
+ println!("tme: {:?}", is_aarch64_feature_detected!("tme"));
+ }
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs
new file mode 100644
index 000000000..4c9d763b4
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs
@@ -0,0 +1,21 @@
+//! Run-time feature detection for ARM on FreeBSD
+
+use super::auxvec;
+use crate::detect::{cache, Feature};
+
+/// Try to read the features from the auxiliary vector
+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::neon, auxv.hwcap & 0x00001000 != 0);
+ enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & 0x00000002 != 0);
+ return value;
+ }
+ value
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs
new file mode 100644
index 000000000..29fcc8cb0
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs
@@ -0,0 +1,102 @@
+//! Parses ELF auxiliary vectors.
+#![cfg_attr(
+ any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc64",
+ target_arch = "riscv64"
+ ),
+ 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 core::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);
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs
new file mode 100644
index 000000000..ade7fb626
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs
@@ -0,0 +1,22 @@
+//! Run-time feature detection on FreeBSD
+
+mod auxvec;
+
+cfg_if::cfg_if! {
+ if #[cfg(target_arch = "aarch64")] {
+ mod aarch64;
+ pub(crate) use self::aarch64::detect_features;
+ } else if #[cfg(target_arch = "arm")] {
+ mod arm;
+ pub(crate) use self::arm::detect_features;
+ } else if #[cfg(target_arch = "powerpc64")] {
+ mod powerpc;
+ pub(crate) use self::powerpc::detect_features;
+ } else {
+ use crate::detect::cache;
+ /// Performs run-time feature detection.
+ pub(crate) fn detect_features() -> cache::Initializer {
+ cache::Initializer::default()
+ }
+ }
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs
new file mode 100644
index 000000000..6bfab631a
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs
@@ -0,0 +1,21 @@
+//! Run-time feature detection for PowerPC on FreeBSD.
+
+use super::auxvec;
+use crate::detect::{cache, Feature};
+
+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
+}