From 0adfbecb2cae2de4eee374300b1b63558c6a5067 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 12 Feb 2023 13:57:57 +0900 Subject: [PATCH 1/3] std_detect: Workaround Exynos 9810 bug on aarch64 Android 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 --- .../std_detect/src/detect/os/linux/aarch64.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/std_detect/src/detect/os/linux/aarch64.rs b/crates/std_detect/src/detect/os/linux/aarch64.rs index a75185d435..ac8da8f8c6 100644 --- a/crates/std_detect/src/detect/os/linux/aarch64.rs +++ b/crates/std_detect/src/detect/os/linux/aarch64.rs @@ -6,6 +6,25 @@ 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(all(target_arch = "aarch64", target_os = "android"))] + { + // 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. + if len > 0 && arch.starts_with(b"exynos9810") { + return cache::Initializer::default(); + } + } if let Ok(auxv) = auxvec::auxv() { let hwcap: AtHwcap = auxv.into(); return hwcap.cache(); From 9ce03f137315630630bca6acb29145d5048fb6d2 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 12 Feb 2023 16:25:13 +0900 Subject: [PATCH 2/3] std_detect: Only check features that are known to be available on armv8.0 cores if CPU is Exynos 9810 --- .../std_detect/src/detect/os/linux/aarch64.rs | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/crates/std_detect/src/detect/os/linux/aarch64.rs b/crates/std_detect/src/detect/os/linux/aarch64.rs index ac8da8f8c6..7a6f4f4515 100644 --- a/crates/std_detect/src/detect/os/linux/aarch64.rs +++ b/crates/std_detect/src/detect/os/linux/aarch64.rs @@ -7,7 +7,7 @@ use crate::detect::{bit, cache, Feature}; /// to read them from /proc/cpuinfo. pub(crate) fn detect_features() -> cache::Initializer { #[cfg(all(target_arch = "aarch64", 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. @@ -21,18 +21,19 @@ pub(crate) fn detect_features() -> cache::Initializer { }; // On Exynos, ro.arch is not available on Android 12+, but it is fine // because Android 9+ includes the fix. - if len > 0 && arch.starts_with(b"exynos9810") { - return cache::Initializer::default(); - } - } + len > 0 && arch.starts_with(b"exynos9810") + }; + #[cfg(not(all(target_arch = "aarch64", 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() } @@ -228,7 +229,7 @@ impl AtHwcap { /// /// The feature dependencies here come directly from LLVM's feature definintions: /// 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| { @@ -237,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); From 227aafa721f919032ed0de1d0069c743f440cdc1 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 12 Feb 2023 16:36:31 +0900 Subject: [PATCH 3/3] std_detect: Remove extra cfg This module is already `#[cfg(target_arch = "aarch64")]`. --- crates/std_detect/src/detect/os/linux/aarch64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/std_detect/src/detect/os/linux/aarch64.rs b/crates/std_detect/src/detect/os/linux/aarch64.rs index 7a6f4f4515..782317d357 100644 --- a/crates/std_detect/src/detect/os/linux/aarch64.rs +++ b/crates/std_detect/src/detect/os/linux/aarch64.rs @@ -6,7 +6,7 @@ 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(all(target_arch = "aarch64", target_os = "android"))] + #[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 @@ -23,7 +23,7 @@ pub(crate) fn detect_features() -> cache::Initializer { // because Android 9+ includes the fix. len > 0 && arch.starts_with(b"exynos9810") }; - #[cfg(not(all(target_arch = "aarch64", target_os = "android")))] + #[cfg(not(target_os = "android"))] let is_exynos9810 = false; if let Ok(auxv) = auxvec::auxv() {