Skip to content

Commit

Permalink
detect: Add test-only alternative implementations for NetBSD
Browse files Browse the repository at this point in the history
Similar to a6c880c, but for NetBSD.
  • Loading branch information
taiki-e committed Sep 12, 2023
1 parent f8e04b5 commit 49df0a5
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 4 deletions.
1 change: 1 addition & 0 deletions .github/.cspell/project-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ subfze
swpp
syscall
sysctlbyname
sysctlnode
sysdeps
systemsim
tagme
Expand Down
142 changes: 141 additions & 1 deletion src/imp/atomic128/detect/aarch64_aa64reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

include!("common.rs");

#[cfg_attr(test, derive(Debug, PartialEq))]
struct AA64Reg {
aa64isar0: u64,
#[cfg(test)]
Expand Down Expand Up @@ -191,7 +192,7 @@ mod imp {
}
}

unsafe fn sysctl_cpu_id(name: &[u8]) -> Option<AA64Reg> {
pub(super) unsafe fn sysctl_cpu_id(name: &[u8]) -> Option<AA64Reg> {
const OUT_LEN: ffi::c_size_t =
core::mem::size_of::<ffi::aarch64_sysctl_cpu_id>() as ffi::c_size_t;

Expand Down Expand Up @@ -394,6 +395,145 @@ mod tests {
}
}

#[allow(clippy::cast_possible_wrap)]
#[cfg(target_os = "netbsd")]
#[test]
fn test_netbsd() {
use c_types::*;
use core::{arch::asm, mem, ptr};
use imp::ffi;
use test_helper::sys;

// Call syscall using asm instead of libc.
// Note that NetBSD does not guarantee the stability of raw syscall as
// much as Linux does (It may actually be stable enough, though: https://lists.llvm.org/pipermail/llvm-dev/2019-June/133393.html).
//
// This is currently used only for testing.
unsafe fn sysctl_cpu_id_asm_syscall(name: &[&[u8]]) -> Result<AA64Reg, c_int> {
// https://github.com/golang/go/blob/4badad8d477ffd7a6b762c35bc69aed82faface7/src/syscall/asm_netbsd_arm64.s
#[inline]
unsafe 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,
) -> Result<c_int, c_int> {
#[allow(clippy::cast_possible_truncation)]
// SAFETY: the caller must uphold the safety contract.
unsafe {
let mut n = sys::SYS___sysctl as u64;
let r: i64;
asm!(
"svc 0",
"b.cc 2f",
"mov x17, x0",
"mov x0, #-1",
"2:",
inout("x17") n,
inout("x0") ptr_reg!(name) => r,
inout("x1") name_len as u64 => _,
in("x2") ptr_reg!(old_p),
in("x3") ptr_reg!(old_len_p),
in("x4") ptr_reg!(new_p),
in("x5") new_len as u64,
options(nostack),
);
if r as c_int == -1 {
Err(n as c_int)
} else {
Ok(r as c_int)
}
}
}

// https://github.com/golang/sys/blob/4badad8d477ffd7a6b762c35bc69aed82faface7/cpu/cpu_netbsd_arm64.go.
use std::{vec, vec::Vec};
fn sysctl_nodes(mib: &mut Vec<i32>) -> Result<Vec<sys::sysctlnode>, i32> {
mib.push(sys::CTL_QUERY);
let mut q_node = sys::sysctlnode {
sysctl_flags: sys::SYSCTL_VERS_1,
..unsafe { mem::zeroed() }
};
let qp = (&mut q_node as *mut sys::sysctlnode).cast::<ffi::c_void>();
let sz = mem::size_of::<sys::sysctlnode>();
let mut olen = 0;
#[allow(clippy::cast_possible_truncation)]
unsafe {
sysctl(mib.as_ptr(), mib.len() as c_uint, ptr::null_mut(), &mut olen, qp, sz)?;
}

let mut nodes = Vec::<sys::sysctlnode>::with_capacity(olen / sz);
let np = nodes.as_mut_ptr().cast::<ffi::c_void>();
#[allow(clippy::cast_possible_truncation)]
unsafe {
sysctl(mib.as_ptr(), mib.len() as c_uint, np, &mut olen, qp, sz)?;
nodes.set_len(olen / sz);
}

mib.pop(); // pop CTL_QUERY
Ok(nodes)
}
fn name_to_mib(parts: &[&[u8]]) -> Result<Vec<i32>, i32> {
let mut mib = vec![];
for (part_no, &part) in parts.iter().enumerate() {
let nodes = sysctl_nodes(&mut mib)?;
for node in nodes {
let mut n = vec![];
for b in node.sysctl_name {
if b != 0 {
n.push(b);
}
}
if n == part {
mib.push(node.sysctl_num);
break;
}
}
if mib.len() != part_no + 1 {
return Err(0);
}
}

Ok(mib)
}

const OUT_LEN: ffi::c_size_t =
core::mem::size_of::<ffi::aarch64_sysctl_cpu_id>() as ffi::c_size_t;

let mib = name_to_mib(name)?;

let mut buf: ffi::aarch64_sysctl_cpu_id = unsafe { core::mem::zeroed() };
let mut out_len = OUT_LEN;
#[allow(clippy::cast_possible_truncation)]
unsafe {
sysctl(
mib.as_ptr(),
mib.len() as c_uint,
(&mut buf as *mut ffi::aarch64_sysctl_cpu_id).cast::<ffi::c_void>(),
&mut out_len,
ptr::null_mut(),
0,
)?;
}
Ok(AA64Reg {
aa64isar0: buf.aa64isar0,
#[cfg(test)]
aa64isar1: buf.aa64isar1,
#[cfg(test)]
aa64mmfr2: buf.aa64mmfr2,
})
}

unsafe {
assert_eq!(
imp::sysctl_cpu_id(b"machdep.cpu0.cpu_id\0").unwrap(),
sysctl_cpu_id_asm_syscall(&[b"machdep", b"cpu0", b"cpu_id"]).unwrap()
);
}
}

// Static assertions for FFI bindings.
// This checks that FFI bindings defined in this crate, FFI bindings defined
// in libc, and FFI bindings generated for the platform's latest header file
Expand Down
27 changes: 27 additions & 0 deletions tests/helper/src/gen/sys/aarch64_be_netbsd/aarch64_armreg.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions tests/helper/src/gen/sys/aarch64_be_netbsd/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions tests/helper/src/gen/sys/aarch64_be_netbsd/sys_syscall.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 142 additions & 0 deletions tests/helper/src/gen/sys/aarch64_be_netbsd/sys_sysctl.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions tests/helper/src/gen/sys/aarch64_netbsd/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions tests/helper/src/gen/sys/aarch64_netbsd/sys_syscall.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 49df0a5

Please sign in to comment.