summaryrefslogtreecommitdiffstats
path: root/library/stdarch/crates/std_detect/src/detect/os/linux
diff options
context:
space:
mode:
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.rs47
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs22
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;