diff options
Diffstat (limited to 'library/stdarch/crates/std_detect/src/detect/os/linux')
-rw-r--r-- | library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs | 47 | ||||
-rw-r--r-- | library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs | 22 |
2 files changed, 61 insertions, 8 deletions
diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs index a75185d43..caaa39f14 100644 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs +++ b/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs @@ -6,14 +6,34 @@ use crate::detect::{bit, cache, Feature}; /// Try to read the features from the auxiliary vector, and if that fails, try /// to read them from /proc/cpuinfo. pub(crate) fn detect_features() -> cache::Initializer { + #[cfg(target_os = "android")] + let is_exynos9810 = { + // Samsung Exynos 9810 has a bug that big and little cores have different + // ISAs. And on older Android (pre-9), the kernel incorrectly reports + // that features available only on some cores are available on all cores. + // https://reviews.llvm.org/D114523 + let mut arch = [0_u8; libc::PROP_VALUE_MAX as usize]; + let len = unsafe { + libc::__system_property_get( + b"ro.arch\0".as_ptr() as *const libc::c_char, + arch.as_mut_ptr() as *mut libc::c_char, + ) + }; + // On Exynos, ro.arch is not available on Android 12+, but it is fine + // because Android 9+ includes the fix. + len > 0 && arch.starts_with(b"exynos9810") + }; + #[cfg(not(target_os = "android"))] + let is_exynos9810 = false; + if let Ok(auxv) = auxvec::auxv() { let hwcap: AtHwcap = auxv.into(); - return hwcap.cache(); + return hwcap.cache(is_exynos9810); } #[cfg(feature = "std_detect_file_io")] if let Ok(c) = super::cpuinfo::CpuInfo::new() { let hwcap: AtHwcap = c.into(); - return hwcap.cache(); + return hwcap.cache(is_exynos9810); } cache::Initializer::default() } @@ -207,9 +227,9 @@ impl From<super::cpuinfo::CpuInfo> for AtHwcap { impl AtHwcap { /// Initializes the cache from the feature -bits. /// - /// The feature dependencies here come directly from LLVM's feature definintions: + /// The feature dependencies here come directly from LLVM's feature definitions: /// https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64.td - fn cache(self) -> cache::Initializer { + fn cache(self, is_exynos9810: bool) -> cache::Initializer { let mut value = cache::Initializer::default(); { let mut enable_feature = |f, enable| { @@ -218,6 +238,25 @@ impl AtHwcap { } }; + // Samsung Exynos 9810 has a bug that big and little cores have different + // ISAs. And on older Android (pre-9), the kernel incorrectly reports + // that features available only on some cores are available on all cores. + // So, only check features that are known to be available on exynos-m3: + // $ rustc --print cfg --target aarch64-linux-android -C target-cpu=exynos-m3 | grep target_feature + // See also https://github.com/rust-lang/stdarch/pull/1378#discussion_r1103748342. + if is_exynos9810 { + enable_feature(Feature::fp, self.fp); + enable_feature(Feature::crc, self.crc32); + // ASIMD support requires float support - if half-floats are + // supported, it also requires half-float support: + let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); + enable_feature(Feature::asimd, asimd); + // Cryptographic extensions require ASIMD + enable_feature(Feature::aes, self.aes && asimd); + enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); + return value; + } + enable_feature(Feature::fp, self.fp); // Half-float support requires float support enable_feature(Feature::fp16, self.fp && self.fphp); diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs index d9e7b28ea..11d9c103e 100644 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs @@ -52,7 +52,12 @@ pub(crate) struct AuxVec { /// Note that run-time feature detection is not invoked for features that can /// be detected at compile-time. Also note that if this function returns an /// error, cpuinfo still can (and will) be used to try to perform run-time -/// feature detecton on some platforms. +/// feature detection on some platforms. +/// +/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on `*-linux-gnu*` targets, +/// since [all `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) +/// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html), +/// and we can safely assume [`getauxval`] is linked to the binary. /// /// For more information about when `getauxval` is available check the great /// [`auxv` crate documentation][auxv_docs]. @@ -60,7 +65,10 @@ pub(crate) struct AuxVec { /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ pub(crate) fn auxv() -> Result<AuxVec, ()> { - #[cfg(feature = "std_detect_dlsym_getauxval")] + #[cfg(all( + feature = "std_detect_dlsym_getauxval", + not(all(target_os = "linux", target_env = "gnu")) + ))] { // Try to call a dynamically-linked getauxval function. if let Ok(hwcap) = getauxval(AT_HWCAP) { @@ -101,7 +109,10 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> { } } - #[cfg(not(feature = "std_detect_dlsym_getauxval"))] + #[cfg(any( + not(feature = "std_detect_dlsym_getauxval"), + all(target_os = "linux", target_env = "gnu") + ))] { // Targets with only AT_HWCAP: #[cfg(any( @@ -154,7 +165,10 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> { /// Tries to read the `key` from the auxiliary vector by calling the /// dynamically-linked `getauxval` function. If the function is not linked, /// this function return `Err`. -#[cfg(feature = "std_detect_dlsym_getauxval")] +#[cfg(all( + feature = "std_detect_dlsym_getauxval", + not(all(target_os = "linux", target_env = "gnu")) +))] fn getauxval(key: usize) -> Result<usize, ()> { use libc; pub type F = unsafe extern "C" fn(usize) -> usize; |