1 use core::{arch::global_asm, mem::size_of}; 2 3 use alloc::{boxed::Box, vec::Vec}; 4 5 use syscall::{ 6 data::Map, 7 error::{Error, Result, EINVAL, ENAMETOOLONG}, 8 flag::{MapFlags, O_CLOEXEC}, 9 SIGCONT, 10 }; 11 12 use super::extra::{create_set_addr_space_buf, FdGuard}; 13 14 pub use redox_exec::*; 15 16 /// Spawns a new context sharing the same address space as the current one (i.e. a new thread). 17 pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> { 18 let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); 19 let (new_pid_fd, new_pid) = new_context()?; 20 21 // Allocate a new signal stack. 22 { 23 let sigstack_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sigstack")?); 24 25 const SIGSTACK_SIZE: usize = 1024 * 256; 26 27 // TODO: Put sigstack at high addresses? 28 let target_sigstack = syscall::fmap( 29 !0, 30 &Map { 31 address: 0, 32 flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, 33 offset: 0, 34 size: SIGSTACK_SIZE, 35 }, 36 )? + SIGSTACK_SIZE; 37 38 let _ = syscall::write(*sigstack_fd, &usize::to_ne_bytes(target_sigstack))?; 39 } 40 41 copy_str(*cur_pid_fd, *new_pid_fd, "name")?; 42 43 // Reuse existing address space 44 { 45 let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?); 46 let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?); 47 48 let buf = create_set_addr_space_buf( 49 *cur_addr_space_fd, 50 __relibc_internal_pte_clone_ret as usize, 51 stack as usize, 52 ); 53 let _ = syscall::write(*new_addr_space_sel_fd, &buf)?; 54 } 55 56 // Reuse file table 57 { 58 let cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?); 59 let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?); 60 61 let _ = syscall::write( 62 *new_filetable_sel_fd, 63 &usize::to_ne_bytes(*cur_filetable_fd), 64 )?; 65 } 66 67 // Reuse sigactions (on Linux, CLONE_THREAD requires CLONE_SIGHAND which implies the sigactions 68 // table is reused). 69 { 70 let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?); 71 let new_sigaction_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-sigactions")?); 72 73 let _ = syscall::write( 74 *new_sigaction_sel_fd, 75 &usize::to_ne_bytes(*cur_sigaction_fd), 76 )?; 77 } 78 79 copy_env_regs(*cur_pid_fd, *new_pid_fd)?; 80 81 // Unblock context. 82 syscall::kill(new_pid, SIGCONT)?; 83 let _ = syscall::waitpid(new_pid, &mut 0, syscall::WUNTRACED | syscall::WCONTINUED); 84 85 Ok(new_pid) 86 } 87 88 extern "C" { 89 fn __relibc_internal_pte_clone_ret(); 90 } 91 92 #[cfg(target_arch = "aarch64")] 93 core::arch::global_asm!( 94 " 95 .globl __relibc_internal_pte_clone_ret 96 .type __relibc_internal_pte_clone_ret, @function 97 .p2align 6 98 __relibc_internal_pte_clone_ret: 99 # Load registers 100 ldr x8, [sp], #8 101 ldr x0, [sp], #8 102 ldr x1, [sp], #8 103 ldr x2, [sp], #8 104 ldr x3, [sp], #8 105 ldr x4, [sp], #8 106 ldr x5, [sp], #8 107 108 # Call entry point 109 blr x8 110 111 ret 112 .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret 113 " 114 ); 115 116 #[cfg(target_arch = "x86")] 117 core::arch::global_asm!( 118 " 119 .globl __relibc_internal_pte_clone_ret 120 .type __relibc_internal_pte_clone_ret, @function 121 .p2align 6 122 __relibc_internal_pte_clone_ret: 123 # Load registers 124 pop eax 125 126 sub esp, 8 127 128 mov DWORD PTR [esp], 0x00001F80 129 # TODO: ldmxcsr [esp] 130 mov WORD PTR [esp], 0x037F 131 fldcw [esp] 132 133 add esp, 8 134 135 # Call entry point 136 call eax 137 138 ret 139 .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret 140 " 141 ); 142 143 #[cfg(target_arch = "x86_64")] 144 core::arch::global_asm!( 145 " 146 .globl __relibc_internal_pte_clone_ret 147 .type __relibc_internal_pte_clone_ret, @function 148 .p2align 6 149 __relibc_internal_pte_clone_ret: 150 # Load registers 151 pop rax 152 pop rdi 153 pop rsi 154 pop rdx 155 pop rcx 156 pop r8 157 pop r9 158 159 sub rsp, 8 160 161 mov DWORD PTR [rsp], 0x00001F80 162 ldmxcsr [rsp] 163 mov WORD PTR [rsp], 0x037F 164 fldcw [rsp] 165 166 add rsp, 8 167 168 # Call entry point 169 call rax 170 171 ret 172 .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret 173 " 174 ); 175