std_detect: Support run-time detection on aarch64 OpenBSD
This commit is contained in:
parent
d3bb923c82
commit
a36f5bd7c8
4 changed files with 91 additions and 24 deletions
|
|
@ -56,6 +56,12 @@ cfg_if! {
|
|||
mod aarch64;
|
||||
#[path = "os/freebsd/mod.rs"]
|
||||
mod os;
|
||||
} else if #[cfg(all(target_os = "openbsd", target_arch = "aarch64", feature = "libc"))] {
|
||||
#[allow(dead_code)] // we don't use code that calls the mrs instruction.
|
||||
#[path = "os/aarch64.rs"]
|
||||
mod aarch64;
|
||||
#[path = "os/openbsd/aarch64.rs"]
|
||||
mod os;
|
||||
} else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] {
|
||||
#[path = "os/windows/aarch64.rs"]
|
||||
mod os;
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
);
|
||||
}
|
||||
|
||||
parse_system_registers(aa64isar0, aa64isar1, aa64pfr0)
|
||||
parse_system_registers(aa64isar0, aa64isar1, Some(aa64pfr0))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_system_registers(
|
||||
aa64isar0: u64,
|
||||
aa64isar1: u64,
|
||||
aa64pfr0: u64,
|
||||
aa64pfr0: Option<u64>,
|
||||
) -> cache::Initializer {
|
||||
let mut value = cache::Initializer::default();
|
||||
|
||||
|
|
@ -76,26 +76,28 @@ pub(crate) fn parse_system_registers(
|
|||
enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);
|
||||
|
||||
// ID_AA64PFR0_EL1 - Processor Feature Register 0
|
||||
let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
|
||||
let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
|
||||
let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
|
||||
let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
|
||||
enable_feature(Feature::fp, fp);
|
||||
enable_feature(Feature::fp16, fphp);
|
||||
// SIMD support requires float support - if half-floats are
|
||||
// supported, it also requires half-float support:
|
||||
enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
|
||||
// SIMD extensions require SIMD support:
|
||||
enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 1);
|
||||
let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
|
||||
let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
|
||||
enable_feature(Feature::sha2, asimd && sha1 && sha2);
|
||||
enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
|
||||
enable_feature(
|
||||
Feature::dotprod,
|
||||
asimd && bits_shift(aa64isar0, 47, 44) >= 1,
|
||||
);
|
||||
enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);
|
||||
if let Some(aa64pfr0) = aa64pfr0 {
|
||||
let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
|
||||
let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
|
||||
let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
|
||||
let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
|
||||
enable_feature(Feature::fp, fp);
|
||||
enable_feature(Feature::fp16, fphp);
|
||||
// SIMD support requires float support - if half-floats are
|
||||
// supported, it also requires half-float support:
|
||||
enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
|
||||
// SIMD extensions require SIMD support:
|
||||
enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 1);
|
||||
let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
|
||||
let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
|
||||
enable_feature(Feature::sha2, asimd && sha1 && sha2);
|
||||
enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
|
||||
enable_feature(
|
||||
Feature::dotprod,
|
||||
asimd && bits_shift(aa64isar0, 47, 44) >= 1,
|
||||
);
|
||||
enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);
|
||||
}
|
||||
|
||||
// ID_AA64PFR0_EL1 - Processor Feature Register 0
|
||||
// Check for either APA or API field
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
//! Run-time feature detection for Aarch64 on OpenBSD.
|
||||
//!
|
||||
//! OpenBSD doesn't trap the mrs instruction, but exposes the system registers through sysctl.
|
||||
//! https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8
|
||||
//! https://github.com/golang/go/commit/cd54ef1f61945459486e9eea2f016d99ef1da925
|
||||
|
||||
use crate::detect::cache;
|
||||
use core::{mem::MaybeUninit, ptr};
|
||||
|
||||
// Defined in sys/sysctl.h.
|
||||
// https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/sys/sysctl.h#L82
|
||||
const CTL_MACHDEP: libc::c_int = 7;
|
||||
// Defined in machine/cpu.h.
|
||||
// https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/arch/arm64/include/cpu.h#L25-L40
|
||||
const CPU_ID_AA64ISAR0: libc::c_int = 2;
|
||||
const CPU_ID_AA64ISAR1: libc::c_int = 3;
|
||||
const CPU_ID_AA64PFR0: libc::c_int = 8;
|
||||
|
||||
/// Try to read the features from the system registers.
|
||||
pub(crate) fn detect_features() -> cache::Initializer {
|
||||
// ID_AA64ISAR0_EL1 and ID_AA64ISAR1_EL1 are supported on OpenBSD 7.1+.
|
||||
// https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8
|
||||
// Others are supported on OpenBSD 7.3+.
|
||||
// https://github.com/openbsd/src/commit/c7654cd65262d532212f65123ee3905ba200365c
|
||||
// sysctl returns an unsupported error if operation is not supported,
|
||||
// so we can safely use this function on older versions of OpenBSD.
|
||||
let aa64isar0 = sysctl64(&[CTL_MACHDEP, CPU_ID_AA64ISAR0]).unwrap_or(0);
|
||||
let aa64isar1 = sysctl64(&[CTL_MACHDEP, CPU_ID_AA64ISAR1]).unwrap_or(0);
|
||||
// Do not use unwrap_or(0) because in fp and asimd fields, 0 indicates that
|
||||
// the feature is available.
|
||||
let aa64pfr0 = sysctl64(&[CTL_MACHDEP, CPU_ID_AA64PFR0]);
|
||||
|
||||
super::aarch64::parse_system_registers(aa64isar0, aa64isar1, aa64pfr0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sysctl64(mib: &[libc::c_int]) -> Option<u64> {
|
||||
const OUT_LEN: libc::size_t = core::mem::size_of::<u64>();
|
||||
let mut out = MaybeUninit::<u64>::uninit();
|
||||
let mut out_len = OUT_LEN;
|
||||
let res = unsafe {
|
||||
libc::sysctl(
|
||||
mib.as_ptr(),
|
||||
mib.len() as libc::c_uint,
|
||||
out.as_mut_ptr() as *mut libc::c_void,
|
||||
&mut out_len,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
if res == -1 || out_len != OUT_LEN {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: we've checked that sysctl was successful and `out` was filled.
|
||||
Some(unsafe { out.assume_init() })
|
||||
}
|
||||
|
|
@ -98,8 +98,11 @@ fn aarch64_windows() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_arch = "aarch64", target_os = "freebsd"))]
|
||||
fn aarch64_freebsd() {
|
||||
#[cfg(all(
|
||||
target_arch = "aarch64",
|
||||
any(target_os = "freebsd", target_os = "openbsd")
|
||||
))]
|
||||
fn aarch64_bsd() {
|
||||
println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
|
||||
println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
|
||||
println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue