about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/stdarch/crates/std_detect/src/detect/mod.rs6
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/aarch64.rs46
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs56
-rw-r--r--library/stdarch/crates/std_detect/tests/cpu-detection.rs7
4 files changed, 91 insertions, 24 deletions
diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs
index 9a135c90a39..db7018232d4 100644
--- a/library/stdarch/crates/std_detect/src/detect/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/mod.rs
@@ -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;
diff --git a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
index bda5f1bf2de..7f860f44ebe 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
@@ -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
diff --git a/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs
new file mode 100644
index 00000000000..068dcba7db7
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs
@@ -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() })
+}
diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
index e090a205c44..ec0875a355e 100644
--- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs
+++ b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
@@ -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"));