Skip to content
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

MSRV 1.60: cpu: Use std::arch::is_aarch64_feature_detected on AArch64. #1542

Closed
wants to merge 4 commits into from
Closed
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
7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,12 @@ name = "ring"
getrandom = { version = "0.2.8" }
untrusted = { version = "0.9" }

[target.'cfg(any(target_arch = "x86",target_arch = "x86_64", all(any(target_arch = "aarch64", target_arch = "arm"), any(target_os = "android", target_os = "fuchsia", target_os = "linux", target_os = "windows"))))'.dependencies]
[target.'cfg(any(target_arch = "x86",target_arch = "x86_64", all(target_arch = "aarch64", any(target_family = "unix", target_family = "windows")), all(target_arch = "arm", any(target_os = "android", target_os = "fuchsia", target_os = "linux", target_os = "windows"))))'.dependencies]
spin = { version = "0.9.2", default-features = false, features = ["once"] }

[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
[target.'cfg(all(target_arch = "arm", any(target_os = "android", target_os = "linux")))'.dependencies]
libc = { version = "0.2.100", default-features = false }

[target.'cfg(all(target_arch = "aarch64", target_os = "windows"))'.dependencies]
windows-sys = { version = "0.48", features = ["Win32_Foundation", "Win32_System_Threading"] }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { version = "0.3.26", default-features = false }

Expand Down
33 changes: 21 additions & 12 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,30 @@ pub(crate) struct Features(());

#[inline(always)]
pub(crate) fn features() -> Features {
// We don't do runtime feature detection on aarch64-apple-* as all AAarch64
// features we use are available on every device since the first devices.
// TODO: The list of operating systems for `aarch64` should really be
// "whatever has `std::arch::is_aarch64_feature_detected`".
#[cfg(any(
target_arch = "x86",
target_arch = "x86_64",
all(
any(target_arch = "aarch64", target_arch = "arm"),
target_arch = "aarch64",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "illumos",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "windows",
)
),
all(
target_arch = "arm",
any(
target_os = "android",
target_os = "fuchsia",
Expand All @@ -52,15 +69,7 @@ pub(crate) fn features() -> Features {
}
}

#[cfg(all(
any(target_arch = "aarch64", target_arch = "arm"),
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
)
))]
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
{
arm::setup();
}
Expand Down
176 changes: 38 additions & 138 deletions src/cpu/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,142 +12,50 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#[cfg(all(
any(target_os = "android", target_os = "linux"),
any(target_arch = "aarch64", target_arch = "arm")
))]
// TODO(MSRV): Replace this with use of `std::arch::is_arm_feature_detected!()`.
#[cfg(all(target_arch = "arm", any(target_os = "android", target_os = "linux")))]
pub fn setup() {
use libc::c_ulong;
use libc::{c_ulong, getauxval, AT_HWCAP};

// XXX: The `libc` crate doesn't provide `libc::getauxval` consistently
// across all Android/Linux targets, e.g. musl.
extern "C" {
fn getauxval(type_: c_ulong) -> c_ulong;
}

const AT_HWCAP: c_ulong = 16;

#[cfg(target_arch = "aarch64")]
const HWCAP_NEON: c_ulong = 1 << 1;

#[cfg(target_arch = "arm")]
const HWCAP_NEON: c_ulong = 1 << 12;

let caps = unsafe { getauxval(AT_HWCAP) };

// We assume NEON is available on AARCH64 because it is a required
// feature.
#[cfg(target_arch = "aarch64")]
debug_assert!(caps & HWCAP_NEON == HWCAP_NEON);

// OpenSSL and BoringSSL don't enable any other features if NEON isn't
// available.
if caps & HWCAP_NEON == HWCAP_NEON {
let mut features = NEON.mask;

#[cfg(target_arch = "aarch64")]
const OFFSET: c_ulong = 3;

#[cfg(target_arch = "arm")]
const OFFSET: c_ulong = 0;

#[cfg(target_arch = "arm")]
let caps = {
const AT_HWCAP2: c_ulong = 26;
unsafe { getauxval(AT_HWCAP2) }
};

const HWCAP_AES: c_ulong = 1 << 0 + OFFSET;
const HWCAP_PMULL: c_ulong = 1 << 1 + OFFSET;
const HWCAP_SHA2: c_ulong = 1 << 3 + OFFSET;
const HWCAP2_AES: c_ulong = 1 << 0;
const HWCAP2_PMULL: c_ulong = 1 << 1;
const HWCAP2_SHA2: c_ulong = 1 << 3;

if caps & HWCAP_AES == HWCAP_AES {
if caps & HWCAP2_AES == HWCAP2_AES {
features |= AES.mask;
}
if caps & HWCAP_PMULL == HWCAP_PMULL {
if caps & HWCAP2_PMULL == HWCAP2_PMULL {
features |= PMULL.mask;
}
if caps & HWCAP_SHA2 == HWCAP_SHA2 {
if caps & HWCAP2_SHA2 == HWCAP2_SHA2 {
features |= SHA256.mask;
}

unsafe { OPENSSL_armcap_P = features };
}
}

#[cfg(all(target_os = "fuchsia", target_arch = "aarch64"))]
pub fn setup() {
type zx_status_t = i32;

#[link(name = "zircon")]
extern "C" {
fn zx_system_get_features(kind: u32, features: *mut u32) -> zx_status_t;
}

const ZX_OK: i32 = 0;
const ZX_FEATURE_KIND_CPU: u32 = 0;
const ZX_ARM64_FEATURE_ISA_ASIMD: u32 = 1 << 2;
const ZX_ARM64_FEATURE_ISA_AES: u32 = 1 << 3;
const ZX_ARM64_FEATURE_ISA_PMULL: u32 = 1 << 4;
const ZX_ARM64_FEATURE_ISA_SHA2: u32 = 1 << 6;

let mut caps = 0;
let rc = unsafe { zx_system_get_features(ZX_FEATURE_KIND_CPU, &mut caps) };

// OpenSSL and BoringSSL don't enable any other features if NEON isn't
// available.
if rc == ZX_OK && (caps & ZX_ARM64_FEATURE_ISA_ASIMD == ZX_ARM64_FEATURE_ISA_ASIMD) {
let mut features = NEON.mask;

if caps & ZX_ARM64_FEATURE_ISA_AES == ZX_ARM64_FEATURE_ISA_AES {
features |= AES.mask;
}
if caps & ZX_ARM64_FEATURE_ISA_PMULL == ZX_ARM64_FEATURE_ISA_PMULL {
features |= PMULL.mask;
}
if caps & ZX_ARM64_FEATURE_ISA_SHA2 == ZX_ARM64_FEATURE_ISA_SHA2 {
features |= 1 << 4;
}

unsafe { OPENSSL_armcap_P = features };
}
}

#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
pub fn setup() {
// We do not need to check for the presence of NEON, as Armv8-A always has it
let mut features = NEON.mask;

let result = unsafe {
windows_sys::Win32::System::Threading::IsProcessorFeaturePresent(
windows_sys::Win32::System::Threading::PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE,
)
};

if result != 0 {
// These are all covered by one call in Windows
features |= AES.mask;
features |= PMULL.mask;
features |= SHA256.mask;
}

unsafe { OPENSSL_armcap_P = features };
}

macro_rules! features {
{
{ // Use `:tt` instead of `:literal` to work around
// https://github.com/rust-lang/rust/issues/72726.
$(
$name:ident {
$static_target_feature_name:literal then $dynamic_target_feature_name:tt => $name:ident {
mask: $mask:expr,

// Should we assume that the feature is always available
// for aarch64-apple-* targets? The first AArch64 iOS
// device used the Apple A7 chip.
// TODO: When we can use `if` in const expressions:
// ```
// aarch64_apple: $aarch64_apple,
// ```
aarch64_apple: true,
}
),+
, // trailing comma is required.
Expand All @@ -159,30 +67,23 @@ macro_rules! features {
};
)+

// TODO: When we can use `if` in const expressions, do this:
// ```
// const ARMCAP_STATIC: u32 = 0
// $(
// | ( if $aarch64_apple &&
// cfg!(all(target_arch = "aarch64",
// target_vendor = "apple")) {
// $name.mask
// } else {
// 0
// }
// )
// )+;
// ```
//
// TODO: Add static feature detection to other targets.
// TODO: Combine static feature detection with runtime feature
// detection.
#[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
#[cfg(all(target_arch = "aarch64", any(target_family = "unix", target_family = "windows")))]
pub fn setup() {
extern crate std;
use std::arch::is_aarch64_feature_detected;

let features = 0
$(
| (if is_aarch64_feature_detected!($dynamic_target_feature_name) { $name.mask } else { 0 })
)+;
debug_assert_eq!(features & ARMCAP_STATIC, ARMCAP_STATIC);
unsafe { OPENSSL_armcap_P = features };
}

const ARMCAP_STATIC: u32 = 0
$( | $name.mask
$(
| ( if cfg!(target_feature = $static_target_feature_name) { $name.mask } else { 0 } )
)+;
#[cfg(not(all(target_arch = "aarch64", target_vendor = "apple")))]
const ARMCAP_STATIC: u32 = 0;

const _ALL_FEATURES_MASK: u32 = 0
$( | $name.mask
Expand Down Expand Up @@ -227,29 +128,28 @@ impl Feature {
}
}

// Assumes all target feature names are the same for ARM and AAarch64.
features! {
// Keep in sync with `ARMV7_NEON`.
NEON {
"neon" then "neon" => NEON {
mask: 1 << 0,
aarch64_apple: true,
},

// Keep in sync with `ARMV8_AES`.
AES {
"aes" then "aes" => AES {
mask: 1 << 2,
aarch64_apple: true,
},

// Keep in sync with `ARMV8_SHA256`.
SHA256 {
"sha2" then "sha2" => SHA256 {
mask: 1 << 4,
aarch64_apple: true,
},

// Keep in sync with `ARMV8_PMULL`.
PMULL {
// TODO(MSRV): There is no "pmull" feature listed from
// `rustc --print cfg --target=aarch64-apple-darwin`. Originally ARMv8 tied
// PMULL detection into AES detection, but later versions split it; see
// https://developer.arm.com/downloads/-/exploration-tools/feature-names-for-a-profile
// "Features introduced prior to 2020." Change this to use "pmull" when
// that is supported.
"aes" then "pmull" => PMULL {
mask: 1 << 5,
aarch64_apple: true,
},
}

Expand Down
Loading