Skip to content

Commit be0e1a4

Browse files
committed
Enable run-time detection by default on AArch64 Apple targets
1 parent e9287eb commit be0e1a4

4 files changed

Lines changed: 29 additions & 137 deletions

File tree

.github/.cspell/project-dictionary.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ lqarx
103103
lrcpc
104104
lsfe
105105
lwsync
106-
MAXNAME
107106
maxu
108107
mcpu
109108
memcheck

src/imp/atomic128/aarch64.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,28 @@ mod detect;
140140
any(target_feature = "lse", portable_atomic_target_feature = "lse"),
141141
)),
142142
))]
143+
#[cfg(target_vendor = "apple")]
144+
#[path = "../detect/aarch64_apple.rs"]
145+
mod detect;
146+
#[cfg(not(portable_atomic_no_outline_atomics))]
147+
#[cfg(any(
148+
test,
149+
not(all(
150+
any(target_feature = "lse2", portable_atomic_target_feature = "lse2"),
151+
any(target_feature = "lse", portable_atomic_target_feature = "lse"),
152+
)),
153+
))]
143154
#[cfg(windows)]
144155
#[path = "../detect/aarch64_windows.rs"]
145156
mod detect;
146157

147-
#[cfg(test)] // test-only (we use auxv.rs)
158+
#[cfg(test)] // test-only (we use auxv.rs instead)
148159
#[cfg(not(valgrind))]
149160
#[cfg(not(portable_atomic_no_outline_atomics))]
150161
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
151162
#[path = "../detect/aarch64_aa64reg.rs"]
152163
mod test_detect_aa64reg;
153-
#[cfg(test)] // test-only (unused)
154-
#[cfg(not(portable_atomic_no_outline_atomics))]
155-
#[cfg(target_vendor = "apple")]
156-
#[path = "../detect/aarch64_apple.rs"]
157-
mod test_detect_apple;
158-
#[cfg(test)] // test-only (we use aarch64_aa64reg.rs)
164+
#[cfg(test)] // test-only (we use aarch64_aa64reg.rs instead)
159165
#[cfg(not(portable_atomic_no_outline_atomics))]
160166
#[cfg(target_os = "openbsd")]
161167
#[path = "../detect/auxv.rs"]
@@ -197,6 +203,7 @@ macro_rules! debug_assert_lse {
197203
target_os = "openbsd",
198204
target_os = "illumos",
199205
target_os = "fuchsia",
206+
target_vendor = "apple",
200207
windows,
201208
),
202209
))]
@@ -237,6 +244,7 @@ macro_rules! debug_assert_lse2 {
237244
target_os = "illumos",
238245
// These don't support detection of FEAT_LSE2.
239246
// target_os = "fuchsia",
247+
target_vendor = "apple",
240248
windows,
241249
),
242250
))]
@@ -280,6 +288,7 @@ macro_rules! debug_assert_lse128 {
280288
target_os = "illumos",
281289
// These don't support detection of FEAT_LSE128.
282290
// target_os = "fuchsia",
291+
target_vendor = "apple",
283292
windows,
284293
),
285294
))]
@@ -323,6 +332,7 @@ macro_rules! debug_assert_rcpc3 {
323332
target_os = "illumos",
324333
// These don't support detection of FEAT_LRCPC3.
325334
// target_os = "fuchsia",
335+
target_vendor = "apple",
326336
windows,
327337
),
328338
))]
@@ -526,6 +536,7 @@ cfg_sel!({
526536
target_os = "illumos",
527537
// These don't support detection of FEAT_LSE2.
528538
// target_os = "fuchsia",
539+
target_vendor = "apple",
529540
windows,
530541
),
531542
))]
@@ -907,6 +918,7 @@ cfg_sel!({
907918
target_os = "illumos",
908919
// These don't support detection of FEAT_LSE2.
909920
// target_os = "fuchsia",
921+
target_vendor = "apple",
910922
windows,
911923
),
912924
))]
@@ -1257,6 +1269,7 @@ unsafe fn atomic_compare_exchange(
12571269
target_os = "openbsd",
12581270
target_os = "illumos",
12591271
target_os = "fuchsia",
1272+
target_vendor = "apple",
12601273
windows,
12611274
),
12621275
))]
@@ -1395,6 +1408,7 @@ unsafe fn atomic_compare_exchange(
13951408
target_os = "openbsd",
13961409
target_os = "illumos",
13971410
target_os = "fuchsia",
1411+
target_vendor = "apple",
13981412
windows,
13991413
),
14001414
)))]

src/imp/detect/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Here is the table of targets that support run-time CPU feature detection and the
1313
| aarch64 | freebsd | elf_aux_info | all | Enabled by default |
1414
| aarch64 | netbsd | sysctlbyname | all | Enabled by default |
1515
| aarch64 | openbsd | sysctl | all | Enabled by default |
16-
| aarch64 | macos/ios/tvos/watchos/visionos | sysctlbyname | all | Currently only used in tests (see [aarch64_apple.rs](aarch64_apple.rs)) |
16+
| aarch64 | macos/ios/tvos/watchos/visionos | sysctlbyname | all | Enabled by default |
1717
| aarch64 | illumos | getisax | lse, lse2 | Enabled by default |
1818
| aarch64/arm64ec | windows | IsProcessorFeaturePresent | lse, lse2 | Enabled by default |
1919
| aarch64 | fuchsia | zx_system_get_features | lse | Enabled by default |

src/imp/detect/aarch64_apple.rs

Lines changed: 7 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ target_feature="v8.7a"
3030
target_feature="wfxt"
3131
```
3232
33-
Refs: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
33+
Non-macOS targets doesn't always supports FEAT_LSE2, so we use this module on them.
34+
As used in the example in https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Enable-DIT-for-constant-time-cryptographic-operations,
35+
sysctlbyname is supported on all Apple platforms.
3436
35-
TODO: non-macOS targets doesn't always supports FEAT_LSE2, but sysctl on them on the App Store is...?
36-
- https://developer.apple.com/forums/thread/9440
37-
- https://nabla-c0d3.github.io/blog/2015/06/16/ios9-security-privacy
38-
- https://github.com/rust-lang/stdarch/pull/1636
37+
Refs: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
3938
*/
4039

4140
include!("common.rs");
@@ -102,16 +101,15 @@ fn _detect(info: &mut CpuInfo) {
102101
// Query both names in case future versions of macOS remove the old name.
103102
// https://github.com/golang/go/commit/c15593197453b8bf90fc3a9080ba2afeaf7934ea
104103
// https://github.com/google/boringssl/commit/91e0b11eba517d83b910b20fe3740eeb39ecb37e
104+
// TODO: use hw.optional.arm.caps on macOS 15+.
105+
// - https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/osfmk/arm/cpu_capabilities_public.h
106+
// - https://github.com/llvm/llvm-project/blob/llvmorg-22.1.0/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/apple.inc#L56
105107
check!(lse, "hw.optional.arm.FEAT_LSE" || "hw.optional.armv8_1_atomics");
106108
check!(lse2, "hw.optional.arm.FEAT_LSE2");
107-
check!(lse128, "hw.optional.arm.FEAT_LSE128");
108-
#[cfg(test)]
109-
check!(lsfe, "hw.optional.arm.FEAT_LSFE");
110109
#[cfg(test)]
111110
check!(rcpc, "hw.optional.arm.FEAT_LRCPC");
112111
#[cfg(test)]
113112
check!(rcpc2, "hw.optional.arm.FEAT_LRCPC2");
114-
check!(rcpc3, "hw.optional.arm.FEAT_LRCPC3");
115113
}
116114

117115
#[allow(
@@ -131,123 +129,6 @@ mod tests {
131129
fn test_alternative() {
132130
use crate::utils::ffi::*;
133131

134-
// Call syscall using asm instead of libc.
135-
// Note that macOS does not guarantee the stability of raw syscall.
136-
// (And they actually changed it: https://go-review.googlesource.com/c/go/+/25495)
137-
//
138-
// This is currently used only for testing.
139-
fn sysctlbyname32_no_libc(name: &CStr) -> Result<u32, c_int> {
140-
#[cfg(not(portable_atomic_no_asm))]
141-
use std::arch::asm;
142-
use std::mem;
143-
144-
use test_helper::sys;
145-
146-
use crate::utils::{RegISize, RegSize};
147-
148-
// Refs: https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/libsyscall/custom/SYS.h#L427
149-
#[inline]
150-
unsafe fn sysctl(
151-
name: *const c_int,
152-
name_len: c_uint,
153-
old_p: *mut c_void,
154-
old_len_p: *mut c_size_t,
155-
new_p: *const c_void,
156-
new_len: c_size_t,
157-
) -> Result<c_int, c_int> {
158-
// https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/osfmk/mach/i386/syscall_sw.h#L158
159-
#[inline]
160-
const fn syscall_construct_unix(n: u64) -> u64 {
161-
const SYSCALL_CLASS_UNIX: u64 = 2;
162-
const SYSCALL_CLASS_SHIFT: u64 = 24;
163-
const SYSCALL_CLASS_MASK: u64 = 0xFF << SYSCALL_CLASS_SHIFT;
164-
const SYSCALL_NUMBER_MASK: u64 = !SYSCALL_CLASS_MASK;
165-
(SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | (SYSCALL_NUMBER_MASK & n)
166-
}
167-
// https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/kern/syscalls.master#L298
168-
let mut n = syscall_construct_unix(202);
169-
let arg1 = ptr_reg!(name);
170-
let arg2 = name_len as RegSize;
171-
let arg3 = ptr_reg!(old_p);
172-
let arg4 = ptr_reg!(old_len_p);
173-
let arg5 = ptr_reg!(new_p);
174-
let arg6 = new_len as RegSize;
175-
let r: RegISize;
176-
// SAFETY: the caller must uphold the safety contract.
177-
unsafe {
178-
asm!(
179-
"svc 0x80", // #SWI_SYSCALL https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/osfmk/mach/arm/vm_param.h#L417
180-
"b.cc 2f",
181-
"mov x16, x0",
182-
"mov x0, #-1",
183-
"2:",
184-
inout("x16") n,
185-
inout("x0") arg1 => r,
186-
inout("x1") arg2 => _,
187-
in("x2") arg3,
188-
in("x3") arg4,
189-
in("x4") arg5,
190-
in("x5") arg6,
191-
// Do not use `preserves_flags` because AArch64 Darwin syscalls modify the condition flags.
192-
options(nostack),
193-
);
194-
}
195-
#[allow(clippy::cast_possible_truncation)]
196-
if r as c_int == -1 { Err(n as c_int) } else { Ok(r as c_int) }
197-
}
198-
// https://github.com/apple-oss-distributions/Libc/blob/af11da5ca9d527ea2f48bb7efbd0f0f2a4ea4812/gen/FreeBSD/sysctlbyname.c
199-
unsafe fn sysctlbyname(
200-
name: &CStr,
201-
old_p: *mut c_void,
202-
old_len_p: *mut c_size_t,
203-
new_p: *mut c_void,
204-
new_len: c_size_t,
205-
) -> Result<c_int, c_int> {
206-
let mut real_oid: [c_int; sys::CTL_MAXNAME as usize + 2] = unsafe { mem::zeroed() };
207-
208-
// Note that this is undocumented API.
209-
// Although FreeBSD defined it in sys/sysctl.h since https://github.com/freebsd/freebsd-src/commit/382e01c8dc7f328f46c61c82a29222f432f510f7
210-
let mut name2oid_oid: [c_int; 2] = [0, 3];
211-
212-
let mut oid_len = mem::size_of_val(&real_oid);
213-
unsafe {
214-
sysctl(
215-
name2oid_oid.as_mut_ptr(),
216-
2,
217-
real_oid.as_mut_ptr().cast::<c_void>(),
218-
&mut oid_len,
219-
name.as_ptr().cast::<c_void>() as *mut c_void,
220-
name.to_bytes_with_nul().len() - 1,
221-
)?;
222-
}
223-
oid_len /= mem::size_of::<c_int>();
224-
#[allow(clippy::cast_possible_truncation)]
225-
unsafe {
226-
sysctl(real_oid.as_mut_ptr(), oid_len as u32, old_p, old_len_p, new_p, new_len)
227-
}
228-
}
229-
230-
const OUT_LEN: ffi::c_size_t = mem::size_of::<u32>() as ffi::c_size_t;
231-
232-
let mut out = 0_u32;
233-
let mut out_len = OUT_LEN;
234-
// SAFETY:
235-
// - `out_len` does not exceed the size of `out`.
236-
// - `sysctlbyname` is thread-safe.
237-
let res = unsafe {
238-
sysctlbyname(
239-
name,
240-
(&mut out as *mut u32).cast::<ffi::c_void>(),
241-
&mut out_len,
242-
ptr::null_mut(),
243-
0,
244-
)?
245-
};
246-
debug_assert_eq!(res, 0);
247-
debug_assert_eq!(out_len, OUT_LEN);
248-
Ok(out)
249-
}
250-
251132
// Call sysctl command instead of libc API.
252133
//
253134
// This is used only for testing.
@@ -292,10 +173,8 @@ mod tests {
292173
);
293174
}
294175
if let Some(res) = res {
295-
assert_eq!(res, sysctlbyname32_no_libc(name).unwrap());
296176
assert_eq!(res, sysctl_output.field(name).unwrap());
297177
} else {
298-
assert_eq!(sysctlbyname32_no_libc(name).unwrap_err(), libc::ENOENT);
299178
assert!(sysctl_output.field(name).is_none());
300179
}
301180
}

0 commit comments

Comments
 (0)