use alloc::boxed::Box;
use core::any::Any;
use core::arch::asm;
use core::ffi::c_void;
use linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap};
use rustix::process::RawPid;
#[inline]
pub(super) unsafe fn clone(
flags: u32,
child_stack: *mut c_void,
parent_tid: *mut RawPid,
newtls: *mut c_void,
child_tid: *mut RawPid,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>>>,
) -> isize {
let r0;
asm!(
"ecall",
"bnez a0,0f",
"mv a0,{fn_}", "mv fp, zero", "mv ra, zero", "tail {entry}",
"0:",
entry = sym super::threads::entry,
fn_ = in(reg) fn_,
in("a7") __NR_clone,
inlateout("a0") flags as isize => r0,
in("a1") child_stack,
in("a2") parent_tid,
in("a3") newtls,
in("a4") child_tid,
options(nostack)
);
r0
}
#[cfg(target_vendor = "mustang")]
#[inline]
pub(super) unsafe fn set_thread_pointer(ptr: *mut c_void) {
asm!("mv tp,{0}", in(reg) ptr);
debug_assert_eq!(get_thread_pointer(), ptr);
}
#[inline]
pub(super) fn get_thread_pointer() -> *mut c_void {
let ptr;
unsafe {
asm!("mv {0},tp", out(reg) ptr, options(nostack, preserves_flags, readonly));
}
ptr
}
pub(super) const TLS_OFFSET: usize = 0x800;
#[inline]
pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usize) -> ! {
asm!(
"ecall",
"mv a0,zero",
"li a7,{__NR_exit}",
"ecall",
"unimp",
__NR_exit = const __NR_exit,
in("a7") __NR_munmap,
in("a0") map_addr,
in("a1") map_len,
options(noreturn, nostack)
);
}