From 3621595ec09535b78a2352215a3e45b93d9e36a1 Mon Sep 17 00:00:00 2001 From: Muntasir Mahmud Date: Wed, 9 Sep 2026 15:39:02 +0600 Subject: [PATCH] cpufeatures: support crc detection --- cpufeatures/README.md | 1 + cpufeatures/src/aarch64.rs | 31 ++++++++++++++++++++++++------- cpufeatures/tests/aarch64.rs | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/cpufeatures/README.md b/cpufeatures/README.md index ed240f05..8d1f94dc 100644 --- a/cpufeatures/README.md +++ b/cpufeatures/README.md @@ -68,6 +68,7 @@ Linux, iOS, and macOS/ARM only (ARM64 does not support OS-independent feature de Target features: - `aes`* +- `crc` - `sha2`* - `sha3`* diff --git a/cpufeatures/src/aarch64.rs b/cpufeatures/src/aarch64.rs index bb955418..eba1829f 100644 --- a/cpufeatures/src/aarch64.rs +++ b/cpufeatures/src/aarch64.rs @@ -67,6 +67,7 @@ macro_rules! __expand_check_macro { #[cfg(any(target_os = "linux", target_os = "android"))] __expand_check_macro! { ("aes", AES), // Enable AES support. + ("crc", CRC32), // Enable CRC32 support. ("dit", DIT), // Enable DIT support. ("sha2", SHA2), // Enable SHA1 and SHA256 support. ("sha3", SHA3), // Enable SHA512 and SHA3 support. @@ -85,6 +86,7 @@ pub mod hwcaps { use libc::c_ulong; pub const AES: c_ulong = libc::HWCAP_AES | libc::HWCAP_PMULL; + pub const CRC32: c_ulong = libc::HWCAP_CRC32; pub const DIT: c_ulong = libc::HWCAP_DIT; pub const SHA2: c_ulong = libc::HWCAP_SHA2; pub const SHA3: c_ulong = libc::HWCAP_SHA3 | libc::HWCAP_SHA512; @@ -109,10 +111,19 @@ macro_rules! check { ("aes") => { true }; + ("crc") => { + unsafe { + // `hw.optional.armv8_crc32` is the legacy name, + // `hw.optional.arm.FEAT_CRC32` is the newer FEAT_ name. + // Either one reporting present means CRC32 is available. + $crate::aarch64::try_sysctlbyname(b"hw.optional.armv8_crc32\0") + || $crate::aarch64::try_sysctlbyname(b"hw.optional.arm.FEAT_CRC32\0") + } + }; ("dit") => { // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Enable-DIT-for-constant-time-cryptographic-operations unsafe { - $crate::aarch64::sysctlbyname(b"hw.optional.arm.FEAT_DIT\0") + $crate::aarch64::try_sysctlbyname(b"hw.optional.arm.FEAT_DIT\0") } }; ("sha2") => { @@ -121,8 +132,8 @@ macro_rules! check { ("sha3") => { unsafe { // `sha3` target feature implies SHA-512 as well - $crate::aarch64::sysctlbyname(b"hw.optional.armv8_2_sha512\0") - && $crate::aarch64::sysctlbyname(b"hw.optional.armv8_2_sha3\0") + $crate::aarch64::try_sysctlbyname(b"hw.optional.armv8_2_sha512\0") + && $crate::aarch64::try_sysctlbyname(b"hw.optional.armv8_2_sha3\0") } }; ("sm4") => { @@ -132,13 +143,17 @@ macro_rules! check { /// Apple helper function for calling `sysctlbyname`. /// +/// Returns `false` when the named key does not exist +/// or has an unexpected size, so renamed keys across OS versions degrade +/// to "unsupported" instead of aborting. +/// /// /// /// # Panics /// If `name` is not NUL terminated #[cfg(target_vendor = "apple")] #[must_use] -pub unsafe fn sysctlbyname(name: &[u8]) -> bool { +pub unsafe fn try_sysctlbyname(name: &[u8]) -> bool { assert_eq!( name.last().cloned(), Some(0), @@ -153,10 +168,11 @@ pub unsafe fn sysctlbyname(name: &[u8]) -> bool { // - `name` is being cast from a valid byte slice we asserted was NUL terminated above. // - `value` is a properly-aligned, writable integer. // - `size` is initialized to the size of `value` (4-bytes). - // - The last two arguments,`newp` and `newlen`, are for setting system parameters, which we + // - The last two arguments, `newp` and `newlen`, are for setting system parameters, which we // aren't doing here (and requires root privileges). The docs say the following: // - `newp`: "Specify NULL if you don’t want to set the attribute’s value" // - `newlen`: "Specify 0 if you don’t want to set the attribute’s value" + // A nonzero return code (unknown key) or unexpected size maps to `false`. let rc = unsafe { libc::sysctlbyname( name.as_ptr().cast::(), @@ -167,8 +183,9 @@ pub unsafe fn sysctlbyname(name: &[u8]) -> bool { ) }; - assert_eq!(size, 4, "unexpected sysctlbyname(3) result size"); - assert_eq!(rc, 0, "sysctlbyname returned error code: {}", rc); + if rc != 0 || size != 4 { + return false; + } value != 0 } diff --git a/cpufeatures/tests/aarch64.rs b/cpufeatures/tests/aarch64.rs index 41a61233..0d4ad0ef 100644 --- a/cpufeatures/tests/aarch64.rs +++ b/cpufeatures/tests/aarch64.rs @@ -2,7 +2,7 @@ #![cfg(target_arch = "aarch64")] -cpufeatures::new!(armcaps, "aes", "sha2", "sha3", "sm4"); +cpufeatures::new!(armcaps, "aes", "crc", "sha2", "sha3", "sm4"); #[test] fn init() {