From 62db9526159ad17c5c868faa79f6e4e634665b7a Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 27 Mar 2023 00:46:52 +0900 Subject: [PATCH] detect: Support run-time detection on aarch64 NetBSD --- .github/.cspell/project-dictionary.txt | 11 + src/imp/atomic128/README.md | 2 +- src/imp/atomic128/aarch64.rs | 4 +- src/imp/atomic128/detect/aarch64_aa64reg.rs | 347 +++++++++++++++++- .../gen/sys/aarch64_netbsd/aarch64_armreg.rs | 27 ++ .../helper/src/gen/sys/aarch64_netbsd/mod.rs | 9 + .../src/gen/sys/aarch64_netbsd/sys_sysctl.rs | 26 ++ tests/helper/src/gen/sys/mod.rs | 4 + tools/build.sh | 1 + tools/codegen/src/ffi.rs | 54 ++- 10 files changed, 478 insertions(+), 7 deletions(-) create mode 100644 tests/helper/src/gen/sys/aarch64_netbsd/aarch64_armreg.rs create mode 100644 tests/helper/src/gen/sys/aarch64_netbsd/mod.rs create mode 100644 tests/helper/src/gen/sys/aarch64_netbsd/sys_sysctl.rs diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt index 98bf1e34..4abf00cf 100644 --- a/.github/.cspell/project-dictionary.txt +++ b/.github/.cspell/project-dictionary.txt @@ -5,6 +5,7 @@ alcgr algr armasm armel +armreg autogen auxv auxvec @@ -20,6 +21,7 @@ cdsg cfgs cinc cirruslabs +clidr cmovae cmovb cmovge @@ -32,6 +34,7 @@ cpsid cpsie CPSR cpuid +cpus crand crandc cror @@ -76,16 +79,23 @@ memcpy metavar mfence mgba +midr miscompilation mmfr moreutils +mpidr mstatus +mvfr +NCPU +NCPUONLINE negs neoverse newrepo newtype nographic nostdinc +NPROCESSORS +ONLN opensbi osfmk osxsave @@ -98,6 +108,7 @@ qword RAII rcpc reentrancy +revidr sbcs seqlock setb diff --git a/src/imp/atomic128/README.md b/src/imp/atomic128/README.md index fb8578f5..edc1b856 100644 --- a/src/imp/atomic128/README.md +++ b/src/imp/atomic128/README.md @@ -29,7 +29,7 @@ Here is the table of targets that support run-time feature detection and the ins | aarch64 | linux-gnu/android | getauxval | | aarch64 | other linux | dlsym(getauxval) (via is_aarch64_feature_detected) | | aarch64 | freebsd | elf_aux_info | -| aarch64 | macos/openbsd | sysctl | +| aarch64 | macos/netbsd/openbsd | sysctl | | aarch64 | windows | IsProcessorFeaturePresent | | aarch64 | fuchsia | zx_system_get_features | diff --git a/src/imp/atomic128/aarch64.rs b/src/imp/atomic128/aarch64.rs index 1f377a8f..04e1c46c 100644 --- a/src/imp/atomic128/aarch64.rs +++ b/src/imp/atomic128/aarch64.rs @@ -61,7 +61,7 @@ include!("macros.rs"); #[path = "detect/aarch64_auxv.rs"] mod detect; #[cfg(not(portable_atomic_no_outline_atomics))] -#[cfg(target_os = "openbsd")] +#[cfg(any(target_os = "netbsd", target_os = "openbsd"))] #[path = "detect/aarch64_aa64reg.rs"] mod detect; #[cfg(not(portable_atomic_no_outline_atomics))] @@ -313,6 +313,7 @@ unsafe fn atomic_compare_exchange( target_os = "linux", target_os = "android", target_os = "freebsd", + target_os = "netbsd", target_os = "openbsd", target_os = "fuchsia", target_os = "windows", @@ -328,6 +329,7 @@ unsafe fn atomic_compare_exchange( target_os = "linux", target_os = "android", target_os = "freebsd", + target_os = "netbsd", target_os = "openbsd", target_os = "fuchsia", target_os = "windows", diff --git a/src/imp/atomic128/detect/aarch64_aa64reg.rs b/src/imp/atomic128/detect/aarch64_aa64reg.rs index 9aece56e..34a77f7b 100644 --- a/src/imp/atomic128/detect/aarch64_aa64reg.rs +++ b/src/imp/atomic128/detect/aarch64_aa64reg.rs @@ -1,6 +1,6 @@ -// Run-time feature detection on aarch64 Linux/FreeBSD/OpenBSD by parsing system registers. +// Run-time feature detection on aarch64 Linux/FreeBSD/NetBSD/OpenBSD by parsing system registers. // -// As of nightly-2023-01-23, is_aarch64_feature_detected doesn't support run-time detection on OpenBSD. +// As of nightly-2023-01-23, is_aarch64_feature_detected doesn't support run-time detection on NetBSD/OpenBSD. // https://github.com/rust-lang/stdarch/blob/a0c30f3e3c75adcd6ee7efc94014ebcead61c507/crates/std_detect/src/detect/mod.rs // https://github.com/rust-lang/stdarch/pull/1374 // @@ -14,10 +14,12 @@ // https://github.com/torvalds/linux/commit/77c97b4ee21290f5f083173d957843b615abbff2 // - FreeBSD 12.0+ (emulate mrs instruction) // https://github.com/freebsd/freebsd-src/commit/398810619cb32abf349f8de23f29510b2ee0839b +// - NetBSD 9.0+ (through sysctl) +// https://github.com/NetBSD/src/commit/70057642485887b9601804adb983c70d11e48d9a // - OpenBSD 7.1+ (through sysctl) // https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 // -// For now, this module is only used on OpenBSD. +// For now, this module is only used on NetBSD/OpenBSD. // - On Linux, this module is test-only because this approach requires a higher // kernel version than Rust supports, and also does not work with qemu-user // (as of QEMU 7.2) and Valgrind. (Looking into HWCAP_CPUID in auxvec, it @@ -37,6 +39,7 @@ include!("common.rs"); +#[cfg_attr(target_os = "netbsd", derive(Default, PartialEq))] struct AA64Reg { aa64isar0: u64, #[cfg(test)] @@ -88,7 +91,7 @@ fn extract(x: u64, high: usize, low: usize) -> u64 { (x >> low) & ((1 << (high - low + 1)) - 1) } -#[cfg(not(target_os = "openbsd"))] +#[cfg(not(any(target_os = "netbsd", target_os = "openbsd")))] mod imp { // This module is test-only. See parent module docs for details. @@ -138,6 +141,250 @@ mod imp { } } } +#[cfg(target_os = "netbsd")] +mod imp { + // NetBSD doesn't trap the mrs instruction, but exposes the system registers through sysctl. + // https://github.com/NetBSD/src/commit/70057642485887b9601804adb983c70d11e48d9a + // https://github.com/golang/sys/commit/ef9fd89ba245e184bdd308f7f2b4f3c551fa5b0f + + use core::ptr; + + use super::AA64Reg; + + // core::ffi::c_* (except c_void) requires Rust 1.64 + #[allow(non_camel_case_types)] + pub(super) mod ffi { + pub(crate) use core::ffi::c_void; + // c_char is u8 on aarch64 netbsd + // https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L104-L157 + // https://github.com/rust-lang/libc/blob/0.2.139/src/unix/bsd/netbsdlike/netbsd/aarch64.rs#L5 + pub(crate) type c_char = u8; + // c_{,u}int is {i,u}32 on non-16-bit architectures + // https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L159-L173 + pub(crate) type c_int = i32; + pub(crate) type c_uint = u32; + // c_size_t is usize + // https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L83-L88 + pub(crate) type c_size_t = usize; + + extern "C" { + // Defined in sys/sysctl.h. + // https://man.netbsd.org/sysctl.3 + // https://github.com/rust-lang/libc/blob/0.2.139/src/unix/bsd/netbsdlike/netbsd/mod.rs#L2574 + pub(crate) fn sysctl( + name: *const c_int, + name_len: c_uint, + old_p: *mut c_void, + old_len_p: *mut c_size_t, + new_p: *const c_void, + new_len: c_size_t, + ) -> c_int; + pub(crate) fn sysctlbyname( + name: *const c_char, + old_p: *mut c_void, + old_len_p: *mut c_size_t, + new_p: *const c_void, + new_len: c_size_t, + ) -> c_int; + } + + // Defined in aarch64/armreg.h. + // https://github.com/NetBSD/src/blob/49ff686c908df01d34af98d7a46d51aabe7008fa/sys/arch/aarch64/include/armreg.h#L1626 + #[derive(Clone, Copy)] + #[repr(C)] + pub(crate) struct aarch64_sysctl_cpu_id { + // NetBSD 9.0+ + // https://github.com/NetBSD/src/commit/70057642485887b9601804adb983c70d11e48d9a + pub(crate) _midr: u64, /* Main ID Register */ + pub(crate) _revidr: u64, /* Revision ID Register */ + pub(crate) _mpidr: u64, /* Multiprocessor Affinity Register */ + pub(crate) _aa64dfr0: u64, /* A64 Debug Feature Register 0 */ + pub(crate) _aa64dfr1: u64, /* A64 Debug Feature Register 1 */ + pub(crate) _aa64isar0: u64, /* A64 Instruction Set Attribute Register 0 */ + pub(crate) _aa64isar1: u64, /* A64 Instruction Set Attribute Register 1 */ + pub(crate) _aa64mmfr0: u64, /* A64 Memory Model Feature Register 0 */ + pub(crate) _aa64mmfr1: u64, /* A64 Memory Model Feature Register 1 */ + pub(crate) _aa64mmfr2: u64, /* A64 Memory Model Feature Register 2 */ + pub(crate) _aa64pfr0: u64, /* A64 Processor Feature Register 0 */ + pub(crate) _aa64pfr1: u64, /* A64 Processor Feature Register 1 */ + pub(crate) _aa64zfr0: u64, /* A64 SVE Feature ID Register 0 */ + pub(crate) _mvfr0: u32, /* Media and VFP Feature Register 0 */ + pub(crate) _mvfr1: u32, /* Media and VFP Feature Register 1 */ + pub(crate) _mvfr2: u32, /* Media and VFP Feature Register 2 */ + // NetBSD 10.0+ + // https://github.com/NetBSD/src/commit/908d3fadf77e1b392db35d1076f7f9961c1d351d + pub(crate) _pad: u32, + pub(crate) _clidr: u64, /* Cache Level ID Register */ + pub(crate) _ctr: u64, /* Cache Type Register */ + } + + // Defined in sys/sysctl.h. + // https://github.com/NetBSD/src/blob/49ff686c908df01d34af98d7a46d51aabe7008fa/sys/sys/sysctl.h + pub(crate) const CTL_HW: c_int = 6; + pub(crate) const HW_NCPU: c_int = 3; + } + + #[inline] + fn sysctl32(mib: &[ffi::c_int]) -> Option { + const OUT_LEN: ffi::c_size_t = core::mem::size_of::() as ffi::c_size_t; + let mut out = 0_u32; + let mut out_len = OUT_LEN; + #[allow(clippy::cast_possible_truncation)] + // SAFETY: + // - `mib.len()` does not exceed the size of `mib`. + // - `out_len` does not exceed the size of `out`. + // - `sysctl` is thread-safe. + let res = unsafe { + ffi::sysctl( + mib.as_ptr(), + mib.len() as ffi::c_uint, + (&mut out as *mut u32).cast::(), + &mut out_len, + ptr::null_mut(), + 0, + ) + }; + if res == -1 { + return None; + } + debug_assert_eq!(out_len, OUT_LEN); + Some(out) + } + + #[allow(clippy::used_underscore_binding)] + #[inline] + unsafe fn sysctl_cpu_id(buf: &mut ffi::aarch64_sysctl_cpu_id, name: &[u8]) -> Option { + const OUT_LEN: ffi::c_size_t = + core::mem::size_of::() as ffi::c_size_t; + + debug_assert_eq!(name.last(), Some(&0), "{:?}", name); + debug_assert_eq!(name.iter().filter(|&&v| v == 0).count(), 1, "{:?}", name); + + let mut out_len = OUT_LEN; + // SAFETY: + // - the caller must guarantee that `name` is ` machdep.cpuN.cpu_id` in a C string. + // - `out_len` does not exceed the size of the value at `buf`. + // - `sysctlbyname` is thread-safe. + let res = unsafe { + ffi::sysctlbyname( + name.as_ptr().cast::(), + (buf as *mut ffi::aarch64_sysctl_cpu_id).cast::(), + &mut out_len, + ptr::null_mut(), + 0, + ) + }; + if res != 0 { + return None; + } + Some(AA64Reg { + aa64isar0: buf._aa64isar0, + #[cfg(test)] + aa64isar1: buf._aa64isar1, + #[cfg(test)] + aa64mmfr2: buf._aa64mmfr2, + }) + } + + #[inline] + pub(super) fn aa64reg() -> AA64Reg { + // SAFETY: all fields of aarch64_sysctl_cpu_id are zero-able and we use + // the result when machdep.cpuN.cpu_id sysctl was successful. + let mut cpu_id_buf: ffi::aarch64_sysctl_cpu_id = unsafe { core::mem::zeroed() }; + // First, get system registers for cpu0. + // If failed, returns default because machdep.cpuN.cpu_id sysctl is not available. + // machdep.cpuN.cpu_id sysctl was added on NetBSD 9.0 so it is not available on older versions. + // SAFETY: we passed a valid name in a C string. + let cpu0 = match unsafe { sysctl_cpu_id(&mut cpu_id_buf, b"machdep.cpu0.cpu_id\0") } { + Some(cpu0) => cpu0, + None => return AA64Reg::default(), + }; + // Second, get the number of cpus. + // If failed, returns default because nothing can be assumed about the other cores. + // Do not use available_parallelism/_SC_NPROCESSORS_ONLN/HW_NCPUONLINE because + // offline cores may become online during execution. + let cpus = match sysctl32(&[ffi::CTL_HW, ffi::HW_NCPU]) { + Some(0) | None => return AA64Reg::default(), // failed + Some(1) => return cpu0, // single-core + Some(cpus) => cpus, + }; + // Unfortunately, there is a bug in Samsung's SoC that supports + // different CPU features in big and little cores. + // https://web.archive.org/web/20210908112244/https://medium.com/@niaow/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb + // https://github.com/golang/go/issues/28431#issuecomment-433573689 + // https://en.wikichip.org/wiki/samsung/exynos/9810 + // So, make sure that all cores provide the same CPU features. + // Note that we are only checking the consistency of the registers to + // which we actually refer. (If we check all registers, fields such as + // product variant are also checked, which breaks runtime detection on + // most big.LITTLE SoCs.) + let mut name_buf = MachdepNameBuffer::new(); + for n in 1..cpus { + // SAFETY: MachdepNameBuffer::name returns a valid name in a C string. + let cpu = match unsafe { sysctl_cpu_id(&mut cpu_id_buf, name_buf.name(n)) } { + Some(cpu) => cpu, + None => return AA64Reg::default(), + }; + if cpu != cpu0 { + return AA64Reg::default(); + } + } + cpu0 + } + + pub(super) struct MachdepNameBuffer { + buf: [u8; NAME_MAX_LEN], + } + + const NAME_PREFIX: &[u8] = b"machdep.cpu"; + const NAME_SUFFIX: &[u8] = b".cpu_id\0"; + pub(super) const U32_MAX_LEN: usize = 10; + const NAME_MAX_LEN: usize = NAME_PREFIX.len() + NAME_SUFFIX.len() + U32_MAX_LEN; + + impl MachdepNameBuffer { + #[inline] + pub(super) fn new() -> Self { + let mut buf: [u8; NAME_MAX_LEN] = [0; NAME_MAX_LEN]; + buf[..NAME_PREFIX.len()].copy_from_slice(NAME_PREFIX); + Self { buf } + } + + #[allow(clippy::cast_possible_truncation, clippy::unreadable_literal)] + #[inline] + pub(super) fn name(&mut self, mut cpu: u32) -> &[u8] { + let mut len = NAME_PREFIX.len(); + // integer -> string conversion which is optimized for small numbers. + macro_rules! put { + ($cur:tt $($tt:tt)*) => { + if cpu >= $cur { + put!($($tt)*); + let n = cpu / $cur; + self.buf[len] = (n as u8) + b'0'; + len += 1; + cpu %= $cur; + } + }; + () => {}; + } + put!( + 10 + 100 + 1000 + 10000 + 100000 + 1000000 + 10000000 + 100000000 + 1000000000 + ); + self.buf[len] = (cpu as u8) + b'0'; + len += 1; + self.buf[len..len + NAME_SUFFIX.len()].copy_from_slice(NAME_SUFFIX); + len += NAME_SUFFIX.len(); + &self.buf[..len] + } + } +} #[cfg(target_os = "openbsd")] mod imp { // OpenBSD doesn't trap the mrs instruction, but exposes the system registers through sysctl. @@ -301,6 +548,77 @@ mod tests { // without actually running tests on these platforms. // See also tools/codegen/src/ffi.rs. // TODO: auto-generate this test + #[cfg(target_os = "netbsd")] + #[allow( + clippy::cast_possible_wrap, + clippy::cast_sign_loss, + clippy::no_effect_underscore_binding, + clippy::used_underscore_binding + )] + const _: fn() = || { + use core::mem::size_of; + use imp::ffi; + use test_helper::{libc, sys}; + let _: ffi::c_char = 0 as std::os::raw::c_char; + let _: ffi::c_int = 0 as std::os::raw::c_int; + let _: ffi::c_uint = 0 as std::os::raw::c_uint; + let _: ffi::c_char = 0 as libc::c_char; + let _: ffi::c_int = 0 as libc::c_int; + let _: ffi::c_uint = 0 as libc::c_uint; + let _: ffi::c_size_t = 0 as libc::size_t; + let mut _sysctl: unsafe extern "C" fn( + *const ffi::c_int, + ffi::c_uint, + *mut ffi::c_void, + *mut ffi::c_size_t, + *const ffi::c_void, + ffi::c_size_t, + ) -> ffi::c_int = ffi::sysctl; + _sysctl = libc::sysctl; + _sysctl = sys::sysctl; + let mut _sysctlbyname: unsafe extern "C" fn( + *const ffi::c_char, + *mut ffi::c_void, + *mut ffi::c_size_t, + *const ffi::c_void, + ffi::c_size_t, + ) -> ffi::c_int = ffi::sysctlbyname; + _sysctlbyname = libc::sysctlbyname; + _sysctlbyname = sys::sysctlbyname; + static_assert!(ffi::CTL_HW == libc::CTL_HW); + static_assert!(ffi::CTL_HW == sys::CTL_HW as ffi::c_int); + static_assert!(ffi::HW_NCPU == libc::HW_NCPU); + static_assert!(ffi::HW_NCPU == sys::HW_NCPU as ffi::c_int); + // libc doesn't have this + // static_assert!( + // size_of::() == size_of::() + // ); + static_assert!( + size_of::() == size_of::() + ); + let ffi: ffi::aarch64_sysctl_cpu_id = unsafe { core::mem::zeroed() }; + let _ = sys::aarch64_sysctl_cpu_id { + ac_midr: ffi._midr, + ac_revidr: ffi._revidr, + ac_mpidr: ffi._mpidr, + ac_aa64dfr0: ffi._aa64dfr0, + ac_aa64dfr1: ffi._aa64dfr1, + ac_aa64isar0: ffi._aa64isar0, + ac_aa64isar1: ffi._aa64isar1, + ac_aa64mmfr0: ffi._aa64mmfr0, + ac_aa64mmfr1: ffi._aa64mmfr1, + ac_aa64mmfr2: ffi._aa64mmfr2, + ac_aa64pfr0: ffi._aa64pfr0, + ac_aa64pfr1: ffi._aa64pfr1, + ac_aa64zfr0: ffi._aa64zfr0, + ac_mvfr0: ffi._mvfr0, + ac_mvfr1: ffi._mvfr1, + ac_mvfr2: ffi._mvfr2, + ac_pad: ffi._pad, + ac_clidr: ffi._clidr, + ac_ctr: ffi._ctr, + }; + }; #[cfg(target_os = "openbsd")] #[allow( clippy::cast_possible_wrap, @@ -334,4 +652,25 @@ mod tests { // static_assert!(ffi::CPU_ID_AA64MMFR2 == libc::CPU_ID_AA64MMFR2); // libc doesn't have this static_assert!(ffi::CPU_ID_AA64MMFR2 == sys::CPU_ID_AA64MMFR2 as ffi::c_int); }; + + #[cfg(target_os = "netbsd")] + #[test] + fn machdep_name_buffer() { + use std::string::ToString; + assert_eq!(u32::MAX.to_string().len(), imp::U32_MAX_LEN); + assert_eq!(imp::MachdepNameBuffer::new().name(0), b"machdep.cpu0.cpu_id\0"); + assert_eq!(imp::MachdepNameBuffer::new().name(1), b"machdep.cpu1.cpu_id\0"); + assert_eq!(imp::MachdepNameBuffer::new().name(10), b"machdep.cpu10.cpu_id\0"); + assert_eq!(imp::MachdepNameBuffer::new().name(100), b"machdep.cpu100.cpu_id\0"); + assert_eq!(imp::MachdepNameBuffer::new().name(1023), b"machdep.cpu1023.cpu_id\0"); + assert_eq!(imp::MachdepNameBuffer::new().name(u32::MAX), b"machdep.cpu4294967295.cpu_id\0"); + } + #[cfg(target_os = "netbsd")] + ::quickcheck::quickcheck! { + fn quickcheck_machdep_name_buffer(x: u32) -> bool { + let expected = std::ffi::CString::new(std::format!("machdep.cpu{}.cpu_id", x)).unwrap(); + assert_eq!(imp::MachdepNameBuffer::new().name(x), expected.into_bytes_with_nul()); + true + } + } } diff --git a/tests/helper/src/gen/sys/aarch64_netbsd/aarch64_armreg.rs b/tests/helper/src/gen/sys/aarch64_netbsd/aarch64_armreg.rs new file mode 100644 index 00000000..70c8a0be --- /dev/null +++ b/tests/helper/src/gen/sys/aarch64_netbsd/aarch64_armreg.rs @@ -0,0 +1,27 @@ +// This file is @generated by portable-atomic-internal-codegen +// (gen function at tools/codegen/src/ffi.rs). +// It is not intended for manual editing. + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct aarch64_sysctl_cpu_id { + pub ac_midr: u64, + pub ac_revidr: u64, + pub ac_mpidr: u64, + pub ac_aa64dfr0: u64, + pub ac_aa64dfr1: u64, + pub ac_aa64isar0: u64, + pub ac_aa64isar1: u64, + pub ac_aa64mmfr0: u64, + pub ac_aa64mmfr1: u64, + pub ac_aa64mmfr2: u64, + pub ac_aa64pfr0: u64, + pub ac_aa64pfr1: u64, + pub ac_aa64zfr0: u64, + pub ac_mvfr0: u32, + pub ac_mvfr1: u32, + pub ac_mvfr2: u32, + pub ac_pad: u32, + pub ac_clidr: u64, + pub ac_ctr: u64, +} diff --git a/tests/helper/src/gen/sys/aarch64_netbsd/mod.rs b/tests/helper/src/gen/sys/aarch64_netbsd/mod.rs new file mode 100644 index 00000000..e5682f56 --- /dev/null +++ b/tests/helper/src/gen/sys/aarch64_netbsd/mod.rs @@ -0,0 +1,9 @@ +// This file is @generated by portable-atomic-internal-codegen +// (gen function at tools/codegen/src/ffi.rs). +// It is not intended for manual editing. + +#![cfg_attr(rustfmt, rustfmt::skip)] +mod sys_sysctl; +pub use sys_sysctl::{CTL_HW, HW_NCPU, sysctl, sysctlbyname}; +mod aarch64_armreg; +pub use aarch64_armreg::aarch64_sysctl_cpu_id; diff --git a/tests/helper/src/gen/sys/aarch64_netbsd/sys_sysctl.rs b/tests/helper/src/gen/sys/aarch64_netbsd/sys_sysctl.rs new file mode 100644 index 00000000..eec654c5 --- /dev/null +++ b/tests/helper/src/gen/sys/aarch64_netbsd/sys_sysctl.rs @@ -0,0 +1,26 @@ +// This file is @generated by portable-atomic-internal-codegen +// (gen function at tools/codegen/src/ffi.rs). +// It is not intended for manual editing. + +pub const CTL_HW: u32 = 6; +pub const HW_NCPU: u32 = 3; +pub type u_int = ::std::os::raw::c_uint; +extern "C" { + pub fn sysctl( + arg1: *const ::std::os::raw::c_int, + arg2: u_int, + arg3: *mut ::core::ffi::c_void, + arg4: *mut usize, + arg5: *const ::core::ffi::c_void, + arg6: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn sysctlbyname( + arg1: *const ::std::os::raw::c_char, + arg2: *mut ::core::ffi::c_void, + arg3: *mut usize, + arg4: *const ::core::ffi::c_void, + arg5: usize, + ) -> ::std::os::raw::c_int; +} diff --git a/tests/helper/src/gen/sys/mod.rs b/tests/helper/src/gen/sys/mod.rs index 69eec625..c710d92a 100644 --- a/tests/helper/src/gen/sys/mod.rs +++ b/tests/helper/src/gen/sys/mod.rs @@ -58,6 +58,10 @@ pub use aarch64_apple_darwin::*; mod aarch64_freebsd; #[cfg(all(target_arch = "aarch64", target_os = "freebsd"))] pub use aarch64_freebsd::*; +#[cfg(all(target_arch = "aarch64", target_os = "netbsd"))] +mod aarch64_netbsd; +#[cfg(all(target_arch = "aarch64", target_os = "netbsd"))] +pub use aarch64_netbsd::*; #[cfg(all(target_arch = "aarch64", target_os = "openbsd"))] mod aarch64_openbsd; #[cfg(all(target_arch = "aarch64", target_os = "openbsd"))] diff --git a/tools/build.sh b/tools/build.sh index bbf153c5..5853658c 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -60,6 +60,7 @@ default_targets=( aarch64-unknown-linux-gnu aarch64-unknown-linux-musl aarch64-unknown-linux-uclibc # custom target + aarch64-unknown-netbsd aarch64-unknown-openbsd # aarch64 always support lse & lse2 aarch64-apple-darwin diff --git a/tools/codegen/src/ffi.rs b/tools/codegen/src/ffi.rs index 5095dda7..7cc51245 100644 --- a/tools/codegen/src/ffi.rs +++ b/tools/codegen/src/ffi.rs @@ -93,6 +93,25 @@ static TARGETS: &[Target] = &[ }, ], }, + Target { + triples: &["aarch64-unknown-netbsd"], + headers: &[ + Header { + // https://github.com/NetBSD/src/blob/HEAD/sys/sys/sysctl.h + path: "sys/sysctl.h", + types: &[], + vars: &["CTL_HW", "HW_NCPU"], + functions: &["sysctl", "sysctlbyname"], + }, + Header { + // https://github.com/NetBSD/src/blob/HEAD/sys/arch/aarch64/include/armreg.h + path: "aarch64/armreg.h", + types: &["aarch64_sysctl_cpu_id"], + vars: &[], + functions: &[], + }, + ], + }, Target { triples: &["aarch64-unknown-openbsd"], headers: &[ @@ -214,6 +233,12 @@ pub(crate) fn gen() -> Result<()> { src_dir.parent().unwrap().join("libpthread/include"), ], freebsd | openbsd => vec![src_dir.join("sys")], + netbsd => vec![ + src_dir.join("sys"), + src_dir.join("sys/sys"), + src_dir.join("include"), + src_dir.join("lib/libpthread"), + ], fuchsia => vec![src_dir.join("zircon/system/public")], _ => todo!("{target:?}"), }; @@ -237,7 +262,7 @@ pub(crate) fn gen() -> Result<()> { let header_path = match target.os { linux | android => src_dir.join(header.path), macos => src_dir.join(format!("bsd/{}", header.path)), - freebsd | openbsd => src_dir.join(format!("sys/{}", header.path)), + freebsd | netbsd | openbsd => src_dir.join(format!("sys/{}", header.path)), fuchsia => src_dir.join(header.path), _ => todo!("{target:?}"), }; @@ -288,6 +313,12 @@ pub(crate) fn gen() -> Result<()> { } } } + syn::Item::Struct(i) + if matches!(i.vis, syn::Visibility::Public(..)) + && types.is_match(&i.ident.to_string()) => + { + uses.insert(format_ident!("{}", i.ident)); + } syn::Item::Type(i) if matches!(i.vis, syn::Visibility::Public(..)) && types.is_match(&i.ident.to_string()) => @@ -349,6 +380,7 @@ fn git_clone(target: &TargetSpec, download_cache_dir: &Utf8Path) -> Result clone(download_cache_dir, "https://github.com/freebsd/freebsd-src.git")?, + netbsd => clone(download_cache_dir, "https://github.com/NetBSD/src.git")?, openbsd => clone(download_cache_dir, "https://github.com/openbsd/src.git")?, fuchsia => clone(download_cache_dir, "https://fuchsia.googlesource.com/fuchsia")?, _ => todo!("{target:?}"), @@ -384,6 +416,26 @@ fn arch_symlink(target: &TargetSpec, src_dir: &Utf8Path) -> Result<()> { let link = &src_dir.join("sys/machine"); fs::os::unix::fs::symlink(src_dir.join("sys").join(arch).join("include"), link)?; } + netbsd => { + let arch = match target.arch { + aarch64 => "aarch64", + _ => todo!("{target:?}"), + }; + let link1 = &src_dir.join("sys").join(arch); + let link2 = &src_dir.join("sys/machine"); + let link3 = match target.arch { + aarch64 => Some(("arm", src_dir.join("sys/arm"))), + _ => None, + }; + fs::os::unix::fs::symlink(src_dir.join("sys/arch").join(arch).join("include"), link1)?; + fs::os::unix::fs::symlink(src_dir.join("sys/arch").join(arch).join("include"), link2)?; + if let Some((arch, link)) = &link3 { + fs::os::unix::fs::symlink( + src_dir.join("sys/arch").join(arch).join("include"), + link, + )?; + } + } openbsd => { let arch = match target.arch { aarch64 => "arm64",