Skip to content

Commit 10c1a09

Browse files
bors[bot]taiki-e
andauthored
Merge #76
76: detect: Workaround Exynos 9810 bug on aarch64 Android r=taiki-e a=taiki-e 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. See https://reviews.llvm.org/D114523 for details. Our own run-time detection code has not been released yet and is not a problem, but portable-atomic < 1.1 may have been affected by this issue since rustc 1.69-nightly when is_aarch64_feature_detected supported run-time detection on Android. (rust-lang/stdarch#1351, rust-lang/rust#105784) A patch on stdarch side: rust-lang/stdarch#1378 Co-authored-by: Taiki Endo <[email protected]>
2 parents e5b567e + ac4f0c4 commit 10c1a09

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

.github/.cspell/project-dictionary.txt

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ docsrs
4242
doctests
4343
DWCAS
4444
endianness
45+
exynos
4546
FIQs
4647
getauxval
4748
hartid

src/imp/atomic128/detect/aarch64_linux.rs

+79
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ include!("common.rs");
3737
// core::ffi::c_* (except c_void) requires Rust 1.64
3838
#[allow(non_camel_case_types)]
3939
mod ffi {
40+
// c_char is u8 on aarch64 Linux/Android
41+
// https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L104-L157
42+
#[cfg(target_os = "android")]
43+
pub(crate) type c_char = u8;
44+
// c_{,u}int is {i,u}32 on non-16-bit architectures
45+
// https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L159-L173
46+
#[cfg(target_os = "android")]
47+
pub(crate) type c_int = i32;
4048
// https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L175-L190
4149
#[cfg(target_pointer_width = "64")]
4250
pub(crate) type c_ulong = u64;
@@ -49,6 +57,11 @@ mod ffi {
4957
// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/linux_like/linux/musl/mod.rs#L744
5058
// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/linux_like/android/b64/mod.rs#L333
5159
pub(crate) fn getauxval(type_: c_ulong) -> c_ulong;
60+
61+
// Defined in sys/system_properties.h.
62+
// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/linux_like/android/mod.rs#L3471
63+
#[cfg(target_os = "android")]
64+
pub(crate) fn __system_property_get(__name: *const c_char, __value: *mut c_char) -> c_int;
5265
}
5366

5467
// https://github.com/torvalds/linux/blob/HEAD/include/uapi/linux/auxvec.h
@@ -57,10 +70,34 @@ mod ffi {
5770
pub(crate) const HWCAP_ATOMICS: c_ulong = 1 << 8;
5871
#[cfg(test)]
5972
pub(crate) const HWCAP_USCAT: c_ulong = 1 << 25;
73+
74+
// Defined in sys/system_properties.h.
75+
// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/linux_like/android/mod.rs#L2760
76+
#[cfg(target_os = "android")]
77+
pub(crate) const PROP_VALUE_MAX: c_int = 92;
6078
}
6179

6280
#[inline]
6381
fn _detect(info: &mut CpuInfo) {
82+
#[cfg(target_os = "android")]
83+
{
84+
// Samsung Exynos 9810 has a bug that big and little cores have different
85+
// ISAs. And on older Android (pre-9), the kernel incorrectly reports
86+
// that features available only on some cores are available on all cores.
87+
// https://reviews.llvm.org/D114523
88+
let mut arch = [0_u8; ffi::PROP_VALUE_MAX as usize];
89+
// SAFETY: we've passed a valid C string and a buffer with max length.
90+
let len = unsafe {
91+
ffi::__system_property_get(
92+
b"ro.arch\0".as_ptr() as *const ffi::c_char,
93+
arch.as_mut_ptr() as *mut ffi::c_char,
94+
)
95+
};
96+
if len > 0 && arch.starts_with(b"exynos9810\0") {
97+
return;
98+
}
99+
}
100+
64101
// SAFETY: getauxval is available in all versions on aarch64 linux-gnu/android.
65102
// See also the module level docs.
66103
let hwcap = unsafe { ffi::getauxval(ffi::AT_HWCAP) };
@@ -88,6 +125,29 @@ fn _detect(info: &mut CpuInfo) {
88125
mod tests {
89126
use super::*;
90127

128+
#[allow(clippy::cast_sign_loss)]
129+
#[cfg(target_os = "android")]
130+
#[test]
131+
fn test_android() {
132+
unsafe {
133+
let mut arch = [1; ffi::PROP_VALUE_MAX as usize];
134+
let len = ffi::__system_property_get(
135+
b"ro.arch\0".as_ptr() as *const ffi::c_char,
136+
arch.as_mut_ptr(),
137+
);
138+
if len < 1 {
139+
std::println!("len={}", len);
140+
}
141+
std::println!("len={}", len);
142+
std::println!("arch={:?}", arch);
143+
std::println!(
144+
"arch={:?}",
145+
core::str::from_utf8(core::slice::from_raw_parts(arch.as_ptr(), len as usize))
146+
.unwrap()
147+
);
148+
}
149+
}
150+
91151
// Static assertions for FFI bindings.
92152
// This checks that FFI bindings defined in this crate, FFI bindings defined
93153
// in libc, and FFI bindings generated for the platform's latest header file
@@ -105,10 +165,27 @@ mod tests {
105165
)]
106166
const _: fn() = || {
107167
use crate::tests::sys::*;
168+
#[cfg(target_os = "android")]
169+
let _: ffi::c_char = 0 as std::os::raw::c_char;
170+
#[cfg(target_os = "android")]
171+
let _: ffi::c_char = 0 as libc::c_char;
172+
#[cfg(target_os = "android")]
173+
let _: ffi::c_int = 0 as std::os::raw::c_int;
174+
#[cfg(target_os = "android")]
175+
let _: ffi::c_int = 0 as libc::c_int;
108176
let _: ffi::c_ulong = 0 as std::os::raw::c_ulong;
109177
let _: ffi::c_ulong = 0 as libc::c_ulong;
110178
let mut _getauxval: unsafe extern "C" fn(ffi::c_ulong) -> ffi::c_ulong = ffi::getauxval;
111179
_getauxval = libc::getauxval;
180+
#[cfg(target_os = "android")]
181+
let mut ___system_property_get: unsafe extern "C" fn(
182+
*const ffi::c_char,
183+
*mut ffi::c_char,
184+
) -> ffi::c_int = ffi::__system_property_get;
185+
#[cfg(target_os = "android")]
186+
{
187+
___system_property_get = libc::__system_property_get;
188+
}
112189
let [] = [(); (ffi::AT_HWCAP - libc::AT_HWCAP) as usize];
113190
let [] =
114191
[(); (ffi::AT_HWCAP - include_uapi_linux_auxvec::AT_HWCAP as ffi::c_ulong) as usize];
@@ -120,5 +197,7 @@ mod tests {
120197
let [] = [(); (ffi::HWCAP_USCAT
121198
- arch_arm64_include_uapi_asm_hwcap::HWCAP_USCAT as ffi::c_ulong)
122199
as usize];
200+
#[cfg(target_os = "android")]
201+
let [] = [(); (ffi::PROP_VALUE_MAX - libc::PROP_VALUE_MAX) as usize];
123202
};
124203
}

0 commit comments

Comments
 (0)