Forked from
redox-os / relibc
762 commits behind the upstream repository.
-
coolreader18 authoredcoolreader18 authored
clone.rs 4.22 KiB
use syscall::{
data::Map,
error::Result,
flag::{MapFlags, O_CLOEXEC},
SIGCONT,
};
use super::extra::{create_set_addr_space_buf, FdGuard};
pub use redox_exec::*;
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<usize> {
let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?);
let (new_pid_fd, new_pid) = new_context()?;
// Allocate a new signal stack.
{
let sigstack_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sigstack")?);
const SIGSTACK_SIZE: usize = 1024 * 256;
// TODO: Put sigstack at high addresses?
let target_sigstack = syscall::fmap(
!0,
&Map {
address: 0,
flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
offset: 0,
size: SIGSTACK_SIZE,
},
)? + SIGSTACK_SIZE;
let _ = syscall::write(*sigstack_fd, &usize::to_ne_bytes(target_sigstack))?;
}
copy_str(*cur_pid_fd, *new_pid_fd, "name")?;
// Reuse existing address space
{
let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?);
let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?);
let buf = create_set_addr_space_buf(
*cur_addr_space_fd,
__relibc_internal_rlct_clone_ret as usize,
stack as usize,
);
let _ = syscall::write(*new_addr_space_sel_fd, &buf)?;
}
// Reuse file table
{
let cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?);
let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?);
let _ = syscall::write(
*new_filetable_sel_fd,
&usize::to_ne_bytes(*cur_filetable_fd),
)?;
}
// Reuse sigactions (on Linux, CLONE_THREAD requires CLONE_SIGHAND which implies the sigactions
// table is reused).
{
let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?);
let new_sigaction_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-sigactions")?);
let _ = syscall::write(
*new_sigaction_sel_fd,
&usize::to_ne_bytes(*cur_sigaction_fd),
)?;
}
copy_env_regs(*cur_pid_fd, *new_pid_fd)?;
// Unblock context.
syscall::kill(new_pid, SIGCONT)?;
let _ = syscall::waitpid(new_pid, &mut 0, syscall::WUNTRACED | syscall::WCONTINUED);
Ok(new_pid)
}
extern "C" {
fn __relibc_internal_rlct_clone_ret();
}
#[cfg(target_arch = "aarch64")]
core::arch::global_asm!(
"
.globl __relibc_internal_rlct_clone_ret
.type __relibc_internal_rlct_clone_ret, @function
.p2align 6
__relibc_internal_rlct_clone_ret:
# Load registers
ldr x8, [sp], #8
ldr x0, [sp], #8
ldr x1, [sp], #8
ldr x2, [sp], #8
ldr x3, [sp], #8
ldr x4, [sp], #8
ldr x5, [sp], #8
# Call entry point
blr x8
ret
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
"
);
#[cfg(target_arch = "x86")]
core::arch::global_asm!(
"
.globl __relibc_internal_rlct_clone_ret
.type __relibc_internal_rlct_clone_ret, @function
.p2align 6
__relibc_internal_rlct_clone_ret:
# Load registers
pop eax
sub esp, 8
mov DWORD PTR [esp], 0x00001F80
# TODO: ldmxcsr [esp]
mov WORD PTR [esp], 0x037F
fldcw [esp]
add esp, 8
# Call entry point
call eax
ret
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
"
);
#[cfg(target_arch = "x86_64")]
core::arch::global_asm!(
"
.globl __relibc_internal_rlct_clone_ret
.type __relibc_internal_rlct_clone_ret, @function
.p2align 6
__relibc_internal_rlct_clone_ret:
# Load registers
pop rax
pop rdi
pop rsi
pop rdx
pop rcx
pop r8
pop r9
sub rsp, 8
mov DWORD PTR [rsp], 0x00001F80
ldmxcsr [rsp]
mov WORD PTR [rsp], 0x037F
fldcw [rsp]
add rsp, 8
# Call entry point
call rax
ret
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
"
);