From a80069326660091b3c2a06a7b5b63139a0b7ffa6 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 19 Jun 2024 13:01:49 +0200 Subject: [PATCH 01/67] Refactor: move redox-exec into redox-rt::proc. --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 4 ++-- .../redox/redox-exec => redox-rt}/Cargo.toml | 3 ++- .../redox-exec => redox-rt}/src/arch/aarch64.rs | 0 .../redox-exec => redox-rt}/src/arch/mod.rs | 0 .../redox-exec => redox-rt}/src/arch/x86.rs | 0 .../redox-exec => redox-rt}/src/arch/x86_64.rs | 2 +- redox-rt/src/lib.rs | 12 ++++++++++++ .../src/lib.rs => redox-rt/src/proc.rs | 17 ++--------------- src/platform/mod.rs | 2 +- src/platform/redox/clone.rs | 4 ++-- src/platform/redox/exec.rs | 8 ++++---- src/platform/redox/extra.rs | 2 +- src/platform/redox/mod.rs | 2 +- 14 files changed, 36 insertions(+), 36 deletions(-) rename {src/platform/redox/redox-exec => redox-rt}/Cargo.toml (83%) rename {src/platform/redox/redox-exec => redox-rt}/src/arch/aarch64.rs (100%) rename {src/platform/redox/redox-exec => redox-rt}/src/arch/mod.rs (100%) rename {src/platform/redox/redox-exec => redox-rt}/src/arch/x86.rs (100%) rename {src/platform/redox/redox-exec => redox-rt}/src/arch/x86_64.rs (98%) create mode 100644 redox-rt/src/lib.rs rename src/platform/redox/redox-exec/src/lib.rs => redox-rt/src/proc.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 2dbd6be7ed..07f1b0718b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,7 +361,13 @@ dependencies = [ ] [[package]] -name = "redox-exec" +name = "redox-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" + +[[package]] +name = "redox-rt" version = "0.1.0" dependencies = [ "goblin", @@ -369,12 +375,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "redox-path" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" - [[package]] name = "redox_event" version = "0.4.0" @@ -415,8 +415,8 @@ dependencies = [ "rand", "rand_jitter", "rand_xorshift", - "redox-exec", "redox-path", + "redox-rt", "redox_event", "redox_syscall", "sc", diff --git a/Cargo.toml b/Cargo.toml index 49e6a5bd58..6eb6c4a990 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = [ "src/crt0", "src/crti", "src/crtn", - "src/platform/redox/redox-exec", + "redox-rt", "ld_so", ] exclude = ["tests", "dlmalloc-rs"] @@ -59,7 +59,7 @@ sc = "0.2.3" [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.5.1" -redox-exec = { path = "src/platform/redox/redox-exec" } +redox-rt = { path = "redox-rt" } redox-path = "0.2" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = ["redox_syscall"] } diff --git a/src/platform/redox/redox-exec/Cargo.toml b/redox-rt/Cargo.toml similarity index 83% rename from src/platform/redox/redox-exec/Cargo.toml rename to redox-rt/Cargo.toml index 18212a3457..56cecb9b3d 100644 --- a/src/platform/redox/redox-exec/Cargo.toml +++ b/redox-rt/Cargo.toml @@ -1,9 +1,10 @@ [package] -name = "redox-exec" +name = "redox-rt" authors = ["4lDO2 <4lDO2@protonmail.com>"] version = "0.1.0" edition = "2021" license = "MIT" +description = "Libc-independent runtime for Redox" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/platform/redox/redox-exec/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs similarity index 100% rename from src/platform/redox/redox-exec/src/arch/aarch64.rs rename to redox-rt/src/arch/aarch64.rs diff --git a/src/platform/redox/redox-exec/src/arch/mod.rs b/redox-rt/src/arch/mod.rs similarity index 100% rename from src/platform/redox/redox-exec/src/arch/mod.rs rename to redox-rt/src/arch/mod.rs diff --git a/src/platform/redox/redox-exec/src/arch/x86.rs b/redox-rt/src/arch/x86.rs similarity index 100% rename from src/platform/redox/redox-exec/src/arch/x86.rs rename to redox-rt/src/arch/x86.rs diff --git a/src/platform/redox/redox-exec/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs similarity index 98% rename from src/platform/redox/redox-exec/src/arch/x86_64.rs rename to redox-rt/src/arch/x86_64.rs index 17aef45681..00bb7253b6 100644 --- a/src/platform/redox/redox-exec/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,6 +1,6 @@ use syscall::error::*; -use crate::{fork_inner, FdGuard}; +use crate::proc::{fork_inner, FdGuard}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs new file mode 100644 index 0000000000..2bf6f31e70 --- /dev/null +++ b/redox-rt/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] +#![feature(array_chunks, int_roundings, let_chains, slice_ptr_get)] +#![forbid(unreachable_patterns)] + +extern crate alloc; + +pub mod arch; +pub mod proc; + +// TODO: Replace auxvs with a non-stack-based interface, but keep getauxval for compatibility +#[path = "../../src/platform/auxv_defs.rs"] +pub mod auxv_defs; diff --git a/src/platform/redox/redox-exec/src/lib.rs b/redox-rt/src/proc.rs similarity index 99% rename from src/platform/redox/redox-exec/src/lib.rs rename to redox-rt/src/proc.rs index 17f4a64588..c6a820740c 100644 --- a/src/platform/redox/redox-exec/src/lib.rs +++ b/redox-rt/src/proc.rs @@ -1,10 +1,5 @@ -#![no_std] -#![feature(array_chunks, int_roundings, let_chains, slice_ptr_get)] -#![forbid(unreachable_patterns)] - -extern crate alloc; - use core::mem::size_of; +use crate::{arch::*, auxv_defs::*}; use alloc::{boxed::Box, collections::BTreeMap, vec}; @@ -27,9 +22,6 @@ use syscall::{ PAGE_SIZE, PROT_EXEC, PROT_READ, PROT_WRITE, }; -pub use self::arch::*; -mod arch; - pub enum FexecResult { Normal { addrspace_handle: FdGuard, @@ -713,11 +705,6 @@ pub fn create_set_addr_space_buf( buf } -#[path = "../../../auxv_defs.rs"] -pub mod auxv_defs; - -use auxv_defs::*; - /// Spawns a new context which will not share the same address space as the current one. File /// descriptors from other schemes are reobtained with `dup`, and grants referencing such file /// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW. @@ -732,7 +719,7 @@ pub fn fork_impl() -> Result { Ok(pid) } -fn fork_inner(initial_rsp: *mut usize) -> Result { +pub fn fork_inner(initial_rsp: *mut usize) -> Result { let (cur_filetable_fd, new_pid_fd, new_pid); { diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 9a5fbaa01e..f523842108 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -33,7 +33,7 @@ pub mod rlb; pub mod auxv_defs; #[cfg(target_os = "redox")] -pub use redox_exec::auxv_defs; +pub use redox_rt::auxv_defs; use self::types::*; pub mod types; diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index 336c0937cf..408e117e8c 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -10,11 +10,11 @@ use syscall::{ use crate::sync::rwlock::Rwlock; use super::{ - extra::{create_set_addr_space_buf, FdGuard}, + extra::FdGuard, signal::sighandler_function, }; -pub use redox_exec::*; +pub use redox_rt::proc::*; static CLONE_LOCK: Rwlock = Rwlock::new(crate::pthread::Pshared::Private); diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 4323242cad..56f3093a40 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -9,7 +9,7 @@ use crate::{ }, }; -use redox_exec::{ExtraInfo, FdGuard, FexecResult}; +use redox_rt::proc::{ExtraInfo, FdGuard, FexecResult, InterpOverride}; use syscall::{data::Stat, error::*, flag::*}; fn fexec_impl( @@ -20,11 +20,11 @@ fn fexec_impl( envs: &[&[u8]], total_args_envs_size: usize, extrainfo: &ExtraInfo, - interp_override: Option, + interp_override: Option, ) -> Result { let memory = FdGuard::new(syscall::open("memory:", 0)?); - let addrspace_selection_fd = match redox_exec::fexec_impl( + let addrspace_selection_fd = match redox_rt::proc::fexec_impl( exec_file, open_via_dup, &memory, @@ -88,7 +88,7 @@ pub enum Executable<'a> { pub fn execve( exec: Executable<'_>, arg_env: ArgEnv, - interp_override: Option, + interp_override: Option, ) -> Result { // NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we // have even read it! diff --git a/src/platform/redox/extra.rs b/src/platform/redox/extra.rs index 5dd09c274c..3c96933cdd 100644 --- a/src/platform/redox/extra.rs +++ b/src/platform/redox/extra.rs @@ -3,7 +3,7 @@ use core::{ptr, slice}; use crate::platform::{sys::e, types::*}; use syscall::{error::*, F_SETFD, F_SETFL}; -pub use redox_exec::*; +pub use redox_rt::proc::FdGuard; #[no_mangle] pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t { diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 079031c28b..dae77e6d43 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -27,7 +27,7 @@ use crate::{ pthread::{self, Errno, ResultExt}, }; -pub use redox_exec::FdGuard; +pub use redox_rt::proc::FdGuard; use super::{types::*, Pal, Read, ERRNO}; From 4eb20628f355dd9dab54efc012bf76818071d972 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 19 Jun 2024 13:18:08 +0200 Subject: [PATCH 02/67] Move some of signal config to redox-rt. --- redox-rt/src/arch/aarch64.rs | 28 +++---- redox-rt/src/arch/x86.rs | 34 ++++----- redox-rt/src/arch/x86_64.rs | 61 ++++++++++----- redox-rt/src/lib.rs | 23 +++++- redox-rt/src/proc.rs | 2 +- redox-rt/src/signal.rs | 73 ++++++++++++++++++ src/macros.rs | 19 ----- src/platform/redox/clone.rs | 5 +- src/platform/redox/signal.rs | 139 ----------------------------------- src/start.rs | 2 +- 10 files changed, 166 insertions(+), 220 deletions(-) create mode 100644 redox-rt/src/signal.rs diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index 058ba0280f..8550bea91a 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -44,12 +44,7 @@ unsafe extern "C" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pi let _ = syscall::close(new_pid_fd); } -core::arch::global_asm!( - " - .p2align 6 - .globl __relibc_internal_fork_wrapper - .type __relibc_internal_fork_wrapper, @function -__relibc_internal_fork_wrapper: +asmfunction!(__relibc_internal_fork_wrapper: [" stp x29, x30, [sp, #-16]! stp x27, x28, [sp, #-16]! stp x25, x26, [sp, #-16]! @@ -64,13 +59,9 @@ __relibc_internal_fork_wrapper: mov x0, sp bl __relibc_internal_fork_impl b 2f +"]); - .size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper - - .p2align 6 - .globl __relibc_internal_fork_ret - .type __relibc_internal_fork_ret, @function -__relibc_internal_fork_ret: +asmfunction!(__relibc_internal_fork_hook: [" ldp x0, x1, [sp] bl __relibc_internal_fork_hook @@ -89,11 +80,12 @@ __relibc_internal_fork_ret: ldp x29, x30, [sp], #16 ret +"]); - .size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret" -); +asmfunction!(__relibc_internal_sigentry: [" + mov x0, sp + bl {inner} -extern "C" { - pub(crate) fn __relibc_internal_fork_wrapper() -> usize; - pub(crate) fn __relibc_internal_fork_ret(); -} + mov x8, {SYS_SIGRETURN} + svc 0 +"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); diff --git a/redox-rt/src/arch/x86.rs b/redox-rt/src/arch/x86.rs index c6addedb38..56797839e9 100644 --- a/redox-rt/src/arch/x86.rs +++ b/redox-rt/src/arch/x86.rs @@ -45,13 +45,7 @@ unsafe extern "cdecl" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, ne let _ = syscall::close(new_pid_fd); } -//TODO: x86 -core::arch::global_asm!( - " - .p2align 6 - .globl __relibc_internal_fork_wrapper - .type __relibc_internal_fork_wrapper, @function -__relibc_internal_fork_wrapper: +asmfunction!(__relibc_internal_fork_wrapper: [" push ebp mov ebp, esp @@ -70,13 +64,9 @@ __relibc_internal_fork_wrapper: call __relibc_internal_fork_impl pop esp jmp 2f +"] <= []); - .size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper - - .p2align 6 - .globl __relibc_internal_fork_ret - .type __relibc_internal_fork_ret, @function -__relibc_internal_fork_ret: +asmfunction!(__relibc_internal_fork_ret: [" // Arguments already on the stack call __relibc_internal_fork_hook @@ -97,11 +87,17 @@ __relibc_internal_fork_ret: pop ebp ret +"] <= []); +asmfunction!(__relibc_internal_sigentry: [" + sub esp, 512 + fxsave [esp] - .size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret" -); + mov ecx, esp + call {inner} -extern "cdecl" { - pub(crate) fn __relibc_internal_fork_wrapper() -> usize; - pub(crate) fn __relibc_internal_fork_ret(); -} + add esp, 512 + fxrstor [esp] + + mov eax, {SYS_SIGRETURN} + int 0x80 +"] <= [inner = sym inner_fastcall, SYS_SIGRETURN = const SYS_SIGRETURN]); diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 00bb7253b6..542b751d26 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,6 +1,8 @@ +use syscall::number::SYS_SIGRETURN; use syscall::error::*; use crate::proc::{fork_inner, FdGuard}; +use crate::signal::inner_c; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; @@ -45,12 +47,7 @@ unsafe extern "sysv64" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, n let _ = syscall::close(new_pid_fd); } -core::arch::global_asm!( - " - .p2align 6 - .globl __relibc_internal_fork_wrapper - .type __relibc_internal_fork_wrapper, @function -__relibc_internal_fork_wrapper: +asmfunction!(__relibc_internal_fork_wrapper -> usize: [" push rbp mov rbp, rsp @@ -70,12 +67,8 @@ __relibc_internal_fork_wrapper: call __relibc_internal_fork_impl jmp 2f - .size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper - - .p2align 6 - .globl __relibc_internal_fork_ret - .type __relibc_internal_fork_ret, @function -__relibc_internal_fork_ret: +"] <= []); +asmfunction!(__relibc_internal_fork_ret: [" mov rdi, [rsp] mov rsi, [rsp + 8] call __relibc_internal_fork_hook @@ -97,11 +90,43 @@ __relibc_internal_fork_ret: pop rbp ret +"] <= []); +// TODO: is the memset necessary? +asmfunction!(__relibc_internal_sigentry_fxsave: [" + sub rsp, 4096 - .size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret" -); + fxsave64 [rsp] -extern "sysv64" { - pub(crate) fn __relibc_internal_fork_wrapper() -> usize; - pub(crate) fn __relibc_internal_fork_ret(); -} + mov rdi, rsp + call {inner} + + fxrstor64 [rsp] + add rsp, 4096 + + mov eax, {SYS_SIGRETURN} + syscall +"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); +asmfunction!(__relibc_internal_sigentry_xsave: [" + sub rsp, 4096 + + cld + mov rdi, rsp + xor eax, eax + mov ecx, 4096 + rep stosb + + mov eax, 0xffffffff + mov edx, eax + xsave [rsp] + + mov rdi, rsp + call {inner} + + mov eax, 0xffffffff + mov edx, eax + xrstor [rsp] + add rsp, 4096 + + mov eax, {SYS_SIGRETURN} + syscall +"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 2bf6f31e70..421695e13f 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -1,12 +1,33 @@ #![no_std] -#![feature(array_chunks, int_roundings, let_chains, slice_ptr_get)] +#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get)] #![forbid(unreachable_patterns)] extern crate alloc; +#[macro_export] +macro_rules! asmfunction( + ($name:ident $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => { + ::core::arch::global_asm!(concat!(" + .p2align 4 + .section .text.", stringify!($name), ", \"ax\", @progbits + .globl ", stringify!($name), " + .type ", stringify!($name), ", @function + ", stringify!($name), ": + ", $($asmstmt, "\n",)* " + .size ", stringify!($name), ", . - ", stringify!($name), " + "), $($decl = $(sym $symname)?$(const $constval)?),*); + + extern "C" { + pub fn $name() $(-> $ret)?; + } + } +); + pub mod arch; pub mod proc; // TODO: Replace auxvs with a non-stack-based interface, but keep getauxval for compatibility #[path = "../../src/platform/auxv_defs.rs"] pub mod auxv_defs; + +pub mod signal; diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index c6a820740c..a01200fc2b 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -795,7 +795,7 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { continue; } - let mut buf; + let buf; // TODO: write! using some #![no_std] Cursor type (tracking the length)? #[cfg(target_pointer_width = "64")] diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs new file mode 100644 index 0000000000..19932ec8c2 --- /dev/null +++ b/redox-rt/src/signal.rs @@ -0,0 +1,73 @@ +use core::ffi::c_int; + +use crate::arch::*; + +#[cfg(target_arch = "x86_64")] +static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); + +pub fn sighandler_function() -> usize { + #[cfg(target_arch = "x86_64")] + // Check OSXSAVE bit + // TODO: HWCAP? + if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { + __relibc_internal_sigentry_xsave as usize + } else { + __relibc_internal_sigentry_fxsave as usize + } + + #[cfg(any(target_arch = "x86", target_arch = "aarch64"))] + { + __relibc_internal_sigentry as usize + } +} + +pub fn setup_sighandler() { + // TODO + let altstack_base = 0_usize; + let altstack_len = 0_usize; + + #[cfg(target_arch = "x86_64")] + { + let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; + CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); + } + + let data = syscall::SetSighandlerData { + entry: sighandler_function(), + altstack_base, + altstack_len, + }; + + let fd = syscall::open( + "thisproc:current/sighandler", + syscall::O_WRONLY | syscall::O_CLOEXEC, + ) + .expect("failed to open thisproc:current/sighandler"); + syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); + let _ = syscall::close(fd); +} + +#[repr(C)] +pub struct SigStack { + #[cfg(target_arch = "x86_64")] + fx: [u8; 4096], + + #[cfg(target_arch = "x86")] + fx: [u8; 512], + + kernel_pushed: syscall::SignalStack, +} + +#[inline(always)] +unsafe fn inner(stack: &mut SigStack) { + let handler: extern "C" fn(c_int) = core::mem::transmute(stack.kernel_pushed.sa_handler); + handler(stack.kernel_pushed.sig_num as c_int) +} +#[cfg(not(target_arch = "x86"))] +pub(crate) unsafe extern "C" fn inner_c(stack: usize) { + inner(&mut *(stack as *mut SigStack)) +} +#[cfg(target_arch = "x86")] +unsafe extern "fastcall" fn inner_fastcall(stack: usize) { + inner(&mut *(stack as *mut SigStack)) +} diff --git a/src/macros.rs b/src/macros.rs index 9e94e9e4f2..23f6809d11 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -352,22 +352,3 @@ macro_rules! strto_float_impl { } }}; } - -#[macro_export] -macro_rules! asmfunction( - ($name:ident : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => { - ::core::arch::global_asm!(concat!(" - .p2align 4 - .section .text.", stringify!($name), ", \"ax\", @progbits - .globl ", stringify!($name), " - .type ", stringify!($name), ", @function - ", stringify!($name), ": - ", $($asmstmt, "\n",)* " - .size ", stringify!($name), ", . - ", stringify!($name), " - "), $($decl = $(sym $symname)?$(const $constval)?),*); - - extern "C" { - pub fn $name(); - } - } -); diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index 408e117e8c..5ec6f7785a 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -9,10 +9,7 @@ use syscall::{ use crate::sync::rwlock::Rwlock; -use super::{ - extra::FdGuard, - signal::sighandler_function, -}; +use redox_rt::{proc::FdGuard, signal::sighandler_function}; pub use redox_rt::proc::*; diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 25254ff262..3fa3c81e3c 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -135,7 +135,6 @@ impl PalSignal for Sys { -1 } } - pub(crate) fn sigaction_impl( sig: i32, act: Option<&sigaction>, @@ -167,141 +166,3 @@ pub(crate) unsafe fn sigprocmask_impl( syscall::sigprocmask(how as usize, set.as_ref(), oset.as_mut())?; Ok(()) } -#[cfg(target_arch = "x86_64")] -static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); - -pub fn sighandler_function() -> usize { - #[cfg(target_arch = "x86_64")] - // Check OSXSAVE bit - // TODO: HWCAP? - if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { - __relibc_internal_sigentry_xsave as usize - } else { - __relibc_internal_sigentry_fxsave as usize - } - - #[cfg(any(target_arch = "x86", target_arch = "aarch64"))] - { - __relibc_internal_sigentry as usize - } -} - -pub fn setup_sighandler() { - use core::mem::size_of; - - // TODO - let altstack_base = 0_usize; - let altstack_len = 0_usize; - - #[cfg(target_arch = "x86_64")] - { - let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; - CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); - } - - let data = SetSighandlerData { - entry: sighandler_function(), - altstack_base, - altstack_len, - }; - - let fd = syscall::open( - "thisproc:current/sighandler", - syscall::O_WRONLY | syscall::O_CLOEXEC, - ) - .expect("failed to open thisproc:current/sighandler"); - syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); - let _ = syscall::close(fd); -} - -#[repr(C)] -pub struct SigStack { - #[cfg(target_arch = "x86_64")] - fx: [u8; 4096], - - #[cfg(target_arch = "x86")] - fx: [u8; 512], - - kernel_pushed: SignalStack, -} - -#[inline(always)] -unsafe fn inner(stack: &mut SigStack) { - let handler: extern "C" fn(c_int) = core::mem::transmute(stack.kernel_pushed.sa_handler); - handler(stack.kernel_pushed.sig_num as c_int) -} -#[cfg(not(target_arch = "x86"))] -unsafe extern "C" fn inner_c(stack: usize) { - inner(&mut *(stack as *mut SigStack)) -} -#[cfg(target_arch = "x86")] -unsafe extern "fastcall" fn inner_fastcall(stack: usize) { - inner(&mut *(stack as *mut SigStack)) -} - -// TODO: is the memset necessary? -#[cfg(target_arch = "x86_64")] -asmfunction!(__relibc_internal_sigentry_xsave: [" - sub rsp, 4096 - - cld - mov rdi, rsp - xor eax, eax - mov ecx, 4096 - rep stosb - - mov eax, 0xffffffff - mov edx, eax - xsave [rsp] - - mov rdi, rsp - call {inner} - - mov eax, 0xffffffff - mov edx, eax - xrstor [rsp] - add rsp, 4096 - - mov eax, {SYS_SIGRETURN} - syscall -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); - -#[cfg(target_arch = "x86_64")] -asmfunction!(__relibc_internal_sigentry_fxsave: [" - sub rsp, 4096 - - fxsave64 [rsp] - - mov rdi, rsp - call {inner} - - fxrstor64 [rsp] - add rsp, 4096 - - mov eax, {SYS_SIGRETURN} - syscall -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); - -#[cfg(target_arch = "x86")] -asmfunction!(__relibc_internal_sigentry: [" - sub esp, 512 - fxsave [esp] - - mov ecx, esp - call {inner} - - add esp, 512 - fxrstor [esp] - - mov eax, {SYS_SIGRETURN} - int 0x80 -"] <= [inner = sym inner_fastcall, SYS_SIGRETURN = const SYS_SIGRETURN]); - -#[cfg(target_arch = "aarch64")] -asmfunction!(__relibc_internal_sigentry: [" - mov x0, sp - bl {inner} - - mov x8, {SYS_SIGRETURN} - svc 0 -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); diff --git a/src/start.rs b/src/start.rs index 13528e99b0..dc0e3e26e5 100644 --- a/src/start.rs +++ b/src/start.rs @@ -183,7 +183,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); } #[cfg(target_os = "redox")] - platform::sys::signal::setup_sighandler(); + redox_rt::signal::setup_sighandler(); let auxvs = get_auxvs(sp.auxv().cast()); crate::platform::init(auxvs); From 0440df142a713a20938855f60c1a4c8a063096cc Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 19 Jun 2024 13:20:47 +0200 Subject: [PATCH 03/67] Patch redox-syscall to fork. --- Cargo.lock | 27 +++++++++++++-------------- Cargo.toml | 3 +++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07f1b0718b..e95e1c36bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,9 +27,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" [[package]] name = "cfg-if" @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "md-5" @@ -272,9 +272,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -388,8 +388,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=usignal#387f1c332681a3cabe04294bce801e9c8c433df5" dependencies = [ "bitflags", ] @@ -496,15 +495,15 @@ dependencies = [ [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 6eb6c4a990..f3c83b3afc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,3 +73,6 @@ panic = "abort" [profile.release] panic = "abort" + +[patch.crates-io] +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "usignal" } From 53ed7aae59b1162024654e5a9041c6a2f5123e1c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 19 Jun 2024 14:44:12 +0200 Subject: [PATCH 04/67] Move rlct_clone, sigprocmask, sigaction, to rt. --- redox-rt/src/arch/aarch64.rs | 12 +++ redox-rt/src/arch/x86.rs | 19 +++++ redox-rt/src/arch/x86_64.rs | 34 ++++++-- redox-rt/src/lib.rs | 3 +- redox-rt/src/proc.rs | 4 +- redox-rt/src/signal.rs | 65 +++++++++++--- redox-rt/src/thread.rs | 72 ++++++++++++++++ src/header/signal/mod.rs | 32 +++---- src/ld_so/tcb.rs | 5 ++ src/platform/mod.rs | 2 +- src/platform/pal/signal.rs | 8 +- src/platform/redox/clone.rs | 151 +-------------------------------- src/platform/redox/exec.rs | 2 +- src/platform/redox/libredox.rs | 6 +- src/platform/redox/path.rs | 31 ++----- src/platform/redox/signal.rs | 51 +++-------- src/pthread/mod.rs | 4 +- src/start.rs | 6 +- 18 files changed, 246 insertions(+), 261 deletions(-) create mode 100644 redox-rt/src/thread.rs diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index 8550bea91a..26d62a506e 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -89,3 +89,15 @@ asmfunction!(__relibc_internal_sigentry: [" mov x8, {SYS_SIGRETURN} svc 0 "] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); + +asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" + # Load registers + ldp x8, x0, [sp], #16 + ldp x1, x2, [sp], #16 + ldp x3, x4, [sp], #16 + + # Call entry point + blr x8 + + ret +"]); diff --git a/redox-rt/src/arch/x86.rs b/redox-rt/src/arch/x86.rs index 56797839e9..eb33fc441a 100644 --- a/redox-rt/src/arch/x86.rs +++ b/redox-rt/src/arch/x86.rs @@ -101,3 +101,22 @@ asmfunction!(__relibc_internal_sigentry: [" mov eax, {SYS_SIGRETURN} int 0x80 "] <= [inner = sym inner_fastcall, SYS_SIGRETURN = const SYS_SIGRETURN]); + +asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" + # 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 +"] <= []); diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 542b751d26..2d9fb84be4 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,4 +1,3 @@ -use syscall::number::SYS_SIGRETURN; use syscall::error::*; use crate::proc::{fork_inner, FdGuard}; @@ -103,9 +102,9 @@ asmfunction!(__relibc_internal_sigentry_fxsave: [" fxrstor64 [rsp] add rsp, 4096 - mov eax, {SYS_SIGRETURN} + //mov eax, {{SYS_SIGRETURN}} syscall -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); +"] <= [inner = sym inner_c]); asmfunction!(__relibc_internal_sigentry_xsave: [" sub rsp, 4096 @@ -127,6 +126,31 @@ asmfunction!(__relibc_internal_sigentry_xsave: [" xrstor [rsp] add rsp, 4096 - mov eax, {SYS_SIGRETURN} + //mov eax, {{SYS_SIGRETURN}} syscall -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); +"] <= [inner = sym inner_c]); + +asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" + # 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 +"] <= []); diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 421695e13f..7ec7ca9d3b 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get)] +#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell, thread_local)] #![forbid(unreachable_patterns)] extern crate alloc; @@ -31,3 +31,4 @@ pub mod proc; pub mod auxv_defs; pub mod signal; +pub mod thread; diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index a01200fc2b..fcf2a5c309 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -710,11 +710,11 @@ pub fn create_set_addr_space_buf( /// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW. pub fn fork_impl() -> Result { let mut old_mask = 0_u64; - syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut old_mask))?; + crate::signal::set_sigmask(None, Some(&mut old_mask))?; let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? }; if pid == 0 { - syscall::sigprocmask(syscall::SIG_SETMASK, Some(&old_mask), None)?; + crate::signal::set_sigmask(Some(old_mask), None)?; } Ok(pid) } diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 19932ec8c2..4247f81702 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,5 +1,8 @@ +use core::cell::Cell; use core::ffi::c_int; +use syscall::{Result, Sigcontrol}; + use crate::arch::*; #[cfg(target_arch = "x86_64")] @@ -21,11 +24,7 @@ pub fn sighandler_function() -> usize { } } -pub fn setup_sighandler() { - // TODO - let altstack_base = 0_usize; - let altstack_len = 0_usize; - +pub fn setup_sighandler(control: &Sigcontrol) { #[cfg(target_arch = "x86_64")] { let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; @@ -33,9 +32,9 @@ pub fn setup_sighandler() { } let data = syscall::SetSighandlerData { - entry: sighandler_function(), - altstack_base, - altstack_len, + user_handler: sighandler_function(), + excp_handler: 0, // TODO + word_addr: control as *const Sigcontrol as usize, }; let fd = syscall::open( @@ -55,13 +54,14 @@ pub struct SigStack { #[cfg(target_arch = "x86")] fx: [u8; 512], - kernel_pushed: syscall::SignalStack, + sa_handler: usize, + sig_num: usize, } #[inline(always)] unsafe fn inner(stack: &mut SigStack) { - let handler: extern "C" fn(c_int) = core::mem::transmute(stack.kernel_pushed.sa_handler); - handler(stack.kernel_pushed.sig_num as c_int) + let handler: extern "C" fn(c_int) = core::mem::transmute(stack.sa_handler); + handler(stack.sig_num as c_int) } #[cfg(not(target_arch = "x86"))] pub(crate) unsafe extern "C" fn inner_c(stack: usize) { @@ -71,3 +71,46 @@ pub(crate) unsafe extern "C" fn inner_c(stack: usize) { unsafe extern "fastcall" fn inner_fastcall(stack: usize) { inner(&mut *(stack as *mut SigStack)) } + +pub fn set_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { + todo!() +} +pub fn or_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { + todo!() +} +pub fn andn_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { + todo!() +} + +extern "C" { + pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; +} + +pub struct TmpDisableSignalsGuard { _inner: () } + +#[thread_local] +static TMP_DISABLE_SIGNALS_DEPTH: Cell = Cell::new(0); + +pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { + unsafe { + let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + ctl.write_volatile(ctl.read_volatile() | syscall::flag::INHIBIT_DELIVERY); + // TODO: fence? + TMP_DISABLE_SIGNALS_DEPTH.set(TMP_DISABLE_SIGNALS_DEPTH.get() + 1); + } + + TmpDisableSignalsGuard { _inner: () } +} +impl Drop for TmpDisableSignalsGuard { + fn drop(&mut self) { + unsafe { + let old = TMP_DISABLE_SIGNALS_DEPTH.get(); + TMP_DISABLE_SIGNALS_DEPTH.set(old - 1); + + if old == 1 { + let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + ctl.write_volatile(ctl.read_volatile() & !syscall::flag::INHIBIT_DELIVERY); + } + } + } +} diff --git a/redox-rt/src/thread.rs b/redox-rt/src/thread.rs new file mode 100644 index 0000000000..298858315f --- /dev/null +++ b/redox-rt/src/thread.rs @@ -0,0 +1,72 @@ +use syscall::SetSighandlerData; +use syscall::{Result, O_CLOEXEC}; + +use crate::arch::*; +use crate::proc::*; +use crate::signal::sighandler_function; + +/// 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 { + let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); + let (new_pid_fd, new_pid) = new_context()?; + + copy_str(*cur_pid_fd, *new_pid_fd, "name")?; + + // Inherit 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)?; + } + + // Inherit 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), + )?; + } + + // Inherit 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), + )?; + } + // Inherit sighandler, but not the sigaltstack. + { + let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); + let data = SetSighandlerData { + user_handler: sighandler_function(), + excp_handler: 0, + word_addr: 0, // TODO + }; + let _ = syscall::write(*new_sighandler_fd, &data)?; + } + + // Sigprocmask starts as "block all", and is initialized when the thread has actually returned + // from clone_ret. + + // TODO: Should some of these registers be inherited? + //copy_env_regs(*cur_pid_fd, *new_pid_fd)?; + + // Unblock context. + let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?); + let _ = syscall::write(*start_fd, &[0])?; + + Ok(new_pid) +} diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index 5e8d52063a..9c924c1d21 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -7,7 +7,7 @@ use cbitset::BitSet; use crate::{ header::{errno, time::timespec}, platform::{self, types::*, Pal, PalSignal, Sys}, - pthread, + pthread::{self, ResultExt}, }; pub use self::sys::*; @@ -107,13 +107,7 @@ pub unsafe extern "C" fn sigaction( act: *const sigaction, oact: *mut sigaction, ) -> c_int { - let act_opt = act.as_ref().map(|act| { - let mut act_clone = act.clone(); - act_clone.sa_flags |= SA_RESTORER as c_ulong; - act_clone.sa_restorer = Some(__restore_rt); - act_clone - }); - Sys::sigaction(sig, act_opt.as_ref(), oact.as_mut()) + Sys::sigaction(sig, act.as_ref(), oact.as_mut()).map(|()| 0).or_minus_one_errno() } #[no_mangle] @@ -270,14 +264,22 @@ pub unsafe extern "C" fn sigprocmask( set: *const sigset_t, oset: *mut sigset_t, ) -> c_int { - let set = set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK); + (|| { + let set = set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK); + let mut oset = oset.as_mut(); - Sys::sigprocmask( - how, - set.as_ref() - .map_or(core::ptr::null(), |r| r as *const sigset_t), - oset, - ) + Sys::sigprocmask( + how, + set.as_ref(), + oset.as_deref_mut(), // as_deref_mut for lifetime reasons + )?; + + if let Some(oset) = oset { + *oset &= !RLCT_SIGNAL_MASK; + } + + Ok(0) + })().or_minus_one_errno() } #[no_mangle] diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index fd3ac90bb2..2b012ea7fd 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -1,4 +1,5 @@ use alloc::vec::Vec; +use syscall::Sigcontrol; use core::{arch::asm, cell::UnsafeCell, mem, ptr, slice, sync::atomic::AtomicBool}; use goblin::error::{Error, Result}; @@ -53,6 +54,8 @@ pub struct Tcb { pub mspace: *const Mutex, /// Underlying pthread_t struct, pthread_self() returns &self.pthread pub pthread: Pthread, + #[cfg(target_os = "redox")] + pub sigcontrol: Sigcontrol, } impl Tcb { @@ -84,6 +87,8 @@ impl Tcb { stack_size: 0, os_tid: UnsafeCell::new(OsTid::default()), }, + #[cfg(target_os = "redox")] + sigcontrol: Default::default(), }, ); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index f523842108..9b598d68a0 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -306,7 +306,7 @@ pub fn init(auxvs: Box<[[usize; 2]]>) { if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGPROCMASK_HI) { inherited_sigprocmask |= (mask as u64) << 32; } - syscall::sigprocmask(syscall::SIG_SETMASK, Some(&inherited_sigprocmask), None).unwrap(); + redox_rt::signal::set_sigmask(Some(inherited_sigprocmask), None).unwrap(); } #[cfg(not(target_os = "redox"))] pub fn init(auxvs: Box<[[usize; 2]]>) {} diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index c085c678e8..eeb5031a76 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -1,9 +1,9 @@ use super::super::{types::*, Pal}; -use crate::header::{ +use crate::{header::{ signal::{sigaction, siginfo_t, sigset_t, stack_t}, sys_time::itimerval, time::timespec, -}; +}, pthread::Errno}; pub trait PalSignal: Pal { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int; @@ -16,13 +16,13 @@ pub trait PalSignal: Pal { unsafe fn setitimer(which: c_int, new: *const itimerval, old: *mut itimerval) -> c_int; - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int; + fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno>; unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int; unsafe fn sigpending(set: *mut sigset_t) -> c_int; - unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int; + fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno>; unsafe fn sigsuspend(set: *const sigset_t) -> c_int; diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index 5ec6f7785a..017696ce6b 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -32,153 +32,4 @@ pub fn wrlock() -> impl Drop { Guard } - -/// 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 { - let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); - let (new_pid_fd, new_pid) = new_context()?; - - copy_str(*cur_pid_fd, *new_pid_fd, "name")?; - - // Inherit 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)?; - } - - // Inherit 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), - )?; - } - - // Inherit 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), - )?; - } - // Inherit sighandler, but not the sigaltstack. - { - let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); - let data = SetSighandlerData { - entry: sighandler_function(), - altstack_base: 0, - altstack_len: 0, - }; - let _ = syscall::write(*new_sighandler_fd, &data)?; - } - - // Sigprocmask starts as "block all", and is initialized when the thread has actually returned - // from clone_ret. - - // TODO: Should some of these registers be inherited? - //copy_env_regs(*cur_pid_fd, *new_pid_fd)?; - - // Unblock context. - let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?); - let _ = syscall::write(*start_fd, &[0])?; - - 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 - ldp x8, x0, [sp], #16 - ldp x1, x2, [sp], #16 - ldp x3, x4, [sp], #16 - - # 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 -" -); +pub use redox_rt::thread::*; diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 56f3093a40..32aaf675a5 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -306,7 +306,7 @@ pub fn execve( unreachable!() } else { let mut sigprocmask = 0_u64; - syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut sigprocmask)).unwrap(); + redox_rt::signal::set_sigmask(None, Some(&mut sigprocmask)).unwrap(); let extrainfo = ExtraInfo { cwd: Some(&cwd), diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 15ea59a7ed..9ceed89a71 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -4,7 +4,7 @@ use syscall::{Error, Result, WaitFlags, EMFILE}; use crate::{ header::{ - errno::EINVAL, signal::sigaction, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec, + errno::EINVAL, signal::{sigaction, SIG_SETMASK}, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec, }, platform::types::*, }; @@ -249,7 +249,7 @@ pub unsafe extern "C" fn redox_sigaction_v1( new: *const sigaction, old: *mut sigaction, ) -> RawResult { - Error::mux(super::signal::sigaction_impl(signal as i32, new.as_ref(), old.as_mut()).map(|()| 0)) + todo!() } #[no_mangle] @@ -258,7 +258,7 @@ pub unsafe extern "C" fn redox_sigprocmask_v1( new: *const u64, old: *mut u64, ) -> RawResult { - Error::mux(super::signal::sigprocmask_impl(how as i32, new, old).map(|()| 0)) + todo!() } #[no_mangle] pub unsafe extern "C" fn redox_mmap_v1( diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs index bdcb4a4254..01c075748b 100644 --- a/src/platform/redox/path.rs +++ b/src/platform/redox/path.rs @@ -1,4 +1,5 @@ use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; +use redox_rt::signal::tmp_disable_signals; use syscall::{data::Stat, error::*, flag::*}; use super::{libcscheme, FdGuard}; @@ -19,7 +20,7 @@ const PATH_MAX: usize = 4096; // and after acquiring the locks. (TODO: ArcSwap? That will need to be ported to no_std first, // though). pub fn chdir(path: &str) -> Result<()> { - let _siglock = SignalMask::lock(); + let _siglock = tmp_disable_signals(); let mut cwd_guard = CWD.lock(); let canonicalized = @@ -40,13 +41,13 @@ pub fn chdir(path: &str) -> Result<()> { } pub fn clone_cwd() -> Option> { - let _siglock = SignalMask::lock(); + let _siglock = tmp_disable_signals(); CWD.lock().clone() } // TODO: MaybeUninit pub fn getcwd(buf: &mut [u8]) -> Option { - let _siglock = SignalMask::lock(); + let _siglock = tmp_disable_signals(); let cwd_guard = CWD.lock(); let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes(); @@ -61,9 +62,8 @@ pub fn getcwd(buf: &mut [u8]) -> Option { Some(cwd.len()) } -// TODO: Move cwd from kernel to libc. It is passed via auxiliary vectors. pub fn canonicalize(path: &str) -> Result { - let _siglock = SignalMask::lock(); + let _siglock = tmp_disable_signals(); let cwd = CWD.lock(); canonicalize_using_cwd(cwd.as_deref(), path).ok_or(Error::new(ENOENT)) } @@ -72,29 +72,10 @@ pub fn canonicalize(path: &str) -> Result { static CWD: Mutex>> = Mutex::new(None); pub fn setcwd_manual(cwd: Box) { - let _siglock = SignalMask::lock(); + let _siglock = tmp_disable_signals(); *CWD.lock() = Some(cwd); } -/// RAII guard able to magically fix signal unsafety, by disabling signals during a critical -/// section. -pub struct SignalMask { - oldset: u64, -} -impl SignalMask { - pub fn lock() -> Self { - let mut oldset = 0; - syscall::sigprocmask(syscall::SIG_SETMASK, Some(&!0), Some(&mut oldset)) - .expect("failed to run sigprocmask"); - Self { oldset } - } -} -impl Drop for SignalMask { - fn drop(&mut self) { - let _ = syscall::sigprocmask(syscall::SIG_SETMASK, Some(&self.oldset), None); - } -} - pub fn open(path: &str, flags: usize) -> Result { // TODO: SYMLOOP_MAX const MAX_LEVEL: usize = 64; diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 3fa3c81e3c..f8f82a8d88 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,5 +1,5 @@ use core::mem; -use syscall::{self, number::SYS_SIGRETURN, Result, SetSighandlerData, SignalStack}; +use syscall::{self, Result}; use super::{ super::{types::*, Pal, PalSignal}, @@ -8,11 +8,11 @@ use super::{ use crate::{ header::{ errno::{EINVAL, ENOSYS}, - signal::{sigaction, siginfo_t, sigset_t, stack_t}, + signal::{sigaction, siginfo_t, sigset_t, stack_t, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, sys_time::{itimerval, ITIMER_REAL}, time::timespec, }, - platform::ERRNO, + platform::ERRNO, pthread::Errno, }; impl PalSignal for Sys { @@ -104,8 +104,8 @@ impl PalSignal for Sys { 0 } - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int { - e(sigaction_impl(sig, act, oact).map(|()| 0)) as c_int + fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> { + todo!() } unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { @@ -117,8 +117,14 @@ impl PalSignal for Sys { -1 } - unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int { - e(sigprocmask_impl(how, set, oset).map(|()| 0)) as c_int + fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno> { + Ok(match how { + SIG_SETMASK => redox_rt::signal::set_sigmask(set.copied(), oset)?, + SIG_BLOCK => redox_rt::signal::or_sigmask(set.copied(), oset)?, + SIG_UNBLOCK => redox_rt::signal::andn_sigmask(set.copied(), oset)?, + + _ => return Err(Errno(EINVAL)), + }) } unsafe fn sigsuspend(set: *const sigset_t) -> c_int { @@ -135,34 +141,3 @@ impl PalSignal for Sys { -1 } } -pub(crate) fn sigaction_impl( - sig: i32, - act: Option<&sigaction>, - oact: Option<&mut sigaction>, -) -> Result<()> { - let new_opt = act.map(|act| { - let sa_handler = unsafe { mem::transmute(act.sa_handler) }; - syscall::SigAction { - sa_handler, - sa_mask: act.sa_mask as u64, - sa_flags: syscall::SigActionFlags::from_bits(act.sa_flags as usize) - .expect("sigaction: invalid bit pattern"), - } - }); - let mut old_opt = oact.as_ref().map(|_| syscall::SigAction::default()); - syscall::sigaction(sig as usize, new_opt.as_ref(), old_opt.as_mut())?; - if let (Some(old), Some(oact)) = (old_opt, oact) { - oact.sa_handler = unsafe { mem::transmute(old.sa_handler) }; - oact.sa_mask = old.sa_mask as sigset_t; - oact.sa_flags = old.sa_flags.bits() as c_ulong; - } - Ok(()) -} -pub(crate) unsafe fn sigprocmask_impl( - how: i32, - set: *const sigset_t, - oset: *mut sigset_t, -) -> Result<()> { - syscall::sigprocmask(how as usize, set.as_ref(), oset.as_mut())?; - Ok(()) -} diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 37402d4513..0290f26fbc 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -132,7 +132,7 @@ pub(crate) unsafe fn create( let mut procmask = 0_u64; #[cfg(target_os = "redox")] - syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut procmask)) + redox_rt::signal::set_sigmask(None, Some(&mut procmask)) .expect("failed to obtain sigprocmask for caller"); // Create a locked mutex, unlocked by the thread after it has started. @@ -242,7 +242,7 @@ unsafe extern "C" fn new_thread_shim( (&*mutex).manual_unlock(); #[cfg(target_os = "redox")] - syscall::sigprocmask(syscall::SIG_SETMASK, Some(&procmask), None) + redox_rt::signal::set_sigmask(Some(procmask), None) .expect("failed to set procmask in child thread"); let retval = entry_point(arg); diff --git a/src/start.rs b/src/start.rs index dc0e3e26e5..540ddb6d12 100644 --- a/src/start.rs +++ b/src/start.rs @@ -3,7 +3,7 @@ use core::{intrinsics, ptr}; use crate::{ header::{libgen, stdio, stdlib}, - ld_so::{self, linker::Linker}, + ld_so::{self, linker::Linker, tcb::Tcb}, platform::{self, get_auxvs, types::*, Pal, Sys}, sync::mutex::Mutex, ALLOCATOR, @@ -157,6 +157,8 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { //TODO: load root object tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); } + #[cfg(target_os = "redox")] + redox_rt::signal::setup_sighandler(&tcb.sigcontrol); } // Set up argc and argv @@ -182,8 +184,6 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { platform::OUR_ENVIRON = copy_string_array(envp, len); platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); } - #[cfg(target_os = "redox")] - redox_rt::signal::setup_sighandler(); let auxvs = get_auxvs(sp.auxv().cast()); crate::platform::init(auxvs); From e1d3bf475a0964da50f6f1e4cf5905d2bc39b520 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 19 Jun 2024 15:59:13 +0200 Subject: [PATCH 05/67] Increase SIGRTMIN to 35. --- src/header/signal/linux.rs | 3 ++- src/header/signal/redox.rs | 2 +- src/pthread/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/header/signal/linux.rs b/src/header/signal/linux.rs index de013cdc13..fb23a0e99b 100644 --- a/src/header/signal/linux.rs +++ b/src/header/signal/linux.rs @@ -58,7 +58,8 @@ pub const SIGSYS: usize = 31; pub const SIGUNUSED: usize = SIGSYS; pub const NSIG: usize = 32; -pub const SIGRTMIN: usize = 34; +pub const SIGRTMIN: usize = 35; // TODO: decrease to 34 +pub const SIGRTMAX: usize = 64; pub const SA_NOCLDSTOP: usize = 1; pub const SA_NOCLDWAIT: usize = 2; diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs index b4e8496add..f146dcda53 100644 --- a/src/header/signal/redox.rs +++ b/src/header/signal/redox.rs @@ -66,7 +66,7 @@ pub const SIGPWR: usize = 30; pub const SIGSYS: usize = 31; pub const NSIG: usize = 32; -pub const SIGRTMIN: usize = 34; +pub const SIGRTMIN: usize = 35; pub const SIGRTMAX: usize = 64; pub const SA_NOCLDSTOP: usize = 0x00000001; diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 0290f26fbc..2b4ad725f5 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -316,8 +316,8 @@ unsafe fn dealloc_thread(thread: &Pthread) { OS_TID_TO_PTHREAD.lock().remove(&thread.os_tid.get().read()); //drop(Box::from_raw(thread as *const Pthread as *mut Pthread)); } -pub const SIGRT_RLCT_CANCEL: usize = 32; -pub const SIGRT_RLCT_TIMER: usize = 33; +pub const SIGRT_RLCT_CANCEL: usize = 33; +pub const SIGRT_RLCT_TIMER: usize = 34; unsafe extern "C" fn cancel_sighandler(_: c_int) { cancel_current_thread(); From 98ac085c5d735ab85556a7c15205cee08fedce62 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 13:06:54 +0200 Subject: [PATCH 06/67] Add sigprocmask stub to rt. --- Cargo.lock | 1 + redox-rt/Cargo.toml | 3 +- redox-rt/src/lib.rs | 1 + redox-rt/src/proc.rs | 3 +- redox-rt/src/signal.rs | 154 ++++++++++++++++++++++++++++++++++------- redox-rt/src/sync.rs | 48 +++++++++++++ 6 files changed, 181 insertions(+), 29 deletions(-) create mode 100644 redox-rt/src/sync.rs diff --git a/Cargo.lock b/Cargo.lock index e95e1c36bd..520d4c544f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,6 +370,7 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" name = "redox-rt" version = "0.1.0" dependencies = [ + "bitflags", "goblin", "plain", "redox_syscall", diff --git a/redox-rt/Cargo.toml b/redox-rt/Cargo.toml index 56cecb9b3d..210e5b8884 100644 --- a/redox-rt/Cargo.toml +++ b/redox-rt/Cargo.toml @@ -9,6 +9,7 @@ description = "Libc-independent runtime for Redox" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -redox_syscall = "0.5.1" +bitflags = "2" goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] } plain = "0.2" +redox_syscall = "0.5.1" diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 7ec7ca9d3b..257ea43129 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -31,4 +31,5 @@ pub mod proc; pub mod auxv_defs; pub mod signal; +pub mod sync; pub mod thread; diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index fcf2a5c309..608aaa683b 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -709,8 +709,7 @@ pub fn create_set_addr_space_buf( /// descriptors from other schemes are reobtained with `dup`, and grants referencing such file /// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW. pub fn fork_impl() -> Result { - let mut old_mask = 0_u64; - crate::signal::set_sigmask(None, Some(&mut old_mask))?; + let mut old_mask = crate::signal::get_sigmask()?; let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? }; if pid == 0 { diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 4247f81702..0d628506f7 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,9 +1,11 @@ use core::cell::Cell; use core::ffi::c_int; +use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Result, Sigcontrol}; +use syscall::{Result, Sigcontrol, SIGCHLD, SIGCONT, SIGURG, SIGWINCH}; use crate::arch::*; +use crate::sync::Mutex; #[cfg(target_arch = "x86_64")] static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); @@ -24,28 +26,6 @@ pub fn sighandler_function() -> usize { } } -pub fn setup_sighandler(control: &Sigcontrol) { - #[cfg(target_arch = "x86_64")] - { - let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; - CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); - } - - let data = syscall::SetSighandlerData { - user_handler: sighandler_function(), - excp_handler: 0, // TODO - word_addr: control as *const Sigcontrol as usize, - }; - - let fd = syscall::open( - "thisproc:current/sighandler", - syscall::O_WRONLY | syscall::O_CLOEXEC, - ) - .expect("failed to open thisproc:current/sighandler"); - syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); - let _ = syscall::close(fd); -} - #[repr(C)] pub struct SigStack { #[cfg(target_arch = "x86_64")] @@ -72,19 +52,61 @@ unsafe extern "fastcall" fn inner_fastcall(stack: usize) { inner(&mut *(stack as *mut SigStack)) } +pub fn get_sigmask() -> Result { + let mut mask = 0; + modify_sigmask(Some(&mut mask), Option:: u32>::None)?; + Ok(mask) +} pub fn set_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - todo!() + modify_sigmask(old, new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32)) } pub fn or_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - todo!() + // Parsing nightmare... + modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32)) } pub fn andn_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - todo!() + modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask & !if upper { newmask >> 32 } else { newmask } as u32)) +} +fn modify_sigmask(old: Option<&mut u64>, op: Option u32>) -> Result<()> { + let _guard = tmp_disable_signals(); + let ctl = current_sigctl(); + + let mut words = ctl.word.each_ref().map(|w| w.load(Ordering::Relaxed)); + + if let Some(old) = old { + *old = combine_mask(words); + } + let Some(mut op) = op else { + return Ok(()); + }; + + let mut can_raise = 0; + let mut cant_raise = 0; + + for i in 0..2 { + while let Err(changed) = ctl.word[i].compare_exchange(words[i], ((words[i] >> 32) << 32) | u64::from(op(words[i] as u32, i == 1)), Ordering::Relaxed, Ordering::Relaxed) { + // If kernel observed a signal being unblocked and pending simultaneously, it will have + // set a flag causing it to check for the INHIBIT_SIGNALS flag every time the context + // is switched to. To avoid race conditions, we should NOT auto-raise those signals in + // userspace as a result of unblocking it. The kernel will instead take care of that later. + can_raise |= (changed & (changed >> 32)) << (32 * i); + cant_raise |= (changed & !(changed >> 32)) << (32 * i); + + words[i] = changed; + } + } + + // TODO: Prioritize cant_raise realtime signals? + + Ok(()) } extern "C" { pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; } +fn current_sigctl() -> &'static Sigcontrol { + unsafe { __relibc_internal_get_sigcontrol_addr() } +} pub struct TmpDisableSignalsGuard { _inner: () } @@ -114,3 +136,83 @@ impl Drop for TmpDisableSignalsGuard { } } } + +#[derive(Clone, Copy)] +struct SignalAction { + handler: SignalHandler, + flags: SigactionFlags, + mask: u64, +} +bitflags::bitflags! { + #[derive(Clone, Copy)] + struct SigactionFlags: u32 { + const SA_RESETHAND = 1; + } +} +fn default_term_handler(sig: c_int) { + syscall::exit((sig as usize) << 8); +} +fn default_core_handler(sig: c_int) { + syscall::exit((sig as usize) << 8); +} +fn default_ign_handler(_: c_int) { +} +fn stop_handler_sentinel(_: c_int) { +} + +#[derive(Clone, Copy)] +union SignalHandler { + sa_handler: Option, + sa_sigaction: Option, +} + +struct TheDefault { + actions: [SignalAction; 64], + ignmask: u64, +} + +static SIGACTIONS: Mutex<[SignalAction; 64]> = Mutex::new([SignalAction { + handler: SignalHandler { sa_handler: None }, + flags: SigactionFlags::empty(), + mask: 0, +}; 64]); +static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH) | sig_bit(SIGCONT)); + +fn expand_mask(mask: u64) -> [u64; 2] { + [mask & 0xffff_ffff, mask >> 32] +} +fn combine_mask([lo, hi]: [u64; 2]) -> u64 { + lo | ((hi & 0xffff_ffff) << 32) +} + +const fn sig_bit(sig: usize) -> u64 { + //assert_ne!(sig, 32); + //assert_ne!(sig, 0); + 1 << (sig - 1) +} + +pub fn setup_sighandler(control: &Sigcontrol) { + { + let mut sigactions = SIGACTIONS.lock(); + } + + #[cfg(target_arch = "x86_64")] + { + let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; + CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); + } + + let data = syscall::SetSighandlerData { + user_handler: sighandler_function(), + excp_handler: 0, // TODO + word_addr: control as *const Sigcontrol as usize, + }; + + let fd = syscall::open( + "thisproc:current/sighandler", + syscall::O_WRONLY | syscall::O_CLOEXEC, + ) + .expect("failed to open thisproc:current/sighandler"); + syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); + let _ = syscall::close(fd); +} diff --git a/redox-rt/src/sync.rs b/redox-rt/src/sync.rs new file mode 100644 index 0000000000..7130778429 --- /dev/null +++ b/redox-rt/src/sync.rs @@ -0,0 +1,48 @@ +// TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this. + +use core::cell::UnsafeCell; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::AtomicU32; + +pub struct Mutex { + pub lockword: AtomicU32, + pub inner: UnsafeCell, +} + +const UNLOCKED: u32 = 0; +const LOCKED: u32 = 1; +const WAITING: u32 = 2; + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +impl Mutex { + pub const fn new(t: T) -> Self { + Self { + lockword: AtomicU32::new(0), + inner: UnsafeCell::new(t), + } + } + pub fn lock(&self) -> MutexGuard<'_, T> { + MutexGuard { lock: self } + } +} +pub struct MutexGuard<'l, T> { + lock: &'l Mutex, +} +impl Deref for MutexGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.inner.get() } + } +} +impl DerefMut for MutexGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.inner.get() } + } +} +impl Drop for MutexGuard<'_, T> { + fn drop(&mut self) { + } +} From 7d562920c2fbf1341ed1ac0459ff69474c56d726 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 14:21:11 +0200 Subject: [PATCH 07/67] Add sigaction boilerplate. --- redox-rt/src/signal.rs | 84 ++++++++++++++++++++++++++++-------- src/header/signal/redox.rs | 16 +++---- src/platform/redox/signal.rs | 58 +++++++++++++++++++++++-- 3 files changed, 128 insertions(+), 30 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 0d628506f7..676f839bcd 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Result, Sigcontrol, SIGCHLD, SIGCONT, SIGURG, SIGWINCH}; +use syscall::{Error, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH}; use crate::arch::*; use crate::sync::Mutex; @@ -101,6 +101,54 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 Ok(()) } +#[derive(Clone, Copy)] +pub enum Sigaction { + Default, + Ignore, + Handled { + handler: SignalHandler, + mask: u64, + flags: SigactionFlags, + }, +} +pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> { + if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) { + return Err(Error::new(EINVAL)); + } + + let _sigguard = tmp_disable_signals(); + let ctl = current_sigctl(); + let guard = SIGACTIONS.lock(); + let old_ignmask = IGNMASK.load(Ordering::Relaxed); + + if let Some(old) = old { + } + + let Some(new) = new else { + return Ok(()); + }; + + match (usize::from(signal), new) { + (_, Sigaction::Ignore) | (SIGCHLD | SIGURG | SIGWINCH, Sigaction::Default) => { + IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); + + // mark the signal as masked + ctl.word[usize::from(signal) / 32].fetch_or(1 << ((signal - 1) % 32), Ordering::Relaxed); + + // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by + // sigaction. + // TODO: handle tmp_disable_signals + } + (SIGTSTP, Sigaction::Default) => (), // stop + (SIGTTIN, Sigaction::Default) => (), // stop + (SIGTTOU, Sigaction::Default) => (), // stop + (_, Sigaction::Default) => (), + (_, Sigaction::Handled { .. }) => (), + } + + todo!() +} + extern "C" { pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; } @@ -137,16 +185,18 @@ impl Drop for TmpDisableSignalsGuard { } } -#[derive(Clone, Copy)] -struct SignalAction { - handler: SignalHandler, - flags: SigactionFlags, - mask: u64, -} bitflags::bitflags! { + // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion. #[derive(Clone, Copy)] - struct SigactionFlags: u32 { - const SA_RESETHAND = 1; + pub struct SigactionFlags: u32 { + const NOCLDSTOP = 1; + const NOCLDWAIT = 2; + const SIGINFO = 4; + const RESTORER = 0x0400_0000; + const ONSTACK = 0x0800_0000; + const RESTART = 0x1000_0000; + const NODEFER = 0x4000_0000; + const RESETHAND = 0x8000_0000; } } fn default_term_handler(sig: c_int) { @@ -161,22 +211,18 @@ fn stop_handler_sentinel(_: c_int) { } #[derive(Clone, Copy)] -union SignalHandler { - sa_handler: Option, - sa_sigaction: Option, +pub union SignalHandler { + pub handler: Option, + pub sigaction: Option, } struct TheDefault { - actions: [SignalAction; 64], + actions: [Sigaction; 64], ignmask: u64, } -static SIGACTIONS: Mutex<[SignalAction; 64]> = Mutex::new([SignalAction { - handler: SignalHandler { sa_handler: None }, - flags: SigactionFlags::empty(), - mask: 0, -}; 64]); -static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH) | sig_bit(SIGCONT)); +static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction::Default; 64]); +static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); fn expand_mask(mask: u64) -> [u64; 2] { [mask & 0xffff_ffff, mask >> 32] diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs index f146dcda53..f21c168e47 100644 --- a/src/header/signal/redox.rs +++ b/src/header/signal/redox.rs @@ -69,14 +69,14 @@ pub const NSIG: usize = 32; pub const SIGRTMIN: usize = 35; pub const SIGRTMAX: usize = 64; -pub const SA_NOCLDSTOP: usize = 0x00000001; -pub const SA_NOCLDWAIT: usize = 0x00000002; -pub const SA_SIGINFO: usize = 0x00000004; -pub const SA_RESTORER: usize = 0x04000000; -pub const SA_ONSTACK: usize = 0x08000000; -pub const SA_RESTART: usize = 0x10000000; -pub const SA_NODEFER: usize = 0x40000000; -pub const SA_RESETHAND: usize = 0x80000000; +pub const SA_NOCLDSTOP: usize = 0x0000_0001; +pub const SA_NOCLDWAIT: usize = 0x0000_0002; +pub const SA_SIGINFO: usize = 0x0000_0004; +pub const SA_RESTORER: usize = 0x0400_0000; +pub const SA_ONSTACK: usize = 0x0800_0000; +pub const SA_RESTART: usize = 0x1000_0000; +pub const SA_NODEFER: usize = 0x4000_0000; +pub const SA_RESETHAND: usize = 0x8000_0000; pub const SS_ONSTACK: usize = 0x00000001; pub const SS_DISABLE: usize = 0x00000002; diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index f8f82a8d88..625ac730c0 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,4 +1,5 @@ use core::mem; +use redox_rt::signal::{Sigaction, SigactionFlags, SignalHandler}; use syscall::{self, Result}; use super::{ @@ -8,7 +9,7 @@ use super::{ use crate::{ header::{ errno::{EINVAL, ENOSYS}, - signal::{sigaction, siginfo_t, sigset_t, stack_t, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, + signal::{sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK}, sys_time::{itimerval, ITIMER_REAL}, time::timespec, }, @@ -104,8 +105,59 @@ impl PalSignal for Sys { 0 } - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> { - todo!() + fn sigaction(sig: c_int, c_act: Option<&sigaction>, c_oact: Option<&mut sigaction>) -> Result<(), Errno> { + let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?; + + let new_action = c_act.map(|c_act| { + let handler = c_act.sa_handler.map_or(0, |f| f as usize); + + if handler == SIG_DFL { + Sigaction::Default + } else if handler == SIG_IGN { + Sigaction::Ignore + } else { + Sigaction::Handled { + handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 { + SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) } } + } else { + SignalHandler { handler: c_act.sa_handler } + }, + mask: c_act.sa_mask, + flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32), + } + } + }); + let mut old_action = c_oact.as_ref().map(|_| Sigaction::Default); + + redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?; + + if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) { + *c_oact = match old_action { + Sigaction::Ignore => sigaction { + sa_handler: unsafe { core::mem::transmute(SIG_IGN) }, + sa_flags: 0, + sa_restorer: None, + sa_mask: 0, + }, + Sigaction::Default => sigaction { + sa_handler: unsafe { core::mem::transmute(SIG_DFL) }, + sa_flags: 0, + sa_restorer: None, + sa_mask: 0, + }, + Sigaction::Handled { handler, mask, flags } => sigaction { + sa_handler: if flags.contains(SigactionFlags::SIGINFO) { + unsafe { core::mem::transmute(handler.sigaction) } + } else { + unsafe { handler.handler } + }, + sa_restorer: None, + sa_flags: flags.bits().into(), + sa_mask: mask, + }, + }; + } + Ok(()) } unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { From 5177ca3926cb948986e1276d5797c8f707d2b347 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 15:52:26 +0200 Subject: [PATCH 08/67] Remove memoffset dependency. --- Cargo.lock | 10 ---------- Cargo.toml | 1 - src/ld_so/tcb.rs | 2 +- src/lib.rs | 2 -- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 520d4c544f..fc8e8ae2d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,15 +214,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -408,7 +399,6 @@ dependencies = [ "libc", "md-5", "memchr", - "memoffset", "pbkdf2", "plain", "posix-regex", diff --git a/Cargo.toml b/Cargo.toml index f3c83b3afc..031a2214bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ cc = "1" [dependencies] bitflags = "2" cbitset = "0.2" -memoffset = "0.9" posix-regex = { path = "posix-regex", features = ["no_std"] } # TODO: For some reason, rand_jitter hasn't been updated to use the latest rand_core diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 2b012ea7fd..ecd8fef49b 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use syscall::Sigcontrol; -use core::{arch::asm, cell::UnsafeCell, mem, ptr, slice, sync::atomic::AtomicBool}; +use core::{arch::asm, cell::UnsafeCell, mem::{self, offset_of}, ptr, slice, sync::atomic::AtomicBool}; use goblin::error::{Error, Result}; use super::ExpectTlsFree; diff --git a/src/lib.rs b/src/lib.rs index b44e17f9f7..24afb60432 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,6 @@ extern crate alloc; extern crate cbitset; extern crate goblin; extern crate memchr; -#[macro_use] -extern crate memoffset; extern crate posix_regex; extern crate rand; From edfe46c60b94d19a3f6d6102db195961f56b701d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 16:43:21 +0200 Subject: [PATCH 09/67] Write x86-64 signal trampoline asm stub. --- redox-rt/src/arch/x86_64.rs | 164 +++++++++++++++++++++++++++--------- redox-rt/src/signal.rs | 15 ++-- src/ld_so/dso.rs | 6 +- src/ld_so/linker.rs | 4 +- src/ld_so/tcb.rs | 13 +-- src/start.rs | 2 +- 6 files changed, 146 insertions(+), 58 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 2d9fb84be4..cba03eb0f3 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,3 +1,7 @@ +use core::mem::offset_of; +use core::sync::atomic::AtomicU8; + +use syscall::data::Sigcontrol; use syscall::error::*; use crate::proc::{fork_inner, FdGuard}; @@ -7,6 +11,14 @@ use crate::signal::inner_c; pub(crate) const STACK_TOP: usize = 1 << 47; pub(crate) const STACK_SIZE: usize = 1024 * 1024; +// NOTE: MUST MATCH TCB STRUCT +pub struct SigArea { + altstack_top: usize, + altstack_bottom: usize, + tmp: usize, + _rsvd: usize, +} + /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS /// is already initialized as if it was a thread. pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> { @@ -90,46 +102,6 @@ asmfunction!(__relibc_internal_fork_ret: [" pop rbp ret "] <= []); -// TODO: is the memset necessary? -asmfunction!(__relibc_internal_sigentry_fxsave: [" - sub rsp, 4096 - - fxsave64 [rsp] - - mov rdi, rsp - call {inner} - - fxrstor64 [rsp] - add rsp, 4096 - - //mov eax, {{SYS_SIGRETURN}} - syscall -"] <= [inner = sym inner_c]); -asmfunction!(__relibc_internal_sigentry_xsave: [" - sub rsp, 4096 - - cld - mov rdi, rsp - xor eax, eax - mov ecx, 4096 - rep stosb - - mov eax, 0xffffffff - mov edx, eax - xsave [rsp] - - mov rdi, rsp - call {inner} - - mov eax, 0xffffffff - mov edx, eax - xrstor [rsp] - add rsp, 4096 - - //mov eax, {{SYS_SIGRETURN}} - syscall -"] <= [inner = sym inner_c]); - asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" # Load registers pop rax @@ -154,3 +126,115 @@ asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" ret "] <= []); + +asmfunction!(__relibc_internal_sigentry: [" + // Get offset to TCB + mov rax, gs:[0] + + // If current RSP is above altstack region, switch to altstack + mov rdx, [rax + {tcb_sa_off} + {sa_altstack_top}] + cmp rdx, rsp + cmova rsp, rdx + + // If current RSP is below altstack region, also switch to altstack + mov rdx, [rax + {tcb_sa_off} + {sa_altstack_bottom}] + cmp rdx, rax + cmovbe rsp, rdx + + // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent + // to setting 'top' to usize::MAX and 'bottom' to 0. + // + // Now that we have a stack, we can finally start initializing the signal stack! + + push ss + push [rax + {tcb_sc_off} + {sc_saved_rsp}] + push [rax + {tcb_sc_off} + {sc_saved_rflags}] + push cs + push [rax + {tcb_sc_off} + {sc_saved_rip}] + + push rdi + push rsi + push [rax + {tcb_sc_off} + {sc_saved_rdx}] + push rcx + push [rax + {tcb_sc_off} + {sc_saved_rax}] + push r8 + push r9 + push r10 + push r11 + push rbx + push rbp + push r12 + push r13 + push r14 + push r15 + + sub rsp, 4096 + 32 + + cld + mov rdi, rsp + xor eax, eax + mov ecx, 4096 + 32 + rep stosb + + // TODO: self-modifying? + cmp byte ptr [{supports_xsave}], 0 + je 3f + + mov eax, 0xffffffff + mov edx, eax + xsave [rsp] + + mov rdi, rsp + call {inner} + + mov eax, 0xffffffff + mov edx, eax + xrstor [rsp] + + add rsp, 4096 + 32 +2: + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + pop r11 + pop r10 + pop r9 + pop r8 + pop rax + pop rcx + pop rdx + pop rsi + pop rdi + + pop gs:[{tcb_sa_off} + {sa_tmp}] + add rsp, 8 + popfq + pop rsp + jmp gs:[{tcb_sa_off} + {sa_tmp}] +3: + fxsave64 [rsp] + + mov rdi, rsp + call {inner} + + fxrstor64 [rsp] + jmp 2b +"] <= [ + inner = sym inner_c, + sa_tmp = const offset_of!(SigArea, tmp), + sa_altstack_top = const offset_of!(SigArea, altstack_top), + sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), + sc_saved_rax = const offset_of!(Sigcontrol, saved_scratch_a), + sc_saved_rdx = const offset_of!(Sigcontrol, saved_scratch_b), + sc_saved_rflags = const offset_of!(Sigcontrol, saved_flags), + sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), + sc_saved_rsp = const offset_of!(Sigcontrol, saved_sp), + tcb_sa_off = const 0, // FIXME + tcb_sc_off = const 0, // FIXME + supports_xsave = sym SUPPORTS_XSAVE, +]); + +static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(0); // FIXME diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 676f839bcd..3097a7e4c0 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Error, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH}; use crate::arch::*; use crate::sync::Mutex; @@ -14,13 +14,13 @@ pub fn sighandler_function() -> usize { #[cfg(target_arch = "x86_64")] // Check OSXSAVE bit // TODO: HWCAP? - if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { + /*if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { __relibc_internal_sigentry_xsave as usize } else { __relibc_internal_sigentry_fxsave as usize - } + }*/ - #[cfg(any(target_arch = "x86", target_arch = "aarch64"))] + //#[cfg(any(target_arch = "x86", target_arch = "aarch64"))] { __relibc_internal_sigentry as usize } @@ -28,14 +28,17 @@ pub fn sighandler_function() -> usize { #[repr(C)] pub struct SigStack { + sa_handler: usize, + sig_num: usize, + #[cfg(target_arch = "x86_64")] fx: [u8; 4096], #[cfg(target_arch = "x86")] fx: [u8; 512], - sa_handler: usize, - sig_num: usize, + _pad: [usize; 4], // pad to 192 = 3 * 64 bytes + regs: IntRegisters, // 160 bytes currently } #[inline(always)] diff --git a/src/ld_so/dso.rs b/src/ld_so/dso.rs index 0bd7a566a6..135ec59dc0 100644 --- a/src/ld_so/dso.rs +++ b/src/ld_so/dso.rs @@ -1,7 +1,7 @@ use super::{ debug::{RTLDDebug, _r_debug}, linker::Symbol, - tcb::{round_up, Master}, + tcb::Master, }; use crate::{ header::{errno::STR_ERROR, sys_mman}, @@ -170,7 +170,7 @@ impl DSO { for ph in elf.program_headers.iter() { let voff = ph.p_vaddr % ph.p_align; let vaddr = (ph.p_vaddr - voff) as usize; - let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize); + let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize); match ph.p_type { program_header::PT_DYNAMIC => { @@ -253,7 +253,7 @@ impl DSO { for ph in elf.program_headers.iter() { let voff = ph.p_vaddr % ph.p_align; let vaddr = (ph.p_vaddr - voff) as usize; - let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize); + let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize); match ph.p_type { program_header::PT_LOAD => { diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 6e76e53b84..983715cbfd 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -27,7 +27,7 @@ use super::{ callbacks::LinkerCallbacks, debug::{RTLDState, _dl_debug_state, _r_debug}, dso::{is_pie_enabled, DSO}, - tcb::{round_up, Master, Tcb}, + tcb::{Master, Tcb}, ExpectTlsFree, PATH_SEP, }; @@ -453,7 +453,7 @@ impl Linker { { let voff = ph.p_vaddr % ph.p_align; let vaddr = (ph.p_vaddr - voff) as usize; - let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize); + let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize); let mut prot = 0; if ph.p_flags & program_header::PF_R == program_header::PF_R { prot |= sys_mman::PROT_READ; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index ecd8fef49b..784131c8be 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -55,14 +55,19 @@ pub struct Tcb { /// Underlying pthread_t struct, pthread_self() returns &self.pthread pub pthread: Pthread, #[cfg(target_os = "redox")] - pub sigcontrol: Sigcontrol, + pub sigcontrol: RtSigarea, +} +#[derive(Debug, Default)] +pub struct RtSigarea { + pub control: Sigcontrol, + pub internal: [usize; 4], } impl Tcb { /// Create a new TCB pub unsafe fn new(size: usize) -> Result<&'static mut Self> { let page_size = Sys::getpagesize(); - let (abi_page, tls, tcb_page) = Self::os_new(round_up(size, page_size))?; + let (abi_page, tls, tcb_page) = Self::os_new(size.next_multiple_of(page_size))?; let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self; trace!("New TCB: {:p}", tcb_ptr); @@ -326,7 +331,3 @@ impl Tcb { let _ = syscall::close(file); } } - -pub fn round_up(value: usize, alignment: usize) -> usize { - return (value + alignment - 1) & (!(alignment - 1)); -} diff --git a/src/start.rs b/src/start.rs index 540ddb6d12..d0301b1b2b 100644 --- a/src/start.rs +++ b/src/start.rs @@ -158,7 +158,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); } #[cfg(target_os = "redox")] - redox_rt::signal::setup_sighandler(&tcb.sigcontrol); + redox_rt::signal::setup_sighandler(&tcb.sigcontrol.control); } // Set up argc and argv From 736a445af61722850164ea7f262362ce68436707 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 22:25:23 +0200 Subject: [PATCH 10/67] Use new proc control struct too. --- redox-rt/src/signal.rs | 20 +++++++++++++++----- redox-rt/src/thread.rs | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 3097a7e4c0..f822bfaf53 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Error, IntRegisters, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; use crate::arch::*; use crate::sync::Mutex; @@ -142,9 +142,11 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction // sigaction. // TODO: handle tmp_disable_signals } - (SIGTSTP, Sigaction::Default) => (), // stop - (SIGTTIN, Sigaction::Default) => (), // stop - (SIGTTOU, Sigaction::Default) => (), // stop + // TODO: Handle pending signals before these flags are set. + (SIGTSTP, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst), + (SIGTTIN, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst), + (SIGTTOU, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst), + (_, Sigaction::Default) => (), (_, Sigaction::Handled { .. }) => (), } @@ -227,6 +229,13 @@ struct TheDefault { static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction::Default; 64]); static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); +static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { + word: [ + AtomicU64::new(SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT), + AtomicU64::new(0), + ], +}; + fn expand_mask(mask: u64) -> [u64; 2] { [mask & 0xffff_ffff, mask >> 32] } @@ -254,7 +263,8 @@ pub fn setup_sighandler(control: &Sigcontrol) { let data = syscall::SetSighandlerData { user_handler: sighandler_function(), excp_handler: 0, // TODO - word_addr: control as *const Sigcontrol as usize, + thread_control_addr: control as *const Sigcontrol as usize, + proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, }; let fd = syscall::open( diff --git a/redox-rt/src/thread.rs b/redox-rt/src/thread.rs index 298858315f..60201c38bd 100644 --- a/redox-rt/src/thread.rs +++ b/redox-rt/src/thread.rs @@ -53,7 +53,8 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { let data = SetSighandlerData { user_handler: sighandler_function(), excp_handler: 0, - word_addr: 0, // TODO + thread_control_addr: 0, // TODO + proc_control_addr: 0, // TODO }; let _ = syscall::write(*new_sighandler_fd, &data)?; } From 58d1153536793565ceb13feb17f66e835c4f6251 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 22:38:36 +0200 Subject: [PATCH 11/67] Split part of TCB into generic-rt --- Cargo.lock | 6 +++ Cargo.toml | 2 + generic-rt/Cargo.toml | 6 +++ generic-rt/src/lib.rs | 73 +++++++++++++++++++++++++ redox-rt/Cargo.toml | 2 + redox-rt/src/arch/x86_64.rs | 3 +- redox-rt/src/signal.rs | 17 ++++-- src/ld_so/tcb.rs | 103 +++++++++++------------------------- src/start.rs | 2 +- 9 files changed, 135 insertions(+), 79 deletions(-) create mode 100644 generic-rt/Cargo.toml create mode 100644 generic-rt/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fc8e8ae2d7..7164fbfd51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,10 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-rt" +version = "0.1.0" + [[package]] name = "goblin" version = "0.7.1" @@ -362,6 +366,7 @@ name = "redox-rt" version = "0.1.0" dependencies = [ "bitflags", + "generic-rt", "goblin", "plain", "redox_syscall", @@ -395,6 +400,7 @@ dependencies = [ "cbitset", "cc", "dlmalloc", + "generic-rt", "goblin", "libc", "md-5", diff --git a/Cargo.toml b/Cargo.toml index 031a2214bb..da68a3e725 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "src/crtn", "redox-rt", "ld_so", + "generic-rt", ] exclude = ["tests", "dlmalloc-rs"] @@ -42,6 +43,7 @@ bcrypt-pbkdf = { version = "0.10", default-features = false, features = ["alloc" scrypt = { version = "0.11", default-features = false, features = ["simple"]} pbkdf2 = { version = "0.12", features = ["sha2"]} sha2 = { version = "0.10", default-features = false } +generic-rt = { path = "generic-rt" } [dependencies.goblin] version = "0.7" diff --git a/generic-rt/Cargo.toml b/generic-rt/Cargo.toml new file mode 100644 index 0000000000..11e01ee046 --- /dev/null +++ b/generic-rt/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "generic-rt" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs new file mode 100644 index 0000000000..97e277a045 --- /dev/null +++ b/generic-rt/src/lib.rs @@ -0,0 +1,73 @@ +#![no_std] + +use core::arch::asm; +use core::mem::{self, offset_of}; + +#[derive(Debug)] +#[repr(C)] +pub struct GenericTcb { + /// Pointer to the end of static TLS. Must be the first member + pub tls_end: *mut u8, + /// Size of the memory allocated for the static TLS in bytes (multiple of page size) + pub tls_len: usize, + /// Pointer to this structure + pub tcb_ptr: *mut Self, + /// Size of the memory allocated for this structure in bytes (should be same as page size) + pub tcb_len: usize, + pub os_specific: Os, +} +impl GenericTcb { + /// Architecture specific code to read a usize from the TCB - aarch64 + #[inline(always)] + #[cfg(target_arch = "aarch64")] + pub unsafe fn arch_read(offset: usize) -> usize { + let abi_ptr: usize; + asm!( + "mrs {}, tpidr_el0", + out(reg) abi_ptr, + ); + + let tcb_ptr = *(abi_ptr as *const usize); + *((tcb_ptr + offset) as *const usize) + } + + /// Architecture specific code to read a usize from the TCB - x86 + #[inline(always)] + #[cfg(target_arch = "x86")] + pub unsafe fn arch_read(offset: usize) -> usize { + let value; + asm!( + " + mov {}, gs:[{}] + ", + out(reg) value, + in(reg) offset, + ); + value + } + + /// Architecture specific code to read a usize from the TCB - x86_64 + #[inline(always)] + #[cfg(target_arch = "x86_64")] + pub unsafe fn arch_read(offset: usize) -> usize { + let value; + asm!( + " + mov {}, fs:[{}] + ", + out(reg) value, + in(reg) offset, + ); + value + } + + pub unsafe fn current_ptr() -> Option<*mut Self> { + let tcb_ptr = Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self; + let tcb_len = Self::arch_read(offset_of!(Self, tcb_len)); + if tcb_ptr.is_null() || tcb_len < mem::size_of::() { + None + } else { + Some(tcb_ptr) + } + } +} diff --git a/redox-rt/Cargo.toml b/redox-rt/Cargo.toml index 210e5b8884..0cffcdca3b 100644 --- a/redox-rt/Cargo.toml +++ b/redox-rt/Cargo.toml @@ -13,3 +13,5 @@ bitflags = "2" goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] } plain = "0.2" redox_syscall = "0.5.1" + +generic-rt = { path = "../generic-rt" } diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index cba03eb0f3..580fb94655 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -11,12 +11,11 @@ use crate::signal::inner_c; pub(crate) const STACK_TOP: usize = 1 << 47; pub(crate) const STACK_SIZE: usize = 1024 * 1024; -// NOTE: MUST MATCH TCB STRUCT +#[derive(Debug, Default)] pub struct SigArea { altstack_top: usize, altstack_bottom: usize, tmp: usize, - _rsvd: usize, } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index f822bfaf53..d805f4cf3e 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -143,9 +143,15 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction // TODO: handle tmp_disable_signals } // TODO: Handle pending signals before these flags are set. - (SIGTSTP, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst), - (SIGTTIN, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst), - (SIGTTOU, Sigaction::Default) => PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst), + (SIGTSTP, Sigaction::Default) => { + PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst); + } + (SIGTTIN, Sigaction::Default) => { + PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst); + } + (SIGTTOU, Sigaction::Default) => { + PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst); + } (_, Sigaction::Default) => (), (_, Sigaction::Handled { .. }) => (), @@ -275,3 +281,8 @@ pub fn setup_sighandler(control: &Sigcontrol) { syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); let _ = syscall::close(fd); } +#[derive(Debug, Default)] +pub struct RtSigarea { + pub control: Sigcontrol, + pub arch: crate::arch::SigArea, +} diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 784131c8be..b2176b6989 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -1,6 +1,7 @@ use alloc::vec::Vec; +use generic_rt::GenericTcb; use syscall::Sigcontrol; -use core::{arch::asm, cell::UnsafeCell, mem::{self, offset_of}, ptr, slice, sync::atomic::AtomicBool}; +use core::{arch::asm, cell::UnsafeCell, mem, ops::{Deref, DerefMut}, ptr, slice, sync::atomic::AtomicBool}; use goblin::error::{Error, Result}; use super::ExpectTlsFree; @@ -30,18 +31,17 @@ impl Master { } } +#[cfg(target_os = "linux")] +type OsSpecific = (); + +#[cfg(target_os = "redox")] +type OsSpecific = redox_rt::signal::RtSigarea; + #[derive(Debug)] #[repr(C)] // FIXME: Only return &Tcb, and use interior mutability, since it contains the Pthread struct pub struct Tcb { - /// Pointer to the end of static TLS. Must be the first member - pub tls_end: *mut u8, - /// Size of the memory allocated for the static TLS in bytes (multiple of page size) - pub tls_len: usize, - /// Pointer to this structure - pub tcb_ptr: *mut Tcb, - /// Size of the memory allocated for this structure in bytes (should be same as page size) - pub tcb_len: usize, + pub generic: GenericTcb, /// Pointer to a list of initial TLS data pub masters_ptr: *mut Master, /// Size of the masters list in bytes (multiple of mem::size_of::()) @@ -54,13 +54,6 @@ pub struct Tcb { pub mspace: *const Mutex, /// Underlying pthread_t struct, pthread_self() returns &self.pthread pub pthread: Pthread, - #[cfg(target_os = "redox")] - pub sigcontrol: RtSigarea, -} -#[derive(Debug, Default)] -pub struct RtSigarea { - pub control: Sigcontrol, - pub internal: [usize; 4], } impl Tcb { @@ -74,10 +67,13 @@ impl Tcb { ptr::write( tcb_ptr, Self { - tls_end: tls.as_mut_ptr().add(tls.len()), - tls_len: tls.len(), - tcb_ptr, - tcb_len: tcb_page.len(), + generic: GenericTcb { + tls_end: tls.as_mut_ptr().add(tls.len()), + tls_len: tls.len(), + tcb_ptr: tcb_ptr.cast(), + tcb_len: tcb_page.len(), + os_specific: OsSpecific::default(), + }, masters_ptr: ptr::null_mut(), masters_len: 0, num_copied_masters: 0, @@ -92,8 +88,6 @@ impl Tcb { stack_size: 0, os_tid: UnsafeCell::new(OsTid::default()), }, - #[cfg(target_os = "redox")] - sigcontrol: Default::default(), }, ); @@ -102,13 +96,7 @@ impl Tcb { /// Get the current TCB pub unsafe fn current() -> Option<&'static mut Self> { - let tcb_ptr = Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self; - let tcb_len = Self::arch_read(offset_of!(Self, tcb_len)); - if tcb_ptr.is_null() || tcb_len < mem::size_of::() { - None - } else { - Some(&mut *tcb_ptr) - } + Some(&mut *GenericTcb::::current_ptr()?.cast()) } /// A slice for all of the TLS data @@ -228,50 +216,6 @@ impl Tcb { Ok((abi, tls, tcb)) } - /// Architecture specific code to read a usize from the TCB - aarch64 - #[inline(always)] - #[cfg(target_arch = "aarch64")] - unsafe fn arch_read(offset: usize) -> usize { - let abi_ptr: usize; - asm!( - "mrs {}, tpidr_el0", - out(reg) abi_ptr, - ); - - let tcb_ptr = *(abi_ptr as *const usize); - *((tcb_ptr + offset) as *const usize) - } - - /// Architecture specific code to read a usize from the TCB - x86 - #[inline(always)] - #[cfg(target_arch = "x86")] - unsafe fn arch_read(offset: usize) -> usize { - let value; - asm!( - " - mov {}, gs:[{}] - ", - out(reg) value, - in(reg) offset, - ); - value - } - - /// Architecture specific code to read a usize from the TCB - x86_64 - #[inline(always)] - #[cfg(target_arch = "x86_64")] - unsafe fn arch_read(offset: usize) -> usize { - let value; - asm!( - " - mov {}, fs:[{}] - ", - out(reg) value, - in(reg) offset, - ); - value - } - /// OS and architecture specific code to activate TLS - Linux x86_64 #[cfg(all(target_os = "linux", target_arch = "x86_64"))] unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { @@ -331,3 +275,16 @@ impl Tcb { let _ = syscall::close(file); } } + +impl Deref for Tcb { + type Target = GenericTcb; + + fn deref(&self) -> &Self::Target { + &self.generic + } +} +impl DerefMut for Tcb { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.generic + } +} diff --git a/src/start.rs b/src/start.rs index d0301b1b2b..9bf2f8da5b 100644 --- a/src/start.rs +++ b/src/start.rs @@ -158,7 +158,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); } #[cfg(target_os = "redox")] - redox_rt::signal::setup_sighandler(&tcb.sigcontrol.control); + redox_rt::signal::setup_sighandler(&tcb.os_specific.control); } // Set up argc and argv From a60710c59732f43a66ccb0ca5ca3f160ec765dbe Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 22:43:25 +0200 Subject: [PATCH 12/67] Add missing signal arch offsets. --- redox-rt/src/arch/x86_64.rs | 6 +++--- redox-rt/src/lib.rs | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 580fb94655..de94685416 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -5,7 +5,7 @@ use syscall::data::Sigcontrol; use syscall::error::*; use crate::proc::{fork_inner, FdGuard}; -use crate::signal::inner_c; +use crate::signal::{inner_c, RtSigarea}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; @@ -231,8 +231,8 @@ asmfunction!(__relibc_internal_sigentry: [" sc_saved_rflags = const offset_of!(Sigcontrol, saved_flags), sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), sc_saved_rsp = const offset_of!(Sigcontrol, saved_sp), - tcb_sa_off = const 0, // FIXME - tcb_sc_off = const 0, // FIXME + tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), + tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), supports_xsave = sym SUPPORTS_XSAVE, ]); diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 257ea43129..84c7eac9eb 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -2,6 +2,10 @@ #![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell, thread_local)] #![forbid(unreachable_patterns)] +use generic_rt::GenericTcb; + +use self::signal::RtSigarea; + extern crate alloc; #[macro_export] @@ -33,3 +37,5 @@ pub mod auxv_defs; pub mod signal; pub mod sync; pub mod thread; + +pub type Tcb = GenericTcb; From 4e93f68324c92d261519d8e0e0714c977862e040 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 21 Jun 2024 13:20:28 +0200 Subject: [PATCH 13/67] Implement hack to ensure TCB exists in bootstrap. --- generic-rt/src/lib.rs | 39 +++++++++++++++++++ redox-rt/src/arch/x86_64.rs | 11 +++--- redox-rt/src/lib.rs | 76 ++++++++++++++++++++++++++++++++++++- redox-rt/src/signal.rs | 22 ++++------- src/ld_so/mod.rs | 37 +----------------- src/ld_so/tcb.rs | 51 +------------------------ 6 files changed, 131 insertions(+), 105 deletions(-) diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs index 97e277a045..2999115c36 100644 --- a/generic-rt/src/lib.rs +++ b/generic-rt/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![feature(core_intrinsics)] use core::arch::asm; use core::mem::{self, offset_of}; @@ -70,4 +71,42 @@ impl GenericTcb { Some(tcb_ptr) } } + pub unsafe fn current() -> Option<&'static mut Self> { + Some(&mut *Self::current_ptr()?) + } } +pub fn panic_notls(msg: impl core::fmt::Display) -> ! { + //eprintln!("panicked in ld.so: {}", msg); + + core::intrinsics::abort(); +} + +pub trait ExpectTlsFree { + type Unwrapped; + + fn expect_notls(self, msg: &str) -> Self::Unwrapped; +} +impl ExpectTlsFree for Result { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Ok(t) => t, + Err(err) => panic_notls(format_args!( + "{}: expect failed for Result with err: {:?}", + msg, err + )), + } + } +} +impl ExpectTlsFree for Option { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Some(t) => t, + None => panic_notls(format_args!("{}: expect failed for Option", msg)), + } + } +} + diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index de94685416..c1a11cd278 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -16,6 +16,7 @@ pub struct SigArea { altstack_top: usize, altstack_bottom: usize, tmp: usize, + pub disable_signals_depth: u64, } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS @@ -145,10 +146,10 @@ asmfunction!(__relibc_internal_sigentry: [" // // Now that we have a stack, we can finally start initializing the signal stack! - push ss + push 0 // SS push [rax + {tcb_sc_off} + {sc_saved_rsp}] push [rax + {tcb_sc_off} + {sc_saved_rflags}] - push cs + push 0 // CS push [rax + {tcb_sc_off} + {sc_saved_rip}] push rdi @@ -176,7 +177,7 @@ asmfunction!(__relibc_internal_sigentry: [" rep stosb // TODO: self-modifying? - cmp byte ptr [{supports_xsave}], 0 + cmp byte ptr [rip + {supports_xsave}], 0 je 3f mov eax, 0xffffffff @@ -208,11 +209,11 @@ asmfunction!(__relibc_internal_sigentry: [" pop rsi pop rdi - pop gs:[{tcb_sa_off} + {sa_tmp}] + pop qword ptr gs:[{tcb_sa_off} + {sa_tmp}] add rsp, 8 popfq pop rsp - jmp gs:[{tcb_sa_off} + {sa_tmp}] + jmp qword ptr gs:[{tcb_sa_off} + {sa_tmp}] 3: fxsave64 [rsp] diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 84c7eac9eb..2d06cc8ec3 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -1,8 +1,8 @@ #![no_std] -#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell, thread_local)] +#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell)] #![forbid(unreachable_patterns)] -use generic_rt::GenericTcb; +use generic_rt::{ExpectTlsFree, GenericTcb}; use self::signal::RtSigarea; @@ -39,3 +39,75 @@ pub mod sync; pub mod thread; pub type Tcb = GenericTcb; + +/// OS and architecture specific code to activate TLS - Redox aarch64 +#[cfg(target_arch = "aarch64")] +pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) { + // Uses ABI page + let abi_ptr = tls_end - tls_len - 16; + ptr::write(abi_ptr as *mut usize, tls_end); + asm!( + "msr tpidr_el0, {}", + in(reg) abi_ptr, + ); +} + +/// OS and architecture specific code to activate TLS - Redox x86 +#[cfg(target_arch = "x86")] +pub unsafe fn tcb_activate(tls_end: usize, _tls_len: usize) { + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open( + "thisproc:current/regs/env", + syscall::O_CLOEXEC | syscall::O_RDWR, + ) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); + + env.gsbase = tls_end as u32; + + let _ = syscall::write(file, &env).expect_notls("failed to write gsbase"); + + let _ = syscall::close(file); +} + +/// OS and architecture specific code to activate TLS - Redox x86_64 +#[cfg(target_arch = "x86_64")] +pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) { + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open( + "thisproc:current/regs/env", + syscall::O_CLOEXEC | syscall::O_RDWR, + ) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); + + env.fsbase = tls_end_and_tcb_start as u64; + + let _ = syscall::write(file, &env).expect_notls("failed to write fsbase"); + + let _ = syscall::close(file); +} + +/// Initialize redox-rt in situations where relibc is not used +pub fn initialize_freestanding() { + // TODO: TLS + let page = unsafe { + &mut *(syscall::fmap(!0, &syscall::Map { + offset: 0, + size: syscall::PAGE_SIZE, + flags: syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE | syscall::MapFlags::MAP_PRIVATE, + address: 0, + }).unwrap() as *mut Tcb) + }; + page.tcb_ptr = page; + page.tcb_len = syscall::PAGE_SIZE; + page.tls_end = (page as *mut Tcb).cast(); + + unsafe { + tcb_activate(page as *mut Tcb as usize, 0) + } +} diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index d805f4cf3e..f1dbf58baa 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; use syscall::{Error, IntRegisters, Result, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; -use crate::arch::*; +use crate::{arch::*, Tcb}; use crate::sync::Mutex; #[cfg(target_arch = "x86_64")] @@ -160,24 +160,18 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction todo!() } -extern "C" { - pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; -} fn current_sigctl() -> &'static Sigcontrol { - unsafe { __relibc_internal_get_sigcontrol_addr() } + &unsafe { Tcb::current() }.unwrap().os_specific.control } pub struct TmpDisableSignalsGuard { _inner: () } -#[thread_local] -static TMP_DISABLE_SIGNALS_DEPTH: Cell = Cell::new(0); - pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { unsafe { - let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + let ctl = current_sigctl().control_flags.get(); ctl.write_volatile(ctl.read_volatile() | syscall::flag::INHIBIT_DELIVERY); // TODO: fence? - TMP_DISABLE_SIGNALS_DEPTH.set(TMP_DISABLE_SIGNALS_DEPTH.get() + 1); + Tcb::current().unwrap().os_specific.arch.disable_signals_depth += 1; } TmpDisableSignalsGuard { _inner: () } @@ -185,11 +179,11 @@ pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { impl Drop for TmpDisableSignalsGuard { fn drop(&mut self) { unsafe { - let old = TMP_DISABLE_SIGNALS_DEPTH.get(); - TMP_DISABLE_SIGNALS_DEPTH.set(old - 1); + let depth = &mut Tcb::current().unwrap().os_specific.arch.disable_signals_depth; + *depth -= 1; - if old == 1 { - let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + if *depth == 0 { + let ctl = current_sigctl().control_flags.get(); ctl.write_volatile(ctl.read_volatile() & !syscall::flag::INHIBIT_DELIVERY); } } diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 809dad7ebd..db559cb886 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -22,47 +22,14 @@ pub mod linker; pub mod start; pub mod tcb; +pub use generic_rt::{panic_notls, ExpectTlsFree}; + static mut STATIC_TCB_MASTER: Master = Master { ptr: ptr::null_mut(), len: 0, offset: 0, }; -fn panic_notls(msg: impl core::fmt::Display) -> ! { - eprintln!("panicked in ld.so: {}", msg); - - core::intrinsics::abort(); -} - -pub trait ExpectTlsFree { - type Unwrapped; - - fn expect_notls(self, msg: &str) -> Self::Unwrapped; -} -impl ExpectTlsFree for Result { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Ok(t) => t, - Err(err) => panic_notls(format_args!( - "{}: expect failed for Result with err: {:?}", - msg, err - )), - } - } -} -impl ExpectTlsFree for Option { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Some(t) => t, - None => panic_notls(format_args!("{}: expect failed for Option", msg)), - } - } -} - #[inline(never)] pub fn static_init(sp: &'static Stack) { let mut phdr_opt = None; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index b2176b6989..ae1b9eaf4c 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -223,56 +223,9 @@ impl Tcb { syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end); } - /// OS and architecture specific code to activate TLS - Redox aarch64 - #[cfg(all(target_os = "redox", target_arch = "aarch64"))] + #[cfg(all(target_os = "redox"))] unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) { - // Uses ABI page - let abi_ptr = tls_end - tls_len - 16; - ptr::write(abi_ptr as *mut usize, tls_end); - asm!( - "msr tpidr_el0, {}", - in(reg) abi_ptr, - ); - } - - /// OS and architecture specific code to activate TLS - Redox x86 - #[cfg(all(target_os = "redox", target_arch = "x86"))] - unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { - let mut env = syscall::EnvRegisters::default(); - - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); - - let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); - - env.gsbase = tls_end as u32; - - let _ = syscall::write(file, &env).expect_notls("failed to write gsbase"); - - let _ = syscall::close(file); - } - - /// OS and architecture specific code to activate TLS - Redox x86_64 - #[cfg(all(target_os = "redox", target_arch = "x86_64"))] - unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { - let mut env = syscall::EnvRegisters::default(); - - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); - - let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); - - env.fsbase = tls_end as u64; - - let _ = syscall::write(file, &env).expect_notls("failed to write fsbase"); - - let _ = syscall::close(file); + redox_rt::tcb_activate(tls_end, tls_len) } } From d45adade1d4606bfa76d2bcd9ed7597c65c3036c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 21 Jun 2024 13:26:26 +0200 Subject: [PATCH 14/67] Remove obsolete proc usage, now reaches init. --- redox-rt/src/proc.rs | 31 +------------------------------ redox-rt/src/signal.rs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 608aaa683b..9b7dbfc385 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -425,18 +425,6 @@ where deactivate_tcb(*open_via_dup)?; } - { - let current_sigaction_fd = FdGuard::new(syscall::dup(*open_via_dup, b"sigactions")?); - let empty_sigaction_fd = FdGuard::new(syscall::dup(*current_sigaction_fd, b"empty")?); - let sigaction_selection_fd = - FdGuard::new(syscall::dup(*open_via_dup, b"current-sigactions")?); - - let _ = syscall::write( - *sigaction_selection_fd, - &usize::to_ne_bytes(*empty_sigaction_fd), - )?; - } - // TODO: Restore old name if exec failed? if let Ok(name_fd) = syscall::dup(*open_via_dup, b"name").map(FdGuard::new) { let _ = syscall::write(*name_fd, interp_override.as_ref().map_or(path, |o| &o.name)); @@ -727,27 +715,10 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { // Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later). { - let cur_sighandler_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sighandler")?); let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); - - let mut sighandler_buf = SetSighandlerData::default(); - - let _ = syscall::read(*cur_sighandler_fd, &mut sighandler_buf)?; - let _ = syscall::write(*new_sighandler_fd, &sighandler_buf)?; + let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?; } - // Reuse the same sigactions (by value). - { - let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?); - let new_sigaction_fd = FdGuard::new(syscall::dup(*cur_sigaction_fd, b"copy")?); - 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(*new_sigaction_fd), - )?; - } copy_str(*cur_pid_fd, *new_pid_fd, "name")?; // Copy existing files into new file table, but do not reuse the same file table (i.e. new diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index f1dbf58baa..24ff85f5a1 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Error, IntRegisters, Result, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; @@ -260,12 +260,7 @@ pub fn setup_sighandler(control: &Sigcontrol) { CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); } - let data = syscall::SetSighandlerData { - user_handler: sighandler_function(), - excp_handler: 0, // TODO - thread_control_addr: control as *const Sigcontrol as usize, - proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, - }; + let data = current_setsighandler_struct(); let fd = syscall::open( "thisproc:current/sighandler", @@ -280,3 +275,11 @@ pub struct RtSigarea { pub control: Sigcontrol, pub arch: crate::arch::SigArea, } +pub fn current_setsighandler_struct() -> SetSighandlerData { + SetSighandlerData { + user_handler: sighandler_function(), + excp_handler: 0, // TODO + thread_control_addr: core::ptr::addr_of!(unsafe { Tcb::current() }.unwrap().os_specific.control) as usize, + proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, + } +} From a2ab86d253cb2c0f095c757b2e029fa5bd2e7ab1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 21 Jun 2024 14:52:27 +0200 Subject: [PATCH 15/67] Implement signal selection in asm, for SA_ONSTACK. --- redox-rt/src/arch/x86_64.rs | 60 +++++++++++++++++++++++++++--------- redox-rt/src/signal.rs | 60 ++++++++++++++++++++++++++---------- src/platform/redox/signal.rs | 34 +++++++++++--------- 3 files changed, 108 insertions(+), 46 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index c1a11cd278..cc1fa64655 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -16,6 +16,7 @@ pub struct SigArea { altstack_top: usize, altstack_bottom: usize, tmp: usize, + pub onstack: u64, pub disable_signals_depth: u64, } @@ -128,18 +129,41 @@ asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" "] <= []); asmfunction!(__relibc_internal_sigentry: [" - // Get offset to TCB - mov rax, gs:[0] + // First, select signal, always pick first available bit + + // Read first signal word + mov rdx, fs:[{tcb_sc_off} + {sc_word}] + mov rcx, rdx + shr rcx, 32 + and edx, ecx + bsf edx, edx + jnz 2f + + // Read second signal word + mov rdx, fs:[{tcb_sc_off} + {sc_word} + 8] + mov rcx, rdx + shr rcx, 32 + and edx, ecx + bsf edx, edx + jnz 4f + add edx, 32 +2: + // By now we have selected a signal, stored in edx (6-bit). We now need to choose whether or + // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then + // skip the sigaltstack logic. + bt fs:[{tcb_sa_off} + {sa_onstack}], edx + jc 3f // If current RSP is above altstack region, switch to altstack - mov rdx, [rax + {tcb_sa_off} + {sa_altstack_top}] + mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}] cmp rdx, rsp cmova rsp, rdx // If current RSP is below altstack region, also switch to altstack - mov rdx, [rax + {tcb_sa_off} + {sa_altstack_bottom}] - cmp rdx, rax + mov rdx, fs:[{tcb_sa_off} + {sa_altstack_bottom}] + cmp rdx, rsp cmovbe rsp, rdx +3: // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent // to setting 'top' to usize::MAX and 'bottom' to 0. @@ -147,16 +171,16 @@ asmfunction!(__relibc_internal_sigentry: [" // Now that we have a stack, we can finally start initializing the signal stack! push 0 // SS - push [rax + {tcb_sc_off} + {sc_saved_rsp}] - push [rax + {tcb_sc_off} + {sc_saved_rflags}] + push fs:[{tcb_sc_off} + {sc_saved_rsp}] + push fs:[{tcb_sc_off} + {sc_saved_rflags}] push 0 // CS - push [rax + {tcb_sc_off} + {sc_saved_rip}] + push fs:[{tcb_sc_off} + {sc_saved_rip}] push rdi push rsi - push [rax + {tcb_sc_off} + {sc_saved_rdx}] + push fs:[{tcb_sc_off} + {sc_saved_rdx}] push rcx - push [rax + {tcb_sc_off} + {sc_saved_rax}] + push fs:[{tcb_sc_off} + {sc_saved_rax}] push r8 push r9 push r10 @@ -168,12 +192,14 @@ asmfunction!(__relibc_internal_sigentry: [" push r14 push r15 - sub rsp, 4096 + 32 + push rdx // selected signal + + sub rsp, 4096 + 24 cld mov rdi, rsp xor eax, eax - mov ecx, 4096 + 32 + mov ecx, 4096 + 24 rep stosb // TODO: self-modifying? @@ -191,7 +217,7 @@ asmfunction!(__relibc_internal_sigentry: [" mov edx, eax xrstor [rsp] - add rsp, 4096 + 32 + add rsp, 4096 + 24 2: pop r15 pop r14 @@ -209,11 +235,11 @@ asmfunction!(__relibc_internal_sigentry: [" pop rsi pop rdi - pop qword ptr gs:[{tcb_sa_off} + {sa_tmp}] + pop qword ptr fs:[{tcb_sa_off} + {sa_tmp}] add rsp, 8 popfq pop rsp - jmp qword ptr gs:[{tcb_sa_off} + {sa_tmp}] + jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp}] 3: fxsave64 [rsp] @@ -222,16 +248,20 @@ asmfunction!(__relibc_internal_sigentry: [" fxrstor64 [rsp] jmp 2b +4: + // Spurious signal "] <= [ inner = sym inner_c, sa_tmp = const offset_of!(SigArea, tmp), sa_altstack_top = const offset_of!(SigArea, altstack_top), sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), + sa_onstack = const offset_of!(SigArea, onstack), sc_saved_rax = const offset_of!(Sigcontrol, saved_scratch_a), sc_saved_rdx = const offset_of!(Sigcontrol, saved_scratch_b), sc_saved_rflags = const offset_of!(Sigcontrol, saved_flags), sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), sc_saved_rsp = const offset_of!(Sigcontrol, saved_sp), + sc_word = const offset_of!(Sigcontrol, word), tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), supports_xsave = sym SUPPORTS_XSAVE, diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 24ff85f5a1..e45cfa4c4c 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; @@ -104,16 +104,24 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 Ok(()) } -#[derive(Clone, Copy)] -pub enum Sigaction { +#[derive(Clone, Copy, Default)] +pub enum SigactionKind { + #[default] Default, + Ignore, Handled { handler: SignalHandler, - mask: u64, - flags: SigactionFlags, }, } + +#[derive(Clone, Copy, Default)] +pub struct Sigaction { + pub kind: SigactionKind, + pub mask: u64, + pub flags: SigactionFlags, +} + pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> { if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) { return Err(Error::new(EINVAL)); @@ -125,39 +133,59 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction let old_ignmask = IGNMASK.load(Ordering::Relaxed); if let Some(old) = old { + // TODO } let Some(new) = new else { return Ok(()); }; - match (usize::from(signal), new) { - (_, Sigaction::Ignore) | (SIGCHLD | SIGURG | SIGWINCH, Sigaction::Default) => { + let sig_group = usize::from(signal) / 32; + let sig_bit32 = 1 << ((signal - 1) % 32); + + match (usize::from(signal), new.kind) { + (_, SigactionKind::Ignore) | (SIGURG | SIGWINCH, SigactionKind::Default) => { IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); // mark the signal as masked - ctl.word[usize::from(signal) / 32].fetch_or(1 << ((signal - 1) % 32), Ordering::Relaxed); + ctl.word[sig_group].fetch_or(sig_bit32, Ordering::Relaxed); // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by // sigaction. // TODO: handle tmp_disable_signals } // TODO: Handle pending signals before these flags are set. - (SIGTSTP, Sigaction::Default) => { + (SIGTSTP, SigactionKind::Default) => { PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst); } - (SIGTTIN, Sigaction::Default) => { + (SIGTTIN, SigactionKind::Default) => { PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst); } - (SIGTTOU, Sigaction::Default) => { + (SIGTTOU, SigactionKind::Default) => { PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst); } + (SIGCHLD, SigactionKind::Default) => { + if new.flags.contains(SigactionFlags::NOCLDSTOP) { + PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst); + } else { + PROC_CONTROL_STRUCT.word[0].fetch_and(!SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst); + } + IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); - (_, Sigaction::Default) => (), - (_, Sigaction::Handled { .. }) => (), + // mark the signal as masked + ctl.word[sig_group].fetch_or(sig_bit32, Ordering::Relaxed); + } + + (_, SigactionKind::Default) => { + IGNMASK.store(old_ignmask & !sig_bit(signal.into()), Ordering::Relaxed); + + // TODO: update mask + //ctl.word[usize::from(signal)].fetch_or(); + }, + (_, SigactionKind::Handled { .. }) => (), } - todo!() + Ok(()) } fn current_sigctl() -> &'static Sigcontrol { @@ -192,7 +220,7 @@ impl Drop for TmpDisableSignalsGuard { bitflags::bitflags! { // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion. - #[derive(Clone, Copy)] + #[derive(Clone, Copy, Default)] pub struct SigactionFlags: u32 { const NOCLDSTOP = 1; const NOCLDWAIT = 2; @@ -226,7 +254,7 @@ struct TheDefault { ignmask: u64, } -static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction::Default; 64]); +static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction { flags: SigactionFlags::empty(), mask: 0, kind: SigactionKind::Default }; 64]); static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 625ac730c0..59d0390eda 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,5 +1,5 @@ use core::mem; -use redox_rt::signal::{Sigaction, SigactionFlags, SignalHandler}; +use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, SignalHandler}; use syscall::{self, Result}; use super::{ @@ -111,49 +111,53 @@ impl PalSignal for Sys { let new_action = c_act.map(|c_act| { let handler = c_act.sa_handler.map_or(0, |f| f as usize); - if handler == SIG_DFL { - Sigaction::Default + let kind = if handler == SIG_DFL { + SigactionKind::Default } else if handler == SIG_IGN { - Sigaction::Ignore + SigactionKind::Ignore } else { - Sigaction::Handled { + SigactionKind::Handled { handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 { SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) } } } else { SignalHandler { handler: c_act.sa_handler } }, - mask: c_act.sa_mask, - flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32), } + }; + + Sigaction { + kind, + mask: c_act.sa_mask, + flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32), } }); - let mut old_action = c_oact.as_ref().map(|_| Sigaction::Default); + let mut old_action = c_oact.as_ref().map(|_| Sigaction::default()); redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?; if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) { - *c_oact = match old_action { - Sigaction::Ignore => sigaction { + *c_oact = match old_action.kind { + SigactionKind::Ignore => sigaction { sa_handler: unsafe { core::mem::transmute(SIG_IGN) }, sa_flags: 0, sa_restorer: None, sa_mask: 0, }, - Sigaction::Default => sigaction { + SigactionKind::Default => sigaction { sa_handler: unsafe { core::mem::transmute(SIG_DFL) }, sa_flags: 0, sa_restorer: None, sa_mask: 0, }, - Sigaction::Handled { handler, mask, flags } => sigaction { - sa_handler: if flags.contains(SigactionFlags::SIGINFO) { + SigactionKind::Handled { handler } => sigaction { + sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) { unsafe { core::mem::transmute(handler.sigaction) } } else { unsafe { handler.handler } }, sa_restorer: None, - sa_flags: flags.bits().into(), - sa_mask: mask, + sa_flags: old_action.flags.bits().into(), + sa_mask: old_action.mask, }, }; } From 7fcf5a1acaeaa88a775d64df41557f525eaf768e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 21 Jun 2024 15:01:29 +0200 Subject: [PATCH 16/67] Ignore special bits when selecting signal. --- redox-rt/src/arch/x86_64.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index cc1fa64655..cade85a186 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -3,6 +3,7 @@ use core::sync::atomic::AtomicU8; use syscall::data::Sigcontrol; use syscall::error::*; +use syscall::flag::*; use crate::proc::{fork_inner, FdGuard}; use crate::signal::{inner_c, RtSigarea}; @@ -136,6 +137,7 @@ asmfunction!(__relibc_internal_sigentry: [" mov rcx, rdx shr rcx, 32 and edx, ecx + and edx, {SIGW0_PENDING_MASK} bsf edx, edx jnz 2f @@ -144,6 +146,7 @@ asmfunction!(__relibc_internal_sigentry: [" mov rcx, rdx shr rcx, 32 and edx, ecx + and edx, {SIGW1_PENDING_MASK} bsf edx, edx jnz 4f add edx, 32 @@ -265,6 +268,10 @@ asmfunction!(__relibc_internal_sigentry: [" tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), supports_xsave = sym SUPPORTS_XSAVE, + SIGW0_PENDING_MASK = const !( + SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2 + ), + SIGW1_PENDING_MASK = const !0, ]); static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(0); // FIXME From 42c24dd75520218fffe424a9f8196f3c43599297 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 10:42:52 +0200 Subject: [PATCH 17/67] Successfully run more userspace. --- redox-rt/src/arch/x86_64.rs | 8 +++++--- redox-rt/src/signal.rs | 5 +++-- redox-rt/src/sync.rs | 6 +++++- src/ld_so/tcb.rs | 9 ++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index cade85a186..6c12a9642f 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -78,7 +78,11 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: [" mov rdi, rsp call __relibc_internal_fork_impl - jmp 2f + + add rsp, 80 + + pop rbp + ret "] <= []); asmfunction!(__relibc_internal_fork_ret: [" @@ -91,8 +95,6 @@ asmfunction!(__relibc_internal_fork_ret: [" xor rax, rax - .p2align 4 -2: add rsp, 32 pop r15 pop r14 diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index e45cfa4c4c..03da284d26 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -129,16 +129,17 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction let _sigguard = tmp_disable_signals(); let ctl = current_sigctl(); - let guard = SIGACTIONS.lock(); + let mut guard = SIGACTIONS.lock(); let old_ignmask = IGNMASK.load(Ordering::Relaxed); if let Some(old) = old { - // TODO + *old = guard[usize::from(signal)]; } let Some(new) = new else { return Ok(()); }; + guard[usize::from(signal)] = *new; let sig_group = usize::from(signal) / 32; let sig_bit32 = 1 << ((signal - 1) % 32); diff --git a/redox-rt/src/sync.rs b/redox-rt/src/sync.rs index 7130778429..172bd37b1f 100644 --- a/redox-rt/src/sync.rs +++ b/redox-rt/src/sync.rs @@ -2,7 +2,7 @@ use core::cell::UnsafeCell; use core::ops::{Deref, DerefMut}; -use core::sync::atomic::AtomicU32; +use core::sync::atomic::{AtomicU32, Ordering}; pub struct Mutex { pub lockword: AtomicU32, @@ -24,6 +24,9 @@ impl Mutex { } } pub fn lock(&self) -> MutexGuard<'_, T> { + while self.lockword.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed).is_err() { + core::hint::spin_loop(); + } MutexGuard { lock: self } } } @@ -44,5 +47,6 @@ impl DerefMut for MutexGuard<'_, T> { } impl Drop for MutexGuard<'_, T> { fn drop(&mut self) { + self.lock.lockword.store(UNLOCKED, Ordering::Release); } } diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index ae1b9eaf4c..a7c0457b25 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -56,6 +56,13 @@ pub struct Tcb { pub pthread: Pthread, } +#[cfg(target_os = "redox")] +const _: () = { + if mem::size_of::() > syscall::PAGE_SIZE { + panic!("too large TCB!"); + } +}; + impl Tcb { /// Create a new TCB pub unsafe fn new(size: usize) -> Result<&'static mut Self> { @@ -223,7 +230,7 @@ impl Tcb { syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end); } - #[cfg(all(target_os = "redox"))] + #[cfg(target_os = "redox")] unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) { redox_rt::tcb_activate(tls_end, tls_len) } From 20284eb2b276a8d5327bc4bcc46ab0064a896253 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 11:15:16 +0200 Subject: [PATCH 18/67] Fix rlct_clone. --- redox-rt/src/arch/x86_64.rs | 2 +- redox-rt/src/thread.rs | 36 ++++++------------------------------ 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 6c12a9642f..71ca1ce271 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -106,7 +106,7 @@ asmfunction!(__relibc_internal_fork_ret: [" pop rbp ret "] <= []); -asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" +asmfunction!(__relibc_internal_rlct_clone_ret: [" # Load registers pop rax pop rdi diff --git a/redox-rt/src/thread.rs b/redox-rt/src/thread.rs index 60201c38bd..9b348a62d7 100644 --- a/redox-rt/src/thread.rs +++ b/redox-rt/src/thread.rs @@ -19,13 +19,13 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { let buf = create_set_addr_space_buf( *cur_addr_space_fd, - __relibc_internal_rlct_clone_ret() as usize, + __relibc_internal_rlct_clone_ret as usize, stack as usize, ); let _ = syscall::write(*new_addr_space_sel_fd, &buf)?; } - // Inherit file table + // Inherit reference to 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")?); @@ -36,34 +36,10 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { )?; } - // Inherit 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), - )?; - } - // Inherit sighandler, but not the sigaltstack. - { - let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); - let data = SetSighandlerData { - user_handler: sighandler_function(), - excp_handler: 0, - thread_control_addr: 0, // TODO - proc_control_addr: 0, // TODO - }; - let _ = syscall::write(*new_sighandler_fd, &data)?; - } - - // Sigprocmask starts as "block all", and is initialized when the thread has actually returned - // from clone_ret. - - // TODO: Should some of these registers be inherited? - //copy_env_regs(*cur_pid_fd, *new_pid_fd)?; + // Since the signal handler is not yet initialized, signals specifically targeting the thread + // (relibc is only required to implement thread-specific signals that already originate from + // the same process) will be discarded. Process-specific signals will ignore this new thread, + // until it has initialized its own signal handler. // Unblock context. let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?); From 8f66730d3726f12a158cc10f623a76e7d60fd61d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 11:45:00 +0200 Subject: [PATCH 19/67] Set child sighandler *after* cloning address space. --- redox-rt/src/proc.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 9b7dbfc385..218bf18da3 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -713,12 +713,6 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); (new_pid_fd, new_pid) = new_context()?; - // Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later). - { - let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); - let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?; - } - copy_str(*cur_pid_fd, *new_pid_fd, "name")?; // Copy existing files into new file table, but do not reuse the same file table (i.e. new @@ -801,6 +795,15 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { } } + // Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later). + // + // Do this after the address space is cloned, since the kernel will get a shared + // reference to the TCB and whatever pages stores the signal proc control struct. + { + let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?); + let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?; + } + let buf = create_set_addr_space_buf( *new_addr_space_fd, __relibc_internal_fork_ret as usize, From c217745524519c0379b11ed3da852e4995a736a7 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 13:22:38 +0200 Subject: [PATCH 20/67] Mark sig{add,del}set unsafe, rather than unsound. --- src/header/signal/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index 9c924c1d21..3645d812e0 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -111,7 +111,7 @@ pub unsafe extern "C" fn sigaction( } #[no_mangle] -pub extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int { +pub unsafe extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int { if signo <= 0 || signo as usize > NSIG { platform::ERRNO.set(errno::EINVAL); return -1; @@ -138,7 +138,7 @@ pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) - } #[no_mangle] -pub extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int { +pub unsafe extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int { if signo <= 0 || signo as usize > NSIG { platform::ERRNO.set(errno::EINVAL); return -1; From b6eb7dcf0f2bda566102a2c19dc4ce03052f6427 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 13:24:05 +0200 Subject: [PATCH 21/67] Impl From for syscall::Error. --- src/pthread/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 2b4ad725f5..a5210a2a0d 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -92,6 +92,12 @@ impl From for Errno { Errno(value.errno) } } +#[cfg(target_os = "redox")] +impl From for syscall::Error { + fn from(value: Errno) -> Self { + syscall::Error::new(value.0) + } +} pub trait ResultExt { fn or_minus_one_errno(self) -> T; From a265c8b7a012c497a955721d95a00aa4ab68f844 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 13:24:30 +0200 Subject: [PATCH 22/67] Reimplement libredox sig{procmask,action}. --- src/platform/redox/libredox.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 9ceed89a71..a1789e24ce 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -4,11 +4,13 @@ use syscall::{Error, Result, WaitFlags, EMFILE}; use crate::{ header::{ - errno::EINVAL, signal::{sigaction, SIG_SETMASK}, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec, + errno::EINVAL, signal::{sigaction, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec, }, - platform::types::*, + platform::{types::*, PalSignal}, }; +use super::Sys; + pub type RawResult = usize; pub fn open(path: &str, oflag: c_int, mode: mode_t) -> Result { @@ -249,7 +251,7 @@ pub unsafe extern "C" fn redox_sigaction_v1( new: *const sigaction, old: *mut sigaction, ) -> RawResult { - todo!() + Error::mux(Sys::sigaction(signal as c_int, new.as_ref(), old.as_mut()).map(|()| 0).map_err(Into::into)) } #[no_mangle] @@ -258,7 +260,7 @@ pub unsafe extern "C" fn redox_sigprocmask_v1( new: *const u64, old: *mut u64, ) -> RawResult { - todo!() + Error::mux(Sys::sigprocmask(how as c_int, new.as_ref(), old.as_mut()).map(|()| 0).map_err(Into::into)) } #[no_mangle] pub unsafe extern "C" fn redox_mmap_v1( From a1e1a159aeee3f38669977f2432ebab6540e7b5f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 17:01:50 +0200 Subject: [PATCH 23/67] Initialize altstack properly. --- redox-rt/src/arch/x86_64.rs | 6 +++--- redox-rt/src/signal.rs | 30 +++++++++++++++++++++--------- src/start.rs | 2 +- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 71ca1ce271..bd823c9811 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -14,9 +14,9 @@ pub(crate) const STACK_SIZE: usize = 1024 * 1024; #[derive(Debug, Default)] pub struct SigArea { - altstack_top: usize, - altstack_bottom: usize, - tmp: usize, + pub altstack_top: usize, + pub altstack_bottom: usize, + pub tmp: usize, pub onstack: u64, pub disable_signals_depth: u64, } diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 03da284d26..d90c2c89cb 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,4 +1,4 @@ -use core::cell::Cell; +use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; @@ -43,6 +43,8 @@ pub struct SigStack { #[inline(always)] unsafe fn inner(stack: &mut SigStack) { + let _ = syscall::write(1, b"INNER SIGNAL HANDLER\n"); + loop {} let handler: extern "C" fn(c_int) = core::mem::transmute(stack.sa_handler); handler(stack.sig_num as c_int) } @@ -197,10 +199,12 @@ pub struct TmpDisableSignalsGuard { _inner: () } pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { unsafe { - let ctl = current_sigctl().control_flags.get(); - ctl.write_volatile(ctl.read_volatile() | syscall::flag::INHIBIT_DELIVERY); + let ctl = ¤t_sigctl().control_flags; + ctl.store(ctl.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + core::sync::atomic::compiler_fence(Ordering::Acquire); + // TODO: fence? - Tcb::current().unwrap().os_specific.arch.disable_signals_depth += 1; + (*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth += 1; } TmpDisableSignalsGuard { _inner: () } @@ -208,12 +212,13 @@ pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { impl Drop for TmpDisableSignalsGuard { fn drop(&mut self) { unsafe { - let depth = &mut Tcb::current().unwrap().os_specific.arch.disable_signals_depth; + let depth = &mut (*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth; *depth -= 1; if *depth == 0 { - let ctl = current_sigctl().control_flags.get(); - ctl.write_volatile(ctl.read_volatile() & !syscall::flag::INHIBIT_DELIVERY); + let ctl = ¤t_sigctl().control_flags; + ctl.store(ctl.load(Ordering::Relaxed) & !syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + core::sync::atomic::compiler_fence(Ordering::Acquire); } } } @@ -278,13 +283,20 @@ const fn sig_bit(sig: usize) -> u64 { 1 << (sig - 1) } -pub fn setup_sighandler(control: &Sigcontrol) { +pub fn setup_sighandler(area: &RtSigarea) { { let mut sigactions = SIGACTIONS.lock(); } + let arch = unsafe { &mut *area.arch.get() }; #[cfg(target_arch = "x86_64")] { + // The asm decides whether to use the altstack, based on whether the saved stack pointer + // was already on that stack. Thus, setting the altstack to the entire address space, is + // equivalent to not using any altstack at all (the default). + arch.altstack_top = usize::MAX; + arch.altstack_bottom = 0; + let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); } @@ -302,7 +314,7 @@ pub fn setup_sighandler(control: &Sigcontrol) { #[derive(Debug, Default)] pub struct RtSigarea { pub control: Sigcontrol, - pub arch: crate::arch::SigArea, + pub arch: UnsafeCell, } pub fn current_setsighandler_struct() -> SetSighandlerData { SetSighandlerData { diff --git a/src/start.rs b/src/start.rs index 9bf2f8da5b..f17bd48723 100644 --- a/src/start.rs +++ b/src/start.rs @@ -158,7 +158,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); } #[cfg(target_os = "redox")] - redox_rt::signal::setup_sighandler(&tcb.os_specific.control); + redox_rt::signal::setup_sighandler(&tcb.os_specific); } // Set up argc and argv From d6588668e22d56f5aac536fa3fc5f05f64a371d1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 17:14:26 +0200 Subject: [PATCH 24/67] Fix pre-Rust part of trampoline!. --- redox-rt/src/arch/x86_64.rs | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index bd823c9811..54a57ae144 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -135,30 +135,37 @@ asmfunction!(__relibc_internal_sigentry: [" // First, select signal, always pick first available bit // Read first signal word - mov rdx, fs:[{tcb_sc_off} + {sc_word}] - mov rcx, rdx + mov rax, fs:[{tcb_sc_off} + {sc_word}] + mov rcx, rax shr rcx, 32 - and edx, ecx - and edx, {SIGW0_PENDING_MASK} - bsf edx, edx + and eax, ecx + and eax, {SIGW0_PENDING_MASK} + bsf eax, eax jnz 2f // Read second signal word - mov rdx, fs:[{tcb_sc_off} + {sc_word} + 8] - mov rcx, rdx + mov rax, fs:[{tcb_sc_off} + {sc_word} + 8] + mov rcx, rax shr rcx, 32 - and edx, ecx - and edx, {SIGW1_PENDING_MASK} - bsf edx, edx + and eax, ecx + and eax, {SIGW1_PENDING_MASK} + bsf eax, eax jnz 4f - add edx, 32 + add eax, 32 2: - // By now we have selected a signal, stored in edx (6-bit). We now need to choose whether or + // By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then // skip the sigaltstack logic. bt fs:[{tcb_sa_off} + {sa_onstack}], edx jc 3f + // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent + // to setting 'top' to usize::MAX and 'bottom' to 0. + + sub rsp, {REDZONE_SIZE} + and rsp, -{STACK_ALIGN} + jmp 4f +3: // If current RSP is above altstack region, switch to altstack mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}] cmp rdx, rsp @@ -168,11 +175,9 @@ asmfunction!(__relibc_internal_sigentry: [" mov rdx, fs:[{tcb_sa_off} + {sa_altstack_bottom}] cmp rdx, rsp cmovbe rsp, rdx -3: - // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent - // to setting 'top' to usize::MAX and 'bottom' to 0. - // + .p2align 4 +4: // Now that we have a stack, we can finally start initializing the signal stack! push 0 // SS @@ -274,6 +279,8 @@ asmfunction!(__relibc_internal_sigentry: [" SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2 ), SIGW1_PENDING_MASK = const !0, + REDZONE_SIZE = const 128, + STACK_ALIGN = const 64, // if xsave is used ]); -static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(0); // FIXME +static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(1); // FIXME From 98a2a566d91e1f6c3431b0e180c8208a6d0e9e79 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 23 Jun 2024 23:30:34 +0200 Subject: [PATCH 25/67] Almost succeed at repeatedly accepting signals. --- redox-rt/src/arch/x86_64.rs | 26 +++++++++++++++----------- redox-rt/src/proc.rs | 14 ++++++++------ redox-rt/src/signal.rs | 19 ++++++++++++------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 54a57ae144..7349809f96 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -150,13 +150,13 @@ asmfunction!(__relibc_internal_sigentry: [" and eax, ecx and eax, {SIGW1_PENDING_MASK} bsf eax, eax - jnz 4f + jnz 7f add eax, 32 2: // By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then // skip the sigaltstack logic. - bt fs:[{tcb_sa_off} + {sa_onstack}], edx + bt fs:[{tcb_sa_off} + {sa_onstack}], eax jc 3f // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent @@ -180,10 +180,10 @@ asmfunction!(__relibc_internal_sigentry: [" 4: // Now that we have a stack, we can finally start initializing the signal stack! - push 0 // SS + push 0x23 // SS push fs:[{tcb_sc_off} + {sc_saved_rsp}] push fs:[{tcb_sc_off} + {sc_saved_rflags}] - push 0 // CS + push 0x2b // CS push fs:[{tcb_sc_off} + {sc_saved_rip}] push rdi @@ -202,7 +202,7 @@ asmfunction!(__relibc_internal_sigentry: [" push r14 push r15 - push rdx // selected signal + push rax // selected signal sub rsp, 4096 + 24 @@ -214,7 +214,7 @@ asmfunction!(__relibc_internal_sigentry: [" // TODO: self-modifying? cmp byte ptr [rip + {supports_xsave}], 0 - je 3f + je 6f mov eax, 0xffffffff mov edx, eax @@ -227,8 +227,8 @@ asmfunction!(__relibc_internal_sigentry: [" mov edx, eax xrstor [rsp] - add rsp, 4096 + 24 -2: +5: + add rsp, 4096 + 32 pop r15 pop r14 pop r13 @@ -245,20 +245,24 @@ asmfunction!(__relibc_internal_sigentry: [" pop rsi pop rdi + iretq + /* pop qword ptr fs:[{tcb_sa_off} + {sa_tmp}] add rsp, 8 popfq pop rsp jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp}] -3: + */ +6: fxsave64 [rsp] mov rdi, rsp call {inner} fxrstor64 [rsp] - jmp 2b -4: + jmp 5b +7: + ud2 // Spurious signal "] <= [ inner = sym inner_c, diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 218bf18da3..e4564bb700 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -795,6 +795,14 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { } } + let buf = create_set_addr_space_buf( + *new_addr_space_fd, + __relibc_internal_fork_ret as usize, + initial_rsp as usize, + ); + let _ = syscall::write(*new_addr_space_sel_fd, &buf)?; + } + { // Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later). // // Do this after the address space is cloned, since the kernel will get a shared @@ -804,12 +812,6 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?; } - let buf = create_set_addr_space_buf( - *new_addr_space_fd, - __relibc_internal_fork_ret as usize, - initial_rsp as usize, - ); - let _ = syscall::write(*new_addr_space_sel_fd, &buf)?; } copy_env_regs(*cur_pid_fd, *new_pid_fd)?; } diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index d90c2c89cb..2ec1e76c09 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; @@ -28,25 +28,30 @@ pub fn sighandler_function() -> usize { #[repr(C)] pub struct SigStack { - sa_handler: usize, - sig_num: usize, - #[cfg(target_arch = "x86_64")] fx: [u8; 4096], #[cfg(target_arch = "x86")] fx: [u8; 512], - _pad: [usize; 4], // pad to 192 = 3 * 64 bytes + _pad: [usize; 3], // pad to 192 = 3 * 64 = 168 + 24 bytes + sig_num: usize, regs: IntRegisters, // 160 bytes currently } #[inline(always)] unsafe fn inner(stack: &mut SigStack) { + // TODO: Set procmask based on SA_NODEFER, SA_RESETHAND, and sa_mask. + + // Re-enable signals again. + let control_flags = &Tcb::current().unwrap().os_specific.control.control_flags; + control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); + core::sync::atomic::compiler_fence(Ordering::Acquire); + let _ = syscall::write(1, b"INNER SIGNAL HANDLER\n"); - loop {} + /*loop {} let handler: extern "C" fn(c_int) = core::mem::transmute(stack.sa_handler); - handler(stack.sig_num as c_int) + handler(stack.sig_num as c_int)*/ } #[cfg(not(target_arch = "x86"))] pub(crate) unsafe extern "C" fn inner_c(stack: usize) { From 3db425fef6e527394b0ffec94320fb0835df11a1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 10:29:51 +0200 Subject: [PATCH 26/67] Correctly find signal number and check action. --- redox-rt/src/arch/x86_64.rs | 14 ++++++++------ redox-rt/src/signal.rs | 25 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 7349809f96..2b54b5c567 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -136,18 +136,20 @@ asmfunction!(__relibc_internal_sigentry: [" // Read first signal word mov rax, fs:[{tcb_sc_off} + {sc_word}] - mov rcx, rax - shr rcx, 32 - and eax, ecx + mov rdx, rax + shr rdx, 32 + not edx + and eax, edx and eax, {SIGW0_PENDING_MASK} bsf eax, eax jnz 2f // Read second signal word mov rax, fs:[{tcb_sc_off} + {sc_word} + 8] - mov rcx, rax - shr rcx, 32 - and eax, ecx + mov rdx, rax + shr rdx, 32 + not edx + and eax, edx and eax, {SIGW1_PENDING_MASK} bsf eax, eax jnz 7f diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 2ec1e76c09..368620ce7b 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -43,15 +43,30 @@ pub struct SigStack { unsafe fn inner(stack: &mut SigStack) { // TODO: Set procmask based on SA_NODEFER, SA_RESETHAND, and sa_mask. + // asm counts from 0 + stack.sig_num += 1; + + let sigaction = SIGACTIONS.lock()[stack.sig_num]; + + let handler = match sigaction.kind { + SigactionKind::Ignore => unreachable!(), + SigactionKind::Default => { + syscall::exit(stack.sig_num << 8); + unreachable!(); + } + SigactionKind::Handled { handler } => handler, + }; + // Re-enable signals again. let control_flags = &Tcb::current().unwrap().os_specific.control.control_flags; control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); core::sync::atomic::compiler_fence(Ordering::Acquire); - let _ = syscall::write(1, b"INNER SIGNAL HANDLER\n"); - /*loop {} - let handler: extern "C" fn(c_int) = core::mem::transmute(stack.sa_handler); - handler(stack.sig_num as c_int)*/ + if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction { + sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut()); + } else if let Some(handler) = handler.handler { + handler(stack.sig_num as c_int); + } } #[cfg(not(target_arch = "x86"))] pub(crate) unsafe extern "C" fn inner_c(stack: usize) { @@ -265,7 +280,9 @@ struct TheDefault { ignmask: u64, } +// indexed directly by signal number static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction { flags: SigactionFlags::empty(), mask: 0, kind: SigactionKind::Default }; 64]); + static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { From 0ea2b5d45f177932bac25ee3cb3bc976cdf7893a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 11:00:28 +0200 Subject: [PATCH 27/67] Fix compilation on Linux. --- src/ld_so/tcb.rs | 1 - src/platform/linux/signal.rs | 27 +++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index a7c0457b25..048c52ae8b 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -1,6 +1,5 @@ use alloc::vec::Vec; use generic_rt::GenericTcb; -use syscall::Sigcontrol; use core::{arch::asm, cell::UnsafeCell, mem, ops::{Deref, DerefMut}, ptr, slice, sync::atomic::AtomicBool}; use goblin::error::{Error, Result}; diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 266c231b98..86b4efb14c 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -2,13 +2,14 @@ use core::mem; use super::{ super::{types::*, PalSignal}, - e, Sys, + e, e_raw, Sys, }; use crate::header::{ signal::{sigaction, siginfo_t, sigset_t, stack_t, NSIG}, sys_time::itimerval, time::timespec, }; +use crate::pthread::Errno; impl PalSignal for Sys { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int { @@ -36,8 +37,8 @@ impl PalSignal for Sys { e(syscall!(SETITIMER, which, new, old)) as c_int } - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int { - e(unsafe { + fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> { + e_raw(unsafe { syscall!( RT_SIGACTION, sig, @@ -45,7 +46,7 @@ impl PalSignal for Sys { oact.map_or_else(core::ptr::null_mut, |x| x as *mut _), mem::size_of::() ) - }) as c_int + }).map(|_| ()) } unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { @@ -56,14 +57,16 @@ impl PalSignal for Sys { e(syscall!(RT_SIGPENDING, set, NSIG / 8)) as c_int } - unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int { - e(syscall!( - RT_SIGPROCMASK, - how, - set, - oset, - mem::size_of::() - )) as c_int + fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno> { + e_raw(unsafe { + syscall!( + RT_SIGPROCMASK, + how, + set.map_or_else(core::ptr::null, |x| x as *const _), + oset.map_or_else(core::ptr::null_mut, |x| x as *mut _), + mem::size_of::() + ) + }).map(|_| ()) } unsafe fn sigsuspend(set: *const sigset_t) -> c_int { From f37bb3cb166722375642766a690d58b9b9aeaba5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 11:59:39 +0200 Subject: [PATCH 28/67] Fix sigaction test on Linux, and rustfmt. --- src/header/signal/mod.rs | 18 +++++++-------- src/header/signal/redox.rs | 33 --------------------------- src/ld_so/tcb.rs | 9 +++++++- src/platform/linux/signal.rs | 41 +++++++++++++++++++++++++--------- src/platform/pal/signal.rs | 25 +++++++++++++++------ src/platform/redox/libredox.rs | 18 ++++++++++++--- src/platform/redox/signal.rs | 28 ++++++++++++++++++----- 7 files changed, 102 insertions(+), 70 deletions(-) diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index 3645d812e0..c015f3f9cb 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -107,7 +107,9 @@ pub unsafe extern "C" fn sigaction( act: *const sigaction, oact: *mut sigaction, ) -> c_int { - Sys::sigaction(sig, act.as_ref(), oact.as_mut()).map(|()| 0).or_minus_one_errno() + Sys::sigaction(sig, act.as_ref(), oact.as_mut()) + .map(|()| 0) + .or_minus_one_errno() } #[no_mangle] @@ -216,11 +218,6 @@ pub unsafe extern "C" fn sigismember(set: *const sigset_t, signo: c_int) -> c_in 0 } -extern "C" { - // Defined in assembly inside platform/x/mod.rs - fn __restore_rt(); -} - #[no_mangle] pub extern "C" fn signal( sig: c_int, @@ -228,8 +225,8 @@ pub extern "C" fn signal( ) -> Option { let sa = sigaction { sa_handler: func, - sa_flags: SA_RESTART as c_ulong, - sa_restorer: Some(__restore_rt), + sa_flags: SA_RESTART as _, + sa_restorer: None, // set by platform if applicable sa_mask: sigset_t::default(), }; let mut old_sa = mem::MaybeUninit::uninit(); @@ -279,7 +276,8 @@ pub unsafe extern "C" fn sigprocmask( } Ok(0) - })().or_minus_one_errno() + })() + .or_minus_one_errno() } #[no_mangle] @@ -318,7 +316,7 @@ pub unsafe extern "C" fn sigset( let mut sa = sigaction { sa_handler: func, sa_flags: 0 as c_ulong, - sa_restorer: Some(__restore_rt), + sa_restorer: None, // set by platform if applicable sa_mask: sigset_t::default(), }; sigemptyset(&mut sa.sa_mask); diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs index f21c168e47..8e878dda0a 100644 --- a/src/header/signal/redox.rs +++ b/src/header/signal/redox.rs @@ -1,38 +1,5 @@ use core::arch::global_asm; -// x8 is register, 119 is SIGRETURN -#[cfg(target_arch = "aarch64")] -global_asm!( - " - .global __restore_rt - __restore_rt: - mov x8, #119 - svc 0 -" -); -// Needs to be defined in assembly because it can't have a function prologue -// eax is register, 119 is SIGRETURN -#[cfg(target_arch = "x86")] -global_asm!( - " - .global __restore_rt - __restore_rt: - mov eax, 119 - int 0x80 -" -); -// Needs to be defined in assembly because it can't have a function prologue -// rax is register, 119 is SIGRETURN -#[cfg(target_arch = "x86_64")] -global_asm!( - " - .global __restore_rt - __restore_rt: - mov rax, 119 - syscall -" -); - pub const SIGHUP: usize = 1; pub const SIGINT: usize = 2; pub const SIGQUIT: usize = 3; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 048c52ae8b..efee9ce9ab 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -1,6 +1,13 @@ use alloc::vec::Vec; +use core::{ + arch::asm, + cell::UnsafeCell, + mem, + ops::{Deref, DerefMut}, + ptr, slice, + sync::atomic::AtomicBool, +}; use generic_rt::GenericTcb; -use core::{arch::asm, cell::UnsafeCell, mem, ops::{Deref, DerefMut}, ptr, slice, sync::atomic::AtomicBool}; use goblin::error::{Error, Result}; use super::ExpectTlsFree; diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 86b4efb14c..0fbc8493e9 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -4,12 +4,14 @@ use super::{ super::{types::*, PalSignal}, e, e_raw, Sys, }; -use crate::header::{ - signal::{sigaction, siginfo_t, sigset_t, stack_t, NSIG}, - sys_time::itimerval, - time::timespec, +use crate::{ + header::{ + signal::{sigaction, siginfo_t, sigset_t, stack_t, NSIG, SA_RESTORER}, + sys_time::itimerval, + time::timespec, + }, + pthread::Errno, }; -use crate::pthread::Errno; impl PalSignal for Sys { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int { @@ -37,16 +39,30 @@ impl PalSignal for Sys { e(syscall!(SETITIMER, which, new, old)) as c_int } - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> { + fn sigaction( + sig: c_int, + act: Option<&sigaction>, + oact: Option<&mut sigaction>, + ) -> Result<(), Errno> { + extern "C" { + fn __restore_rt(); + } + let act = act.map(|act| { + let mut act_clone = act.clone(); + act_clone.sa_flags |= SA_RESTORER as c_ulong; + act_clone.sa_restorer = Some(__restore_rt); + act_clone + }); e_raw(unsafe { syscall!( RT_SIGACTION, sig, - act.map_or_else(core::ptr::null, |x| x as *const _), + act.as_ref().map_or_else(core::ptr::null, |x| x as *const _), oact.map_or_else(core::ptr::null_mut, |x| x as *mut _), mem::size_of::() ) - }).map(|_| ()) + }) + .map(|_| ()) } unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { @@ -57,7 +73,11 @@ impl PalSignal for Sys { e(syscall!(RT_SIGPENDING, set, NSIG / 8)) as c_int } - fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno> { + fn sigprocmask( + how: c_int, + set: Option<&sigset_t>, + oset: Option<&mut sigset_t>, + ) -> Result<(), Errno> { e_raw(unsafe { syscall!( RT_SIGPROCMASK, @@ -66,7 +86,8 @@ impl PalSignal for Sys { oset.map_or_else(core::ptr::null_mut, |x| x as *mut _), mem::size_of::() ) - }).map(|_| ()) + }) + .map(|_| ()) } unsafe fn sigsuspend(set: *const sigset_t) -> c_int { diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index eeb5031a76..d85c35d955 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -1,9 +1,12 @@ use super::super::{types::*, Pal}; -use crate::{header::{ - signal::{sigaction, siginfo_t, sigset_t, stack_t}, - sys_time::itimerval, - time::timespec, -}, pthread::Errno}; +use crate::{ + header::{ + signal::{sigaction, siginfo_t, sigset_t, stack_t}, + sys_time::itimerval, + time::timespec, + }, + pthread::Errno, +}; pub trait PalSignal: Pal { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int; @@ -16,13 +19,21 @@ pub trait PalSignal: Pal { unsafe fn setitimer(which: c_int, new: *const itimerval, old: *mut itimerval) -> c_int; - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno>; + fn sigaction( + sig: c_int, + act: Option<&sigaction>, + oact: Option<&mut sigaction>, + ) -> Result<(), Errno>; unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int; unsafe fn sigpending(set: *mut sigset_t) -> c_int; - fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno>; + fn sigprocmask( + how: c_int, + set: Option<&sigset_t>, + oset: Option<&mut sigset_t>, + ) -> Result<(), Errno>; unsafe fn sigsuspend(set: *const sigset_t) -> c_int; diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index a1789e24ce..821efb0bb0 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -4,7 +4,11 @@ use syscall::{Error, Result, WaitFlags, EMFILE}; use crate::{ header::{ - errno::EINVAL, signal::{sigaction, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec, + errno::EINVAL, + signal::{sigaction, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, + sys_stat::UTIME_NOW, + sys_uio::iovec, + time::timespec, }, platform::{types::*, PalSignal}, }; @@ -251,7 +255,11 @@ pub unsafe extern "C" fn redox_sigaction_v1( new: *const sigaction, old: *mut sigaction, ) -> RawResult { - Error::mux(Sys::sigaction(signal as c_int, new.as_ref(), old.as_mut()).map(|()| 0).map_err(Into::into)) + Error::mux( + Sys::sigaction(signal as c_int, new.as_ref(), old.as_mut()) + .map(|()| 0) + .map_err(Into::into), + ) } #[no_mangle] @@ -260,7 +268,11 @@ pub unsafe extern "C" fn redox_sigprocmask_v1( new: *const u64, old: *mut u64, ) -> RawResult { - Error::mux(Sys::sigprocmask(how as c_int, new.as_ref(), old.as_mut()).map(|()| 0).map_err(Into::into)) + Error::mux( + Sys::sigprocmask(how as c_int, new.as_ref(), old.as_mut()) + .map(|()| 0) + .map_err(Into::into), + ) } #[no_mangle] pub unsafe extern "C" fn redox_mmap_v1( diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 59d0390eda..50f8f48a24 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -9,11 +9,15 @@ use super::{ use crate::{ header::{ errno::{EINVAL, ENOSYS}, - signal::{sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK}, + signal::{ + sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, + SIG_SETMASK, SIG_UNBLOCK, + }, sys_time::{itimerval, ITIMER_REAL}, time::timespec, }, - platform::ERRNO, pthread::Errno, + platform::ERRNO, + pthread::Errno, }; impl PalSignal for Sys { @@ -105,7 +109,11 @@ impl PalSignal for Sys { 0 } - fn sigaction(sig: c_int, c_act: Option<&sigaction>, c_oact: Option<&mut sigaction>) -> Result<(), Errno> { + fn sigaction( + sig: c_int, + c_act: Option<&sigaction>, + c_oact: Option<&mut sigaction>, + ) -> Result<(), Errno> { let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?; let new_action = c_act.map(|c_act| { @@ -118,9 +126,13 @@ impl PalSignal for Sys { } else { SigactionKind::Handled { handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 { - SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) } } + SignalHandler { + sigaction: unsafe { core::mem::transmute(c_act.sa_handler) }, + } } else { - SignalHandler { handler: c_act.sa_handler } + SignalHandler { + handler: c_act.sa_handler, + } }, } }; @@ -173,7 +185,11 @@ impl PalSignal for Sys { -1 } - fn sigprocmask(how: c_int, set: Option<&sigset_t>, oset: Option<&mut sigset_t>) -> Result<(), Errno> { + fn sigprocmask( + how: c_int, + set: Option<&sigset_t>, + oset: Option<&mut sigset_t>, + ) -> Result<(), Errno> { Ok(match how { SIG_SETMASK => redox_rt::signal::set_sigmask(set.copied(), oset)?, SIG_BLOCK => redox_rt::signal::or_sigmask(set.copied(), oset)?, From 18b5c73b618f43680b9ca6b366525cdbd86da946 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 12:29:44 +0200 Subject: [PATCH 29/67] Compile on the other arches. --- redox-rt/src/arch/aarch64.rs | 46 ++++++++++++++++----------- redox-rt/src/arch/{x86.rs => i686.rs} | 19 ++++++++--- redox-rt/src/arch/mod.rs | 4 +-- redox-rt/src/lib.rs | 4 +-- redox-rt/src/signal.rs | 4 +-- src/platform/redox/signal.rs | 2 +- 6 files changed, 48 insertions(+), 31 deletions(-) rename redox-rt/src/arch/{x86.rs => i686.rs} (86%) diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index 26d62a506e..be9afcc0cc 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -1,11 +1,21 @@ use syscall::error::*; -use crate::{fork_inner, FdGuard}; +use crate::proc::{fork_inner, FdGuard}; +use crate::signal::inner_c; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; pub(crate) const STACK_SIZE: usize = 1024 * 1024; +#[derive(Debug, Default)] +pub struct SigArea { + pub altstack_top: usize, + pub altstack_bottom: usize, + pub tmp: usize, + pub onstack: u64, + pub disable_signals_depth: u64, +} + /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS /// is already initialized as if it was a thread. pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> { @@ -33,18 +43,16 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> { Ok(()) } -#[no_mangle] -unsafe extern "C" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize { +unsafe extern "C" fn fork_impl(initial_rsp: *mut usize) -> usize { Error::mux(fork_inner(initial_rsp)) } -#[no_mangle] -unsafe extern "C" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) { +unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) { let _ = syscall::close(cur_filetable_fd); let _ = syscall::close(new_pid_fd); } -asmfunction!(__relibc_internal_fork_wrapper: [" +asmfunction!(__relibc_internal_fork_wrapper -> usize: [" stp x29, x30, [sp, #-16]! stp x27, x28, [sp, #-16]! stp x25, x26, [sp, #-16]! @@ -57,20 +65,20 @@ asmfunction!(__relibc_internal_fork_wrapper: [" //TODO: store floating point regs mov x0, sp - bl __relibc_internal_fork_impl - b 2f -"]); + bl {fork_impl} -asmfunction!(__relibc_internal_fork_hook: [" + add sp, sp, #128 + ret +"] <= [fork_impl = sym fork_impl]); + +asmfunction!(__relibc_internal_fork_ret: [" ldp x0, x1, [sp] - bl __relibc_internal_fork_hook + bl {child_hook} //TODO: load floating point regs mov x0, xzr - .p2align 4 -2: add sp, sp, #32 ldp x19, x20, [sp], #16 ldp x21, x22, [sp], #16 @@ -80,17 +88,17 @@ asmfunction!(__relibc_internal_fork_hook: [" ldp x29, x30, [sp], #16 ret -"]); +"] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" mov x0, sp bl {inner} - mov x8, {SYS_SIGRETURN} - svc 0 -"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]); + // FIXME + b . +"] <= [inner = sym inner_c]); -asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" +asmfunction!(__relibc_internal_rlct_clone_ret: [" # Load registers ldp x8, x0, [sp], #16 ldp x1, x2, [sp], #16 @@ -100,4 +108,4 @@ asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" blr x8 ret -"]); +"] <= []); diff --git a/redox-rt/src/arch/x86.rs b/redox-rt/src/arch/i686.rs similarity index 86% rename from redox-rt/src/arch/x86.rs rename to redox-rt/src/arch/i686.rs index eb33fc441a..bab929a114 100644 --- a/redox-rt/src/arch/x86.rs +++ b/redox-rt/src/arch/i686.rs @@ -1,11 +1,21 @@ use syscall::error::*; -use crate::{fork_inner, FdGuard}; +use crate::proc::{fork_inner, FdGuard}; +use crate::signal::{inner_fastcall, RtSigarea}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 31; pub(crate) const STACK_SIZE: usize = 1024 * 1024; +#[derive(Debug, Default)] +pub struct SigArea { + pub altstack_top: usize, + pub altstack_bottom: usize, + pub tmp: usize, + pub onstack: u64, + pub disable_signals_depth: u64, +} + /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS /// is already initialized as if it was a thread. pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> { @@ -45,7 +55,7 @@ unsafe extern "cdecl" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, ne let _ = syscall::close(new_pid_fd); } -asmfunction!(__relibc_internal_fork_wrapper: [" +asmfunction!(__relibc_internal_fork_wrapper -> usize: [" push ebp mov ebp, esp @@ -98,9 +108,8 @@ asmfunction!(__relibc_internal_sigentry: [" add esp, 512 fxrstor [esp] - mov eax, {SYS_SIGRETURN} - int 0x80 -"] <= [inner = sym inner_fastcall, SYS_SIGRETURN = const SYS_SIGRETURN]); + ud2 +"] <= [inner = sym inner_fastcall]); asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" # Load registers diff --git a/redox-rt/src/arch/mod.rs b/redox-rt/src/arch/mod.rs index 372b7802b9..efbef2b74b 100644 --- a/redox-rt/src/arch/mod.rs +++ b/redox-rt/src/arch/mod.rs @@ -4,9 +4,9 @@ pub use self::aarch64::*; pub mod aarch64; #[cfg(target_arch = "x86")] -pub use self::x86::*; +pub use self::i686::*; #[cfg(target_arch = "x86")] -pub mod x86; +pub mod i686; #[cfg(target_arch = "x86_64")] pub use self::x86_64::*; diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 2d06cc8ec3..a1f3189c09 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -45,8 +45,8 @@ pub type Tcb = GenericTcb; pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) { // Uses ABI page let abi_ptr = tls_end - tls_len - 16; - ptr::write(abi_ptr as *mut usize, tls_end); - asm!( + core::ptr::write(abi_ptr as *mut usize, tls_end); + core::arch::asm!( "msr tpidr_el0, {}", in(reg) abi_ptr, ); diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 368620ce7b..7b72dd5e83 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -11,7 +11,7 @@ use crate::sync::Mutex; static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); pub fn sighandler_function() -> usize { - #[cfg(target_arch = "x86_64")] + //#[cfg(target_arch = "x86_64")] // Check OSXSAVE bit // TODO: HWCAP? /*if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { @@ -73,7 +73,7 @@ pub(crate) unsafe extern "C" fn inner_c(stack: usize) { inner(&mut *(stack as *mut SigStack)) } #[cfg(target_arch = "x86")] -unsafe extern "fastcall" fn inner_fastcall(stack: usize) { +pub(crate) unsafe extern "fastcall" fn inner_fastcall(stack: usize) { inner(&mut *(stack as *mut SigStack)) } diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 50f8f48a24..de8d1ee2b3 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -125,7 +125,7 @@ impl PalSignal for Sys { SigactionKind::Ignore } else { SigactionKind::Handled { - handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 { + handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_ulong != 0 { SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) }, } From c93b43b4b7a251fbe3eff46d91e4cb8aa5a8db51 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 14:53:58 +0200 Subject: [PATCH 30/67] Build on i686, remove unnecessary #[no_mangle]. --- redox-rt/src/arch/i686.rs | 14 ++++++-------- redox-rt/src/arch/x86_64.rs | 14 ++++++-------- redox-rt/src/signal.rs | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index bab929a114..2706061640 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -44,13 +44,11 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> { Ok(()) } -#[no_mangle] -unsafe extern "cdecl" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize { +unsafe extern "cdecl" fn fork_impl(initial_rsp: *mut usize) -> usize { Error::mux(fork_inner(initial_rsp)) } -#[no_mangle] -unsafe extern "cdecl" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) { +unsafe extern "cdecl" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) { let _ = syscall::close(cur_filetable_fd); let _ = syscall::close(new_pid_fd); } @@ -71,14 +69,14 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: [" fnstcw [esp+24] push esp - call __relibc_internal_fork_impl + call {fork_impl} pop esp jmp 2f -"] <= []); +"] <= [fork_impl = sym fork_impl]); asmfunction!(__relibc_internal_fork_ret: [" // Arguments already on the stack - call __relibc_internal_fork_hook + call {child_hook} //TODO ldmxcsr [esp+16] fldcw [esp+24] @@ -97,7 +95,7 @@ asmfunction!(__relibc_internal_fork_ret: [" pop ebp ret -"] <= []); +"] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" sub esp, 512 fxsave [esp] diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 2b54b5c567..a5b2e7e7d4 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -49,13 +49,11 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> { Ok(()) } -#[no_mangle] -unsafe extern "sysv64" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize { +unsafe extern "sysv64" fn fork_impl(initial_rsp: *mut usize) -> usize { Error::mux(fork_inner(initial_rsp)) } -#[no_mangle] -unsafe extern "sysv64" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) { +unsafe extern "sysv64" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) { let _ = syscall::close(cur_filetable_fd); let _ = syscall::close(new_pid_fd); } @@ -77,18 +75,18 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: [" fnstcw [rsp+24] mov rdi, rsp - call __relibc_internal_fork_impl + call {fork_impl} add rsp, 80 pop rbp ret -"] <= []); +"] <= [fork_impl = sym fork_impl]); asmfunction!(__relibc_internal_fork_ret: [" mov rdi, [rsp] mov rsi, [rsp + 8] - call __relibc_internal_fork_hook + call {child_hook} ldmxcsr [rsp+16] fldcw [rsp+24] @@ -105,7 +103,7 @@ asmfunction!(__relibc_internal_fork_ret: [" pop rbp ret -"] <= []); +"] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_rlct_clone_ret: [" # Load registers pop rax diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 7b72dd5e83..6171630bd5 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,8 +1,8 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; -use core::sync::atomic::{AtomicU64, Ordering}; +use core::sync::atomic::Ordering; -use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; +use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH, data::AtomicU64}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; From 590ad70a9f696ce72f0693d96f7a5b1f71778009 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 17:58:55 +0200 Subject: [PATCH 31/67] Fix trampoline for i686. Ctrl-C now works. --- redox-rt/src/arch/i686.rs | 98 +++++++++++++++++++++++++++++++++++-- redox-rt/src/arch/x86_64.rs | 14 +++--- redox-rt/src/signal.rs | 11 ++++- 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 2706061640..b09167207f 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -1,4 +1,6 @@ -use syscall::error::*; +use core::mem::offset_of; + +use syscall::*; use crate::proc::{fork_inner, FdGuard}; use crate::signal::{inner_fastcall, RtSigarea}; @@ -97,17 +99,105 @@ asmfunction!(__relibc_internal_fork_ret: [" ret "] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" - sub esp, 512 + // Read pending half of first signal. This can be done nonatomically wrt the mask bits, since + // only this thread is allowed to modify the latter. + + // Read first signal word + mov eax, gs:[{tcb_sc_off} + {sc_word}] + mov edx, gs:[{tcb_sc_off} + {sc_word} + 4] + not edx + and eax, edx + and eax, {SIGW0_PENDING_MASK} + bsf eax, eax + jnz 2f + + // Read second signal word + mov eax, gs:[{tcb_sc_off} + {sc_word} + 8] + mov edx, gs:[{tcb_sc_off} + {sc_word} + 12] + not edx + and eax, edx + and eax, {SIGW1_PENDING_MASK} + bsf eax, eax + jz 7f + add eax, 32 +2: + and esp, -{STACK_ALIGN} + bt gs:[{tcb_sa_off} + {sa_onstack}], eax + jnc 4f + + mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}] + cmp esp, edx + ja 3f + + cmp esp, gs:[{tcb_sa_off} + {sa_altstack_bottom}] + jnbe 4f +3: + mov esp, edx +4: + // Now that we have a stack, we can finally start populating the signal stack. + push fs + .byte 0x66, 0x6a, 0x00 // pushw 0 + push ss + .byte 0x66, 0x6a, 0x00 // pushw 0 + push dword ptr gs:[{tcb_sc_off} + {sc_saved_esp}] + push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}] + push cs + .byte 0x66, 0x6a, 0x00 // pushw 0 + push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}] + + push dword ptr gs:[{tcb_sc_off} + {sc_saved_edx}] + push ecx + push dword ptr gs:[{tcb_sc_off} + {sc_saved_eax}] + push ebx + push edi + push esi + push ebp + + push eax + sub esp, 512 + 8 fxsave [esp] mov ecx, esp call {inner} - add esp, 512 fxrstor [esp] + add esp, 512 + 12 + pop ebp + pop esi + pop edi + pop ebx + pop eax + pop ecx + pop edx + + pop dword ptr gs:[{tcb_sa_off} + {sa_tmp}] + add esp, 4 + popf + pop esp + jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp}] +7: ud2 -"] <= [inner = sym inner_fastcall]); +"] <= [ + inner = sym inner_fastcall, + sa_tmp = const offset_of!(SigArea, tmp), + sa_altstack_top = const offset_of!(SigArea, altstack_top), + sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), + sa_onstack = const offset_of!(SigArea, onstack), + sc_saved_eax = const offset_of!(Sigcontrol, saved_scratch_a), + sc_saved_edx = const offset_of!(Sigcontrol, saved_scratch_b), + sc_saved_eflags = const offset_of!(Sigcontrol, saved_flags), + sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), + sc_saved_esp = const offset_of!(Sigcontrol, saved_sp), + sc_word = const offset_of!(Sigcontrol, word), + tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), + tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), + SIGW0_PENDING_MASK = const !( + SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2 + ), + SIGW1_PENDING_MASK = const !0, + STACK_ALIGN = const 16, +]); asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" # Load registers diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index a5b2e7e7d4..a2cdf1adb5 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -153,27 +153,25 @@ asmfunction!(__relibc_internal_sigentry: [" jnz 7f add eax, 32 2: + sub rsp, {REDZONE_SIZE} + and rsp, -{STACK_ALIGN} + // By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then // skip the sigaltstack logic. bt fs:[{tcb_sa_off} + {sa_onstack}], eax - jc 3f + jnc 4f // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent // to setting 'top' to usize::MAX and 'bottom' to 0. - sub rsp, {REDZONE_SIZE} - and rsp, -{STACK_ALIGN} - jmp 4f -3: // If current RSP is above altstack region, switch to altstack mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}] - cmp rdx, rsp + cmp rsp, rdx cmova rsp, rdx // If current RSP is below altstack region, also switch to altstack - mov rdx, fs:[{tcb_sa_off} + {sa_altstack_bottom}] - cmp rdx, rsp + cmp rsp, fs:[{tcb_sa_off} + {sa_altstack_bottom}] cmovbe rsp, rdx .p2align 4 diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 6171630bd5..2ffd3031d7 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -34,7 +34,12 @@ pub struct SigStack { #[cfg(target_arch = "x86")] fx: [u8; 512], + #[cfg(target_arch = "x86_64")] _pad: [usize; 3], // pad to 192 = 3 * 64 = 168 + 24 bytes + + #[cfg(target_arch = "x86")] + _pad: [usize; 2], // pad to 192 = 3 * 64 = 168 + 24 bytes + sig_num: usize, regs: IntRegisters, // 160 bytes currently } @@ -310,15 +315,17 @@ pub fn setup_sighandler(area: &RtSigarea) { let mut sigactions = SIGACTIONS.lock(); } let arch = unsafe { &mut *area.arch.get() }; - - #[cfg(target_arch = "x86_64")] { // The asm decides whether to use the altstack, based on whether the saved stack pointer // was already on that stack. Thus, setting the altstack to the entire address space, is // equivalent to not using any altstack at all (the default). arch.altstack_top = usize::MAX; arch.altstack_bottom = 0; + arch.onstack = 0; + } + #[cfg(target_arch = "x86_64")] + { let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx; CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed); } From 630bf2ae3d739765e112e88b62846c541831db46 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 21:47:54 +0200 Subject: [PATCH 32/67] Fix popf operand size. --- redox-rt/src/arch/i686.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index b09167207f..290380face 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -173,7 +173,7 @@ asmfunction!(__relibc_internal_sigentry: [" pop dword ptr gs:[{tcb_sa_off} + {sa_tmp}] add esp, 4 - popf + popfd pop esp jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp}] 7: From 157d9fb2ba19f15180bcc67ae812c4ad89f5642a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Jun 2024 21:48:25 +0200 Subject: [PATCH 33/67] Set sigmask to sa_mask inside handler. --- redox-rt/src/signal.rs | 69 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 2ffd3031d7..e2beea9cef 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -51,7 +51,15 @@ unsafe fn inner(stack: &mut SigStack) { // asm counts from 0 stack.sig_num += 1; - let sigaction = SIGACTIONS.lock()[stack.sig_num]; + let sigaction = { + let mut guard = SIGACTIONS.lock(); + let action = guard[stack.sig_num]; + if action.flags.contains(SigactionFlags::RESETHAND) { + // TODO: other things that must be set + guard[stack.sig_num].kind = SigactionKind::Default; + } + action + }; let handler = match sigaction.kind { SigactionKind::Ignore => unreachable!(), @@ -62,16 +70,73 @@ unsafe fn inner(stack: &mut SigStack) { SigactionKind::Handled { handler } => handler, }; + let mut sigmask_inside = sigaction.mask; + if !sigaction.flags.contains(SigactionFlags::NODEFER) { + sigmask_inside &= !sig_bit(stack.sig_num); + } + + let os = &Tcb::current().unwrap().os_specific; + + // Set sigmask to sa_mask and unmark the signal as pending. + let lo = os.control.word[0].load(Ordering::Relaxed) >> 32; + let hi = os.control.word[1].load(Ordering::Relaxed) >> 32; + let prev_sigmask = lo | (hi << 32); + + let sig_group = stack.sig_num / 32; + + let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { + prev &= 0xffff_ffff; + if sig_group == 0 { + prev &= !sig_bit(stack.sig_num); + } + prev |= (sigmask_inside & 0xffff_ffff) << 32; + Some(prev) + }).unwrap(); + let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { + prev &= 0xffff_ffff; + if sig_group == 1 { + prev &= !sig_bit(stack.sig_num); + } + prev |= (sigmask_inside >> 32) << 32; + Some(prev) + }).unwrap(); + + // TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first? + // Re-enable signals again. - let control_flags = &Tcb::current().unwrap().os_specific.control.control_flags; + let control_flags = &os.control.control_flags; control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); core::sync::atomic::compiler_fence(Ordering::Acquire); + // Call handler, either sa_handler or sa_siginfo depending on flag. if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction { sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut()); } else if let Some(handler) = handler.handler { handler(stack.sig_num as c_int); } + + // Disable signals while we modify the sigmask again + control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); + core::sync::atomic::compiler_fence(Ordering::Acquire); + + // Update sigmask again. + let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { + prev &= 0xffff_ffff; + prev |= lo << 32; + Some(prev) + }).unwrap(); + let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { + prev &= 0xffff_ffff; + prev |= hi << 32; + Some(prev) + }).unwrap(); + + // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered + // here? And would it be possible to tail-call-optimize that? + + // And re-enable them again + control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); + core::sync::atomic::compiler_fence(Ordering::Acquire); } #[cfg(not(target_arch = "x86"))] pub(crate) unsafe extern "C" fn inner_c(stack: usize) { From 2d66993b3fb85cc31515964b4cadc90826f7dcfa Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 26 Jun 2024 12:58:27 +0200 Subject: [PATCH 34/67] Adapt to now-inverted signal mask (allowset). --- redox-rt/src/arch/i686.rs | 8 ++------ redox-rt/src/arch/x86_64.rs | 2 -- redox-rt/src/signal.rs | 37 +++++++++++++++++++++---------------- src/platform/redox/exec.rs | 3 +-- src/pthread/mod.rs | 16 ++++++++++------ 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 290380face..337eb6a5db 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -104,18 +104,14 @@ asmfunction!(__relibc_internal_sigentry: [" // Read first signal word mov eax, gs:[{tcb_sc_off} + {sc_word}] - mov edx, gs:[{tcb_sc_off} + {sc_word} + 4] - not edx - and eax, edx + and eax, gs:[{tcb_sc_off} + {sc_word} + 4] and eax, {SIGW0_PENDING_MASK} bsf eax, eax jnz 2f // Read second signal word mov eax, gs:[{tcb_sc_off} + {sc_word} + 8] - mov edx, gs:[{tcb_sc_off} + {sc_word} + 12] - not edx - and eax, edx + and eax, gs:[{tcb_sc_off} + {sc_word} + 12] and eax, {SIGW1_PENDING_MASK} bsf eax, eax jz 7f diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index a2cdf1adb5..8ae3b50f46 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -136,7 +136,6 @@ asmfunction!(__relibc_internal_sigentry: [" mov rax, fs:[{tcb_sc_off} + {sc_word}] mov rdx, rax shr rdx, 32 - not edx and eax, edx and eax, {SIGW0_PENDING_MASK} bsf eax, eax @@ -146,7 +145,6 @@ asmfunction!(__relibc_internal_sigentry: [" mov rax, fs:[{tcb_sc_off} + {sc_word} + 8] mov rdx, rax shr rdx, 32 - not edx and eax, edx and eax, {SIGW1_PENDING_MASK} bsf eax, eax diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index e2beea9cef..63fcbd460e 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -70,9 +70,9 @@ unsafe fn inner(stack: &mut SigStack) { SigactionKind::Handled { handler } => handler, }; - let mut sigmask_inside = sigaction.mask; + let mut sigallow_inside = !sigaction.mask; if !sigaction.flags.contains(SigactionFlags::NODEFER) { - sigmask_inside &= !sig_bit(stack.sig_num); + sigallow_inside &= !sig_bit(stack.sig_num); } let os = &Tcb::current().unwrap().os_specific; @@ -80,7 +80,7 @@ unsafe fn inner(stack: &mut SigStack) { // Set sigmask to sa_mask and unmark the signal as pending. let lo = os.control.word[0].load(Ordering::Relaxed) >> 32; let hi = os.control.word[1].load(Ordering::Relaxed) >> 32; - let prev_sigmask = lo | (hi << 32); + let prev_sigallow = lo | (hi << 32); let sig_group = stack.sig_num / 32; @@ -89,7 +89,7 @@ unsafe fn inner(stack: &mut SigStack) { if sig_group == 0 { prev &= !sig_bit(stack.sig_num); } - prev |= (sigmask_inside & 0xffff_ffff) << 32; + prev |= (sigallow_inside & 0xffff_ffff) << 32; Some(prev) }).unwrap(); let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { @@ -97,7 +97,7 @@ unsafe fn inner(stack: &mut SigStack) { if sig_group == 1 { prev &= !sig_bit(stack.sig_num); } - prev |= (sigmask_inside >> 32) << 32; + prev |= (sigallow_inside >> 32) << 32; Some(prev) }).unwrap(); @@ -119,7 +119,7 @@ unsafe fn inner(stack: &mut SigStack) { control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); core::sync::atomic::compiler_fence(Ordering::Acquire); - // Update sigmask again. + // Update allowset again. let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { prev &= 0xffff_ffff; prev |= lo << 32; @@ -156,7 +156,7 @@ pub fn set_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { modify_sigmask(old, new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32)) } pub fn or_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { - // Parsing nightmare... + // Parsing nightmare... :) modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32)) } pub fn andn_sigmask(new: Option, old: Option<&mut u64>) -> Result<()> { @@ -169,7 +169,7 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 let mut words = ctl.word.each_ref().map(|w| w.load(Ordering::Relaxed)); if let Some(old) = old { - *old = combine_mask(words); + *old = !combine_allowset(words); } let Some(mut op) = op else { return Ok(()); @@ -179,7 +179,11 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 let mut cant_raise = 0; for i in 0..2 { - while let Err(changed) = ctl.word[i].compare_exchange(words[i], ((words[i] >> 32) << 32) | u64::from(op(words[i] as u32, i == 1)), Ordering::Relaxed, Ordering::Relaxed) { + let pending_bits = words[i] & 0xffff_ffff; + let allow_bits = (words[i] >> 32) as u32; + let new_allow_bits = !op(!allow_bits, i == 1); + + while let Err(changed) = ctl.word[i].compare_exchange(words[i], pending_bits | (u64::from(new_allow_bits) << 32), Ordering::Relaxed, Ordering::Relaxed) { // If kernel observed a signal being unblocked and pending simultaneously, it will have // set a flag causing it to check for the INHIBIT_SIGNALS flag every time the context // is switched to. To avoid race conditions, we should NOT auto-raise those signals in @@ -357,16 +361,14 @@ static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { word: [ - AtomicU64::new(SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT), - AtomicU64::new(0), + //AtomicU64::new(SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | 0xffff_ffff_0000_0000), + AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending" + AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending" ], }; -fn expand_mask(mask: u64) -> [u64; 2] { - [mask & 0xffff_ffff, mask >> 32] -} -fn combine_mask([lo, hi]: [u64; 2]) -> u64 { - lo | ((hi & 0xffff_ffff) << 32) +fn combine_allowset([lo, hi]: [u64; 2]) -> u64 { + (lo >> 32) | ((hi >> 32) << 32) } const fn sig_bit(sig: usize) -> u64 { @@ -404,6 +406,9 @@ pub fn setup_sighandler(area: &RtSigarea) { .expect("failed to open thisproc:current/sighandler"); syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); let _ = syscall::close(fd); + + // TODO: Inherited set of ignored signals + set_sigmask(Some(0), None); } #[derive(Debug, Default)] pub struct RtSigarea { diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 32aaf675a5..5dda2e77c1 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -305,8 +305,7 @@ pub fn execve( unreachable!() } else { - let mut sigprocmask = 0_u64; - redox_rt::signal::set_sigmask(None, Some(&mut sigprocmask)).unwrap(); + let sigprocmask = redox_rt::signal::get_sigmask().unwrap(); let extrainfo = ExtraInfo { cwd: Some(&cwd), diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index a5210a2a0d..f6751cb510 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -136,13 +136,15 @@ pub(crate) unsafe fn create( ) -> Result { let attrs = attrs.copied().unwrap_or_default(); - let mut procmask = 0_u64; + let mut current_sigmask = 0_u64; #[cfg(target_os = "redox")] - redox_rt::signal::set_sigmask(None, Some(&mut procmask)) - .expect("failed to obtain sigprocmask for caller"); + { + current_sigmask = redox_rt::signal::get_sigmask() + .expect("failed to obtain sigprocmask for caller"); + } // Create a locked mutex, unlocked by the thread after it has started. - let synchronization_mutex = Mutex::locked(procmask); + let synchronization_mutex = Mutex::locked(current_sigmask); let synchronization_mutex = &synchronization_mutex; let stack_size = attrs.stacksize.next_multiple_of(Sys::getpagesize()); @@ -248,8 +250,10 @@ unsafe extern "C" fn new_thread_shim( (&*mutex).manual_unlock(); #[cfg(target_os = "redox")] - redox_rt::signal::set_sigmask(Some(procmask), None) - .expect("failed to set procmask in child thread"); + { + redox_rt::signal::set_sigmask(Some(procmask), None) + .expect("failed to set procmask in child thread"); + } let retval = entry_point(arg); From 442954915b9f5ce61078640a321f404e38c42044 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 26 Jun 2024 17:06:03 +0200 Subject: [PATCH 35/67] Fix x86_64 spurious signal jump condition. --- redox-rt/src/arch/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 8ae3b50f46..cf6b2dcbcf 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -148,7 +148,7 @@ asmfunction!(__relibc_internal_sigentry: [" and eax, edx and eax, {SIGW1_PENDING_MASK} bsf eax, eax - jnz 7f + jz 7f add eax, 32 2: sub rsp, {REDZONE_SIZE} From 568fc09277bbd2e4bbf3b2ebebacf78c4f67cd28 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 26 Jun 2024 22:10:02 +0200 Subject: [PATCH 36/67] Reset sighandler in fexec before switching addrsp. --- redox-rt/src/proc.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index e4564bb700..a89354f274 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -421,6 +421,15 @@ where push(argc)?; + if let Ok(sighandler_fd) = syscall::dup(*open_via_dup, b"sighandler").map(FdGuard::new) { + let _ = syscall::write(*sighandler_fd, &SetSighandlerData { + user_handler: 0, + excp_handler: 0, + thread_control_addr: 0, + proc_control_addr: 0, + }); + } + unsafe { deactivate_tcb(*open_via_dup)?; } From 9bb34901bfcc47d3e47b3a7233aba94e9baa2f3b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 27 Jun 2024 11:16:01 +0200 Subject: [PATCH 37/67] Adjust trampolines, only ip and 'archdep' regs are saved. --- redox-rt/src/arch/i686.rs | 24 ++++++++++++++---------- redox-rt/src/arch/x86_64.rs | 31 ++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 337eb6a5db..d2912ae8c4 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -99,6 +99,10 @@ asmfunction!(__relibc_internal_fork_ret: [" ret "] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" + mov gs:[{tcb_sa_off} + {sa_tmp_esp}], esp + mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax + mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx + // Read pending half of first signal. This can be done nonatomically wrt the mask bits, since // only this thread is allowed to modify the latter. @@ -135,15 +139,15 @@ asmfunction!(__relibc_internal_sigentry: [" .byte 0x66, 0x6a, 0x00 // pushw 0 push ss .byte 0x66, 0x6a, 0x00 // pushw 0 - push dword ptr gs:[{tcb_sc_off} + {sc_saved_esp}] + push dword ptr gs:[{tcb_sa_off} + {sc_tmp_esp}] push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}] push cs .byte 0x66, 0x6a, 0x00 // pushw 0 push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}] - push dword ptr gs:[{tcb_sc_off} + {sc_saved_edx}] + push dword ptr gs:[{tcb_sa_off} + {sc_tmp_edx}] push ecx - push dword ptr gs:[{tcb_sc_off} + {sc_saved_eax}] + push dword ptr gs:[{tcb_sa_off} + {sc_tmp_eax}] push ebx push edi push esi @@ -167,24 +171,24 @@ asmfunction!(__relibc_internal_sigentry: [" pop ecx pop edx - pop dword ptr gs:[{tcb_sa_off} + {sa_tmp}] + pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}] add esp, 4 popfd pop esp - jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp}] + jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}] 7: ud2 "] <= [ inner = sym inner_fastcall, - sa_tmp = const offset_of!(SigArea, tmp), + sa_tmp_eip = const offset_of!(SigArea, tmp_eip), + sa_tmp_esp = const offset_of!(SigArea, tmp_esp), + sa_tmp_eax = const offset_of!(SigArea, tmp_eax), + sa_tmp_edx = const offset_of!(SigArea, tmp_edx), sa_altstack_top = const offset_of!(SigArea, altstack_top), sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), sa_onstack = const offset_of!(SigArea, onstack), - sc_saved_eax = const offset_of!(Sigcontrol, saved_scratch_a), - sc_saved_edx = const offset_of!(Sigcontrol, saved_scratch_b), - sc_saved_eflags = const offset_of!(Sigcontrol, saved_flags), + sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg), sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), - sc_saved_esp = const offset_of!(Sigcontrol, saved_sp), sc_word = const offset_of!(Sigcontrol, word), tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index cf6b2dcbcf..13bfc52640 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -14,9 +14,13 @@ pub(crate) const STACK_SIZE: usize = 1024 * 1024; #[derive(Debug, Default)] pub struct SigArea { + pub tmp_rip: usize, + pub tmp_rsp: usize, + pub tmp_rax: usize, + pub tmp_rdx: usize, + pub altstack_top: usize, pub altstack_bottom: usize, - pub tmp: usize, pub onstack: u64, pub disable_signals_depth: u64, } @@ -130,6 +134,11 @@ asmfunction!(__relibc_internal_rlct_clone_ret: [" "] <= []); asmfunction!(__relibc_internal_sigentry: [" + // Save some registers + mov fs:[{tcb_sa_off} + {sa_tmp_rsp}], rsp + mov fs:[{tcb_sa_off} + {sa_tmp_rax}], rax + mov fs:[{tcb_sa_off} + {sa_tmp_rdx}], rdx + // First, select signal, always pick first available bit // Read first signal word @@ -177,16 +186,16 @@ asmfunction!(__relibc_internal_sigentry: [" // Now that we have a stack, we can finally start initializing the signal stack! push 0x23 // SS - push fs:[{tcb_sc_off} + {sc_saved_rsp}] + push fs:[{tcb_sa_off} + {sa_tmp_rsp}] push fs:[{tcb_sc_off} + {sc_saved_rflags}] push 0x2b // CS push fs:[{tcb_sc_off} + {sc_saved_rip}] push rdi push rsi - push fs:[{tcb_sc_off} + {sc_saved_rdx}] + push fs:[{tcb_sa_off} + {sa_tmp_rdx}] push rcx - push fs:[{tcb_sc_off} + {sc_saved_rax}] + push fs:[{tcb_sa_off} + {sa_tmp_rax}] push r8 push r9 push r10 @@ -243,11 +252,11 @@ asmfunction!(__relibc_internal_sigentry: [" iretq /* - pop qword ptr fs:[{tcb_sa_off} + {sa_tmp}] + pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] add rsp, 8 popfq pop rsp - jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp}] + jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] */ 6: fxsave64 [rsp] @@ -262,15 +271,15 @@ asmfunction!(__relibc_internal_sigentry: [" // Spurious signal "] <= [ inner = sym inner_c, - sa_tmp = const offset_of!(SigArea, tmp), + sa_tmp_rip = const offset_of!(SigArea, tmp_rip), + sa_tmp_rsp = const offset_of!(SigArea, tmp_rsp), + sa_tmp_rax = const offset_of!(SigArea, tmp_rax), + sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx), sa_altstack_top = const offset_of!(SigArea, altstack_top), sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), sa_onstack = const offset_of!(SigArea, onstack), - sc_saved_rax = const offset_of!(Sigcontrol, saved_scratch_a), - sc_saved_rdx = const offset_of!(Sigcontrol, saved_scratch_b), - sc_saved_rflags = const offset_of!(Sigcontrol, saved_flags), + sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg), sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), - sc_saved_rsp = const offset_of!(Sigcontrol, saved_sp), sc_word = const offset_of!(Sigcontrol, word), tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), From cda5f18946062d472f222d099db4f97ba9eb4c75 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 27 Jun 2024 11:42:40 +0200 Subject: [PATCH 38/67] Change interrupt stack format, emulate atomicity. --- redox-rt/src/arch/i686.rs | 1 + redox-rt/src/arch/x86_64.rs | 64 ++++++++++++++++++++++++++++++++----- redox-rt/src/signal.rs | 10 +++--- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index d2912ae8c4..27f1e55bce 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -10,6 +10,7 @@ pub(crate) const STACK_TOP: usize = 1 << 31; pub(crate) const STACK_SIZE: usize = 1024 * 1024; #[derive(Debug, Default)] +#[repr(C)] pub struct SigArea { pub altstack_top: usize, pub altstack_bottom: usize, diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 13bfc52640..33d52167e2 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -6,6 +6,7 @@ use syscall::error::*; use syscall::flag::*; use crate::proc::{fork_inner, FdGuard}; +use crate::signal::SigStack; use crate::signal::{inner_c, RtSigarea}; // Setup a stack starting from the very end of the address space, and then growing downwards. @@ -13,6 +14,7 @@ pub(crate) const STACK_TOP: usize = 1 << 47; pub(crate) const STACK_SIZE: usize = 1024 * 1024; #[derive(Debug, Default)] +#[repr(C)] pub struct SigArea { pub tmp_rip: usize, pub tmp_rsp: usize, @@ -25,6 +27,31 @@ pub struct SigArea { pub disable_signals_depth: u64, } +#[repr(C, align(64))] +#[derive(Debug, Default)] +pub struct ArchIntRegs { + _pad: [usize; 2], // ensure size is divisible by 32 + + pub r15: usize, + pub r14: usize, + pub r13: usize, + pub r12: usize, + pub rbp: usize, + pub rbx: usize, + pub r11: usize, + pub r10: usize, + pub r9: usize, + pub r8: usize, + pub rax: usize, + pub rcx: usize, + pub rdx: usize, + pub rsi: usize, + pub rdi: usize, + pub rflags: usize, + pub rip: usize, + pub rsp: usize, +} + /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS /// is already initialized as if it was a thread. pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> { @@ -185,11 +212,9 @@ asmfunction!(__relibc_internal_sigentry: [" 4: // Now that we have a stack, we can finally start initializing the signal stack! - push 0x23 // SS push fs:[{tcb_sa_off} + {sa_tmp_rsp}] - push fs:[{tcb_sc_off} + {sc_saved_rflags}] - push 0x2b // CS push fs:[{tcb_sc_off} + {sc_saved_rip}] + push fs:[{tcb_sc_off} + {sc_saved_rflags}] push rdi push rsi @@ -250,14 +275,12 @@ asmfunction!(__relibc_internal_sigentry: [" pop rsi pop rdi - iretq - /* - pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] - add rsp, 8 popfq + pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] +__relibc_internal_sigentry_crit_first: pop rsp +__relibc_internal_sigentry_crit_second: jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] - */ 6: fxsave64 [rsp] @@ -292,4 +315,29 @@ asmfunction!(__relibc_internal_sigentry: [" STACK_ALIGN = const 64, // if xsave is used ]); +extern "C" { + fn __relibc_internal_sigentry_crit_first(); + fn __relibc_internal_sigentry_crit_second(); +} +pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { + // It is impossible to update RSP and RIP atomically on x86_64, without using IRETQ, which is + // almost as slow as calling a SIGRETURN syscall would be. Instead, we abuse the fact that + // signals are disabled in the prologue of the signal trampoline, which allows us to emulate + // atomicity inside the critical section, consisting of one instruction at 'crit_first', and + // one at 'crit_second', see asm. + + if stack.regs.rip == __relibc_internal_sigentry_crit_first as usize { + // Reexecute pop rsp and jump steps. This case needs to be different from the one below, + // since rsp has not been overwritten with the previous context's stack, just yet. At this + // point, we know [rsp+0] contains the saved RSP, and [rsp-8] contains the saved RIP. + let stack_ptr = stack.regs.rsp as *const usize; + stack.regs.rsp = stack_ptr.read(); + stack.regs.rip = stack_ptr.sub(1).read(); + } else if stack.regs.rip == __relibc_internal_sigentry_crit_second as usize { + // Almost finished, just reexecute the jump before tmp_rip is overwritten by this + // deeper-level signal. + stack.regs.rip = area.tmp_rip; + } +} + static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(1); // FIXME diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 63fcbd460e..d328896d62 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; use core::sync::atomic::Ordering; -use syscall::{Error, IntRegisters, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH, data::AtomicU64}; +use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH, data::AtomicU64}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; @@ -41,16 +41,18 @@ pub struct SigStack { _pad: [usize; 2], // pad to 192 = 3 * 64 = 168 + 24 bytes sig_num: usize, - regs: IntRegisters, // 160 bytes currently + pub regs: ArchIntRegs, // 160 bytes currently } #[inline(always)] unsafe fn inner(stack: &mut SigStack) { - // TODO: Set procmask based on SA_NODEFER, SA_RESETHAND, and sa_mask. + let os = &Tcb::current().unwrap().os_specific; // asm counts from 0 stack.sig_num += 1; + arch_pre(stack, &mut *os.arch.get()); + let sigaction = { let mut guard = SIGACTIONS.lock(); let action = guard[stack.sig_num]; @@ -75,8 +77,6 @@ unsafe fn inner(stack: &mut SigStack) { sigallow_inside &= !sig_bit(stack.sig_num); } - let os = &Tcb::current().unwrap().os_specific; - // Set sigmask to sa_mask and unmark the signal as pending. let lo = os.control.word[0].load(Ordering::Relaxed) >> 32; let hi = os.control.word[1].load(Ordering::Relaxed) >> 32; From 5b8d53ddd38114874d3c361eb1f6e13496336110 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 27 Jun 2024 14:00:17 +0200 Subject: [PATCH 39/67] Fix x86_64 trampoline. --- redox-rt/src/arch/x86_64.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 33d52167e2..b597928fac 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -231,6 +231,7 @@ asmfunction!(__relibc_internal_sigentry: [" push r13 push r14 push r15 + sub rsp, 16 push rax // selected signal @@ -258,7 +259,7 @@ asmfunction!(__relibc_internal_sigentry: [" xrstor [rsp] 5: - add rsp, 4096 + 32 + add rsp, 4096 + 32 + 16 pop r15 pop r14 pop r13 @@ -277,8 +278,17 @@ asmfunction!(__relibc_internal_sigentry: [" popfq pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] + + // x86 lacks atomic instructions for setting both the stack and instruction pointer + // simultaneously, except the slow microcoded IRETQ instruction. Thus, we let the arch_pre + // function emulate atomicity between the pop rsp and indirect jump. + + .globl __relibc_internal_sigentry_crit_first __relibc_internal_sigentry_crit_first: + pop rsp + + .globl __relibc_internal_sigentry_crit_second __relibc_internal_sigentry_crit_second: jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] 6: From 39f45b0f67336a11e6f7eadcb71790dbea1cc919 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 27 Jun 2024 16:58:24 +0200 Subject: [PATCH 40/67] Fix i686 trampoline. --- redox-rt/src/arch/i686.rs | 67 +++++++++++++++++++++++++++++---------- redox-rt/src/signal.rs | 11 ++++--- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 27f1e55bce..07d8ae05b7 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -3,7 +3,7 @@ use core::mem::offset_of; use syscall::*; use crate::proc::{fork_inner, FdGuard}; -use crate::signal::{inner_fastcall, RtSigarea}; +use crate::signal::{inner_fastcall, RtSigarea, SigStack}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 31; @@ -14,10 +14,30 @@ pub(crate) const STACK_SIZE: usize = 1024 * 1024; pub struct SigArea { pub altstack_top: usize, pub altstack_bottom: usize, - pub tmp: usize, + pub tmp_eip: usize, + pub tmp_esp: usize, + pub tmp_eax: usize, + pub tmp_edx: usize, pub onstack: u64, pub disable_signals_depth: u64, } +#[derive(Debug, Default)] +#[repr(C)] +pub struct ArchIntRegs { + pub _pad: [usize; 2], // make size divisible by 16 + + pub ebp: usize, + pub esi: usize, + pub edi: usize, + pub ebx: usize, + pub eax: usize, + pub ecx: usize, + pub edx: usize, + + pub eflags: usize, + pub eip: usize, + pub esp: usize, +} /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS /// is already initialized as if it was a thread. @@ -100,6 +120,7 @@ asmfunction!(__relibc_internal_fork_ret: [" ret "] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" + // Save some registers mov gs:[{tcb_sa_off} + {sa_tmp_esp}], esp mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx @@ -136,33 +157,29 @@ asmfunction!(__relibc_internal_sigentry: [" mov esp, edx 4: // Now that we have a stack, we can finally start populating the signal stack. - push fs - .byte 0x66, 0x6a, 0x00 // pushw 0 - push ss - .byte 0x66, 0x6a, 0x00 // pushw 0 - push dword ptr gs:[{tcb_sa_off} + {sc_tmp_esp}] - push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}] - push cs - .byte 0x66, 0x6a, 0x00 // pushw 0 + push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esp}] push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}] + push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}] - push dword ptr gs:[{tcb_sa_off} + {sc_tmp_edx}] + push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edx}] push ecx - push dword ptr gs:[{tcb_sa_off} + {sc_tmp_eax}] + push dword ptr gs:[{tcb_sa_off} + {sa_tmp_eax}] push ebx push edi push esi push ebp + sub esp, 8 + push eax - sub esp, 512 + 8 + sub esp, 12 + 512 fxsave [esp] mov ecx, esp call {inner} fxrstor [esp] - add esp, 512 + 12 + add esp, 512 + 12 + 4 + 8 pop ebp pop esi @@ -172,10 +189,15 @@ asmfunction!(__relibc_internal_sigentry: [" pop ecx pop edx - pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}] - add esp, 4 popfd + pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}] + + .globl __relibc_internal_sigentry_crit_first +__relibc_internal_sigentry_crit_first: pop esp + + .globl __relibc_internal_sigentry_crit_second +__relibc_internal_sigentry_crit_second: jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}] 7: ud2 @@ -218,3 +240,16 @@ asmfunction!(__relibc_internal_rlct_clone_ret -> usize: [" ret "] <= []); +extern "C" { + fn __relibc_internal_sigentry_crit_first(); + fn __relibc_internal_sigentry_crit_second(); +} +pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { + if stack.regs.eip == __relibc_internal_sigentry_crit_first as usize { + let stack_ptr = stack.regs.esp as *const usize; + stack.regs.esp = stack_ptr.read(); + stack.regs.eip = stack_ptr.sub(1).read(); + } else if stack.regs.eip == __relibc_internal_sigentry_crit_second as usize { + stack.regs.eip = area.tmp_eip; + } +} diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index d328896d62..8b7bf0ff49 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -29,19 +29,22 @@ pub fn sighandler_function() -> usize { #[repr(C)] pub struct SigStack { #[cfg(target_arch = "x86_64")] - fx: [u8; 4096], + fx: [u8; 4096], // 64 byte aligned #[cfg(target_arch = "x86")] - fx: [u8; 512], + fx: [u8; 512], // 16 byte aligned #[cfg(target_arch = "x86_64")] _pad: [usize; 3], // pad to 192 = 3 * 64 = 168 + 24 bytes #[cfg(target_arch = "x86")] - _pad: [usize; 2], // pad to 192 = 3 * 64 = 168 + 24 bytes + _pad: [usize; 3], // pad to 64 = 4 * 16 = 52 + 12 bytes sig_num: usize, - pub regs: ArchIntRegs, // 160 bytes currently + + // x86_64: 160 bytes + // i686: 48 bytes + pub regs: ArchIntRegs, } #[inline(always)] From f28fe4a3875c784534dd486d879a38a1067ca8ee Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 27 Jun 2024 21:20:56 +0200 Subject: [PATCH 41/67] Use fetch_add instead of CAS when setting sigmask. This makes sigprocmask, the way it is currently implemented, wait-free (technically I think x86 only guarantees LOCK XADD is lock-free and fair, but still). --- redox-rt/src/signal.rs | 53 ++++++++++-------------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 8b7bf0ff49..a651e34182 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -79,30 +79,18 @@ unsafe fn inner(stack: &mut SigStack) { if !sigaction.flags.contains(SigactionFlags::NODEFER) { sigallow_inside &= !sig_bit(stack.sig_num); } + let sigallow_inside_lo = sigallow_inside & 0xffff_ffff; + let sigallow_inside_hi = sigallow_inside >> 32; // Set sigmask to sa_mask and unmark the signal as pending. - let lo = os.control.word[0].load(Ordering::Relaxed) >> 32; - let hi = os.control.word[1].load(Ordering::Relaxed) >> 32; - let prev_sigallow = lo | (hi << 32); + let prev_sigallow_lo = os.control.word[0].load(Ordering::Relaxed) >> 32; + let prev_sigallow_hi = os.control.word[1].load(Ordering::Relaxed) >> 32; + let prev_sigallow = prev_sigallow_lo | (prev_sigallow_hi << 32); let sig_group = stack.sig_num / 32; - let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { - prev &= 0xffff_ffff; - if sig_group == 0 { - prev &= !sig_bit(stack.sig_num); - } - prev |= (sigallow_inside & 0xffff_ffff) << 32; - Some(prev) - }).unwrap(); - let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { - prev &= 0xffff_ffff; - if sig_group == 1 { - prev &= !sig_bit(stack.sig_num); - } - prev |= (sigallow_inside >> 32) << 32; - Some(prev) - }).unwrap(); + let prev_w0 = os.control.word[0].fetch_add(sigallow_inside_lo.wrapping_sub(prev_sigallow_lo), Ordering::Relaxed); + let prev_w1 = os.control.word[1].fetch_add(sigallow_inside_hi.wrapping_sub(prev_sigallow_hi), Ordering::Relaxed); // TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first? @@ -123,16 +111,8 @@ unsafe fn inner(stack: &mut SigStack) { core::sync::atomic::compiler_fence(Ordering::Acquire); // Update allowset again. - let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { - prev &= 0xffff_ffff; - prev |= lo << 32; - Some(prev) - }).unwrap(); - let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| { - prev &= 0xffff_ffff; - prev |= hi << 32; - Some(prev) - }).unwrap(); + let prev_w0 = os.control.word[0].fetch_add(prev_sigallow_lo.wrapping_sub(sigallow_inside_lo), Ordering::Relaxed); + let prev_w1 = os.control.word[1].fetch_add(prev_sigallow_hi.wrapping_sub(sigallow_inside_hi), Ordering::Relaxed); // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered // here? And would it be possible to tail-call-optimize that? @@ -183,19 +163,10 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 for i in 0..2 { let pending_bits = words[i] & 0xffff_ffff; - let allow_bits = (words[i] >> 32) as u32; - let new_allow_bits = !op(!allow_bits, i == 1); + let old_allow_bits = words[i] & 0xffff_ffff_0000_0000; + let new_allow_bits = u64::from(!op(!((old_allow_bits >> 32) as u32), i == 1)) << 32; - while let Err(changed) = ctl.word[i].compare_exchange(words[i], pending_bits | (u64::from(new_allow_bits) << 32), Ordering::Relaxed, Ordering::Relaxed) { - // If kernel observed a signal being unblocked and pending simultaneously, it will have - // set a flag causing it to check for the INHIBIT_SIGNALS flag every time the context - // is switched to. To avoid race conditions, we should NOT auto-raise those signals in - // userspace as a result of unblocking it. The kernel will instead take care of that later. - can_raise |= (changed & (changed >> 32)) << (32 * i); - cant_raise |= (changed & !(changed >> 32)) << (32 * i); - - words[i] = changed; - } + ctl.word[i].fetch_add(new_allow_bits.wrapping_sub(old_allow_bits), Ordering::Relaxed); } // TODO: Prioritize cant_raise realtime signals? From 71800d2b731730d89be998a44db587aca1ba293b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 28 Jun 2024 22:19:47 +0200 Subject: [PATCH 42/67] Fix spurious ign signal. --- redox-rt/src/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index a651e34182..7c93c8a728 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -219,7 +219,7 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); // mark the signal as masked - ctl.word[sig_group].fetch_or(sig_bit32, Ordering::Relaxed); + ctl.word[sig_group].fetch_and(!(sig_bit32 << 32), Ordering::Relaxed); // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by // sigaction. From 63509e75ce127fdb05c07a464e975687e8ef2977 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 29 Jun 2024 14:01:38 +0200 Subject: [PATCH 43/67] Use new signal ABI where 'actions' are in shmem. --- redox-rt/src/arch/x86_64.rs | 4 +- redox-rt/src/signal.rs | 163 ++++++++++++++++++++---------------- src/header/signal/redox.rs | 14 ++-- 3 files changed, 99 insertions(+), 82 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index b597928fac..689b1ff8eb 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -317,9 +317,7 @@ __relibc_internal_sigentry_crit_second: tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), supports_xsave = sym SUPPORTS_XSAVE, - SIGW0_PENDING_MASK = const !( - SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2 - ), + SIGW0_PENDING_MASK = const !0, SIGW1_PENDING_MASK = const !0, REDZONE_SIZE = const 128, STACK_ALIGN = const 64, // if xsave is used diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 7c93c8a728..0e9eb42781 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,8 +1,9 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; -use core::sync::atomic::Ordering; +use core::sync::atomic::{AtomicUsize, Ordering}; -use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH, data::AtomicU64}; +use syscall::{RawAction, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; +use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64}; use crate::{arch::*, Tcb}; use crate::sync::Mutex; @@ -57,11 +58,16 @@ unsafe fn inner(stack: &mut SigStack) { arch_pre(stack, &mut *os.arch.get()); let sigaction = { - let mut guard = SIGACTIONS.lock(); - let action = guard[stack.sig_num]; + let mut guard = SIGACTIONS_LOCK.lock(); + let action = convert_old(&PROC_CONTROL_STRUCT.actions[stack.sig_num - 1]); if action.flags.contains(SigactionFlags::RESETHAND) { // TODO: other things that must be set - guard[stack.sig_num].kind = SigactionKind::Default; + drop(guard); + sigaction(stack.sig_num as u8, Some(&Sigaction { + kind: SigactionKind::Default, + mask: 0, + flags: SigactionFlags::empty(), + }), None); } action }; @@ -191,6 +197,44 @@ pub struct Sigaction { pub mask: u64, pub flags: SigactionFlags, } +impl Sigaction { + fn ip(&self) -> usize { + unsafe { + match self.kind { + SigactionKind::Handled { handler } => if self.flags.contains(SigactionFlags::SIGINFO) { + handler.sigaction.map_or(0, |a| a as usize) + } else { + handler.handler.map_or(0, |a| a as usize) + } + _ => 0, + } + } + } +} + +const MASK_DONTCARE: u64 = !0; + +fn convert_old(action: &RawAction) -> Sigaction { + let old_first = action.first.load(Ordering::Relaxed); + let old_mask = action.user_data.load(Ordering::Relaxed); + + let handler = (old_first & !(u64::from(STORED_FLAGS) << 32)) as usize; + let flags = SigactionFlags::from_bits_retain(((old_first >> 32) as u32) & STORED_FLAGS); + + let kind = if handler == default_handler as usize { + SigactionKind::Default + } else if flags.contains(SigactionFlags::IGNORED) { + SigactionKind::Ignore + } else { + SigactionKind::Handled { handler: unsafe { core::mem::transmute(handler as usize) } } + }; + + Sigaction { + mask: old_mask, + flags, + kind, + } +} pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> { if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) { @@ -199,62 +243,46 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction let _sigguard = tmp_disable_signals(); let ctl = current_sigctl(); - let mut guard = SIGACTIONS.lock(); - let old_ignmask = IGNMASK.load(Ordering::Relaxed); + + let action = &PROC_CONTROL_STRUCT.actions[usize::from(signal) - 1]; if let Some(old) = old { - *old = guard[usize::from(signal)]; + *old = convert_old(action); } let Some(new) = new else { return Ok(()); }; - guard[usize::from(signal)] = *new; - let sig_group = usize::from(signal) / 32; - let sig_bit32 = 1 << ((signal - 1) % 32); + let explicit_handler = new.ip(); - match (usize::from(signal), new.kind) { + let (mask, flags, handler) = match (usize::from(signal), new.kind) { (_, SigactionKind::Ignore) | (SIGURG | SIGWINCH, SigactionKind::Default) => { - IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); - - // mark the signal as masked - ctl.word[sig_group].fetch_and(!(sig_bit32 << 32), Ordering::Relaxed); - - // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by + // TODO: POSIX specifies that pending signals shall be discarded if set to SIG_IGN by // sigaction. // TODO: handle tmp_disable_signals + (MASK_DONTCARE, SigactionFlags::IGNORED, if matches!(new.kind, SigactionKind::Default) { + default_handler as usize + } else { + 0 + }) } // TODO: Handle pending signals before these flags are set. - (SIGTSTP, SigactionKind::Default) => { - PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst); - } - (SIGTTIN, SigactionKind::Default) => { - PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst); - } - (SIGTTOU, SigactionKind::Default) => { - PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst); - } + (SIGTSTP | SIGTTOU | SIGTTIN, SigactionKind::Default) => (MASK_DONTCARE, SigactionFlags::SIG_SPECIFIC, default_handler as usize), (SIGCHLD, SigactionKind::Default) => { - if new.flags.contains(SigactionFlags::NOCLDSTOP) { - PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst); - } else { - PROC_CONTROL_STRUCT.word[0].fetch_and(!SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst); - } - IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); - - // mark the signal as masked - ctl.word[sig_group].fetch_or(sig_bit32, Ordering::Relaxed); + let nocldstop_bit = new.flags & SigactionFlags::SIG_SPECIFIC; + (MASK_DONTCARE, SigactionFlags::IGNORED | nocldstop_bit, default_handler as usize) } (_, SigactionKind::Default) => { - IGNMASK.store(old_ignmask & !sig_bit(signal.into()), Ordering::Relaxed); - - // TODO: update mask - //ctl.word[usize::from(signal)].fetch_or(); + (new.mask, new.flags, default_handler as usize) }, - (_, SigactionKind::Handled { .. }) => (), - } + (_, SigactionKind::Handled { .. }) => { + (new.mask, new.flags, explicit_handler) + } + }; + action.first.store((handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32), Ordering::Relaxed); + action.user_data.store(mask, Ordering::Relaxed); Ok(()) } @@ -296,26 +324,23 @@ bitflags::bitflags! { // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion. #[derive(Clone, Copy, Default)] pub struct SigactionFlags: u32 { - const NOCLDSTOP = 1; const NOCLDWAIT = 2; - const SIGINFO = 4; - const RESTORER = 0x0400_0000; - const ONSTACK = 0x0800_0000; - const RESTART = 0x1000_0000; - const NODEFER = 0x4000_0000; - const RESETHAND = 0x8000_0000; + const RESTORER = 4; + const SIGINFO = 0x0200_0000; + const ONSTACK = 0x0400_0000; + const RESTART = 0x0800_0000; + const NODEFER = 0x1000_0000; + const RESETHAND = 0x2000_0000; + const SIG_SPECIFIC = 0x4000_0000; + const IGNORED = 0x8000_0000; } } -fn default_term_handler(sig: c_int) { + +const STORED_FLAGS: u32 = 0xfe00_0000; + +fn default_handler(sig: c_int) { syscall::exit((sig as usize) << 8); } -fn default_core_handler(sig: c_int) { - syscall::exit((sig as usize) << 8); -} -fn default_ign_handler(_: c_int) { -} -fn stop_handler_sentinel(_: c_int) { -} #[derive(Clone, Copy)] pub union SignalHandler { @@ -323,22 +348,16 @@ pub union SignalHandler { pub sigaction: Option, } -struct TheDefault { - actions: [Sigaction; 64], - ignmask: u64, -} - -// indexed directly by signal number -static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction { flags: SigactionFlags::empty(), mask: 0, kind: SigactionKind::Default }; 64]); - -static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); +static SIGACTIONS_LOCK: Mutex<()> = Mutex::new(()); static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { - word: [ - //AtomicU64::new(SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | 0xffff_ffff_0000_0000), - AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending" - AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending" - ], + pending: AtomicU64::new(0), + actions: [const { + RawAction { + first: AtomicU64::new(0), + user_data: AtomicU64::new(0), + } + }; 64], }; fn combine_allowset([lo, hi]: [u64; 2]) -> u64 { @@ -353,7 +372,7 @@ const fn sig_bit(sig: usize) -> u64 { pub fn setup_sighandler(area: &RtSigarea) { { - let mut sigactions = SIGACTIONS.lock(); + let mut sigactions = SIGACTIONS_LOCK.lock(); } let arch = unsafe { &mut *area.arch.get() }; { diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs index 8e878dda0a..689b9da3bf 100644 --- a/src/header/signal/redox.rs +++ b/src/header/signal/redox.rs @@ -36,14 +36,14 @@ pub const NSIG: usize = 32; pub const SIGRTMIN: usize = 35; pub const SIGRTMAX: usize = 64; -pub const SA_NOCLDSTOP: usize = 0x0000_0001; pub const SA_NOCLDWAIT: usize = 0x0000_0002; -pub const SA_SIGINFO: usize = 0x0000_0004; -pub const SA_RESTORER: usize = 0x0400_0000; -pub const SA_ONSTACK: usize = 0x0800_0000; -pub const SA_RESTART: usize = 0x1000_0000; -pub const SA_NODEFER: usize = 0x4000_0000; -pub const SA_RESETHAND: usize = 0x8000_0000; +pub const SA_RESTORER: usize = 0x0000_0004; // TODO: remove +pub const SA_SIGINFO: usize = 0x0200_0000; +pub const SA_ONSTACK: usize = 0x0400_0000; +pub const SA_RESTART: usize = 0x0800_0000; +pub const SA_NODEFER: usize = 0x1000_0000; +pub const SA_RESETHAND: usize = 0x2000_0000; +pub const SA_NOCLDSTOP: usize = 0x4000_0000; pub const SS_ONSTACK: usize = 0x00000001; pub const SS_DISABLE: usize = 0x00000002; From a166a1ebb2a5391d94c2aba78fa76e7737263be6 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 29 Jun 2024 14:55:47 +0200 Subject: [PATCH 44/67] For now, put ptr to pctl in TCB. --- redox-rt/src/arch/x86_64.rs | 18 +++++++++++++----- redox-rt/src/signal.rs | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 689b1ff8eb..63b59c9faa 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,13 +1,13 @@ use core::mem::offset_of; use core::sync::atomic::AtomicU8; -use syscall::data::Sigcontrol; +use syscall::data::{Sigcontrol, SigProcControl}; use syscall::error::*; use syscall::flag::*; use crate::proc::{fork_inner, FdGuard}; use crate::signal::SigStack; -use crate::signal::{inner_c, RtSigarea}; +use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; @@ -23,8 +23,8 @@ pub struct SigArea { pub altstack_top: usize, pub altstack_bottom: usize, - pub onstack: u64, pub disable_signals_depth: u64, + pub pctl: usize, // TODO: find out how to correctly reference that static } #[repr(C, align(64))] @@ -193,7 +193,13 @@ asmfunction!(__relibc_internal_sigentry: [" // By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then // skip the sigaltstack logic. - bt fs:[{tcb_sa_off} + {sa_onstack}], eax + mov edx, eax + add edx, edx + lea rdx, [{pctl_off_actions} + edx * 8] + add rdx, fs:[{tcb_sa_off} + {sa_off_pctl}] + + // scale factor 16 doesn't exist, so we premultiplied edx by 2 + bt qword ptr [rdx], 56 jnc 4f // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent @@ -310,12 +316,14 @@ __relibc_internal_sigentry_crit_second: sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx), sa_altstack_top = const offset_of!(SigArea, altstack_top), sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), - sa_onstack = const offset_of!(SigArea, onstack), sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg), sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), sc_word = const offset_of!(Sigcontrol, word), tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), + pctl_off_actions = const offset_of!(SigProcControl, actions), + //pctl = sym PROC_CONTROL_STRUCT, + sa_off_pctl = const offset_of!(SigArea, pctl), supports_xsave = sym SUPPORTS_XSAVE, SIGW0_PENDING_MASK = const !0, SIGW1_PENDING_MASK = const !0, diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 0e9eb42781..0eeaf73581 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -350,7 +350,7 @@ pub union SignalHandler { static SIGACTIONS_LOCK: Mutex<()> = Mutex::new(()); -static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { +pub(crate) static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl { pending: AtomicU64::new(0), actions: [const { RawAction { @@ -381,7 +381,7 @@ pub fn setup_sighandler(area: &RtSigarea) { // equivalent to not using any altstack at all (the default). arch.altstack_top = usize::MAX; arch.altstack_bottom = 0; - arch.onstack = 0; + arch.pctl = core::ptr::addr_of!(PROC_CONTROL_STRUCT) as usize; } #[cfg(target_arch = "x86_64")] From 5460ffc4c9d76037d8751679719b242ea2d56536 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 29 Jun 2024 15:58:09 +0200 Subject: [PATCH 45/67] Jump to trampoline after SYS_{READ,WRITE} EINTR. --- redox-rt/src/arch/x86_64.rs | 21 +++++++++++++++++++- redox-rt/src/lib.rs | 1 + redox-rt/src/signal.rs | 19 ++++++++++++------ redox-rt/src/sys.rs | 35 ++++++++++++++++++++++++++++++++++ src/platform/redox/libredox.rs | 5 +++-- src/platform/redox/mod.rs | 8 +++++--- 6 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 redox-rt/src/sys.rs diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 63b59c9faa..67a3600c65 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -6,8 +6,9 @@ use syscall::error::*; use syscall::flag::*; use crate::proc::{fork_inner, FdGuard}; -use crate::signal::SigStack; +use crate::signal::{tmp_disable_signals, SigStack}; use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT}; +use crate::Tcb; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; @@ -357,3 +358,21 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { } static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(1); // FIXME + +pub unsafe fn manually_enter_trampoline() { + let _g = tmp_disable_signals(); + + let a = &Tcb::current().unwrap().os_specific.control; + a.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? + + core::arch::asm!(" + lea rax, [rip + 2f] + mov fs:[{tcb_sc_off} + {sc_saved_rip}], rax + jmp __relibc_internal_sigentry + 2: + ", + out("rax") _, + tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), + sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), + ); +} diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index a1f3189c09..0a864aa87a 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -36,6 +36,7 @@ pub mod auxv_defs; pub mod signal; pub mod sync; +pub mod sys; pub mod thread; pub type Tcb = GenericTcb; diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 0eeaf73581..2cb8da5329 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -73,7 +73,9 @@ unsafe fn inner(stack: &mut SigStack) { }; let handler = match sigaction.kind { - SigactionKind::Ignore => unreachable!(), + SigactionKind::Ignore => { + panic!("ctl {:x?} signal {}", os.control, stack.sig_num) + } SigactionKind::Default => { syscall::exit(stack.sig_num << 8); unreachable!(); @@ -95,8 +97,10 @@ unsafe fn inner(stack: &mut SigStack) { let sig_group = stack.sig_num / 32; - let prev_w0 = os.control.word[0].fetch_add(sigallow_inside_lo.wrapping_sub(prev_sigallow_lo), Ordering::Relaxed); - let prev_w1 = os.control.word[1].fetch_add(sigallow_inside_hi.wrapping_sub(prev_sigallow_hi), Ordering::Relaxed); + //let _ = syscall::write(1, &alloc::format!("WORD0 {:x?}\n", os.control.word).as_bytes()); + let prev_w0 = os.control.word[0].fetch_add((sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32), Ordering::Relaxed); + let prev_w1 = os.control.word[1].fetch_add((sigallow_inside_hi << 32).wrapping_sub(prev_sigallow_hi << 32), Ordering::Relaxed); + //let _ = syscall::write(1, &alloc::format!("WORD1 {:x?}\n", os.control.word).as_bytes()); // TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first? @@ -117,8 +121,10 @@ unsafe fn inner(stack: &mut SigStack) { core::sync::atomic::compiler_fence(Ordering::Acquire); // Update allowset again. - let prev_w0 = os.control.word[0].fetch_add(prev_sigallow_lo.wrapping_sub(sigallow_inside_lo), Ordering::Relaxed); - let prev_w1 = os.control.word[1].fetch_add(prev_sigallow_hi.wrapping_sub(sigallow_inside_hi), Ordering::Relaxed); + //let _ = syscall::write(1, &alloc::format!("WORD2 {:x?}\n", os.control.word).as_bytes()); + let prev_w0 = os.control.word[0].fetch_add((prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32), Ordering::Relaxed); + let prev_w1 = os.control.word[1].fetch_add((prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32), Ordering::Relaxed); + //let _ = syscall::write(1, &alloc::format!("WORD3 {:x?}\n", os.control.word).as_bytes()); // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered // here? And would it be possible to tail-call-optimize that? @@ -167,13 +173,14 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option u32 let mut can_raise = 0; let mut cant_raise = 0; + //let _ = syscall::write(1, &alloc::format!("OLDWORD {:x?}\n", ctl.word).as_bytes()); for i in 0..2 { - let pending_bits = words[i] & 0xffff_ffff; let old_allow_bits = words[i] & 0xffff_ffff_0000_0000; let new_allow_bits = u64::from(!op(!((old_allow_bits >> 32) as u32), i == 1)) << 32; ctl.word[i].fetch_add(new_allow_bits.wrapping_sub(old_allow_bits), Ordering::Relaxed); } + //let _ = syscall::write(1, &alloc::format!("NEWWORD {:x?}\n", ctl.word).as_bytes()); // TODO: Prioritize cant_raise realtime signals? diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs new file mode 100644 index 0000000000..e9ec7383a8 --- /dev/null +++ b/redox-rt/src/sys.rs @@ -0,0 +1,35 @@ +use syscall::error::{Result, Error, EINTR}; + +use crate::arch::manually_enter_trampoline; +use crate::signal::tmp_disable_signals; + +// TODO: uninitialized memory? +#[inline] +pub fn posix_read(fd: usize, buf: &mut [u8]) -> Result { + loop { + let res = syscall::read(fd, buf); + + if res == Err(Error::new(EINTR)) { + unsafe { + manually_enter_trampoline(); + } + } + + return res; + } +} +#[inline] +pub fn posix_write(fd: usize, buf: &[u8]) -> Result { + loop { + let res = syscall::write(fd, buf); + + if res == Err(Error::new(EINTR)) { + unsafe { + manually_enter_trampoline(); + } + } + + return res; + + } +} diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 821efb0bb0..7001c07d72 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -1,5 +1,6 @@ use core::{slice, str}; +use redox_rt::sys::{posix_read, posix_write}; use syscall::{Error, Result, WaitFlags, EMFILE}; use crate::{ @@ -147,7 +148,7 @@ pub unsafe extern "C" fn redox_dup2_v1( } #[no_mangle] pub unsafe extern "C" fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult { - Error::mux(syscall::read( + Error::mux(posix_read( fd, slice::from_raw_parts_mut(dst_base, dst_len), )) @@ -158,7 +159,7 @@ pub unsafe extern "C" fn redox_write_v1( src_base: *const u8, src_len: usize, ) -> RawResult { - Error::mux(syscall::write(fd, slice::from_raw_parts(src_base, src_len))) + Error::mux(posix_write(fd, slice::from_raw_parts(src_base, src_len))) } #[no_mangle] pub unsafe extern "C" fn redox_fsync_v1(fd: usize) -> RawResult { diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index dae77e6d43..83a5cbbe1b 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -10,7 +10,7 @@ use crate::{ fs::File, header::{ dirent::dirent, - errno::{EBADR, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS, EPERM, ERANGE}, + errno::{EBADF, EBADFD, EBADR, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS, EPERM, ERANGE}, fcntl, limits, sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE}, sys_random, @@ -824,7 +824,8 @@ impl Pal for Sys { } fn read(fd: c_int, buf: &mut [u8]) -> Result { - Ok(syscall::read(fd as usize, buf)? as ssize_t) + let fd = usize::try_from(fd).map_err(|_| Errno(EBADF))?; + Ok(redox_rt::sys::posix_read(fd, buf)? as ssize_t) } fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result { unsafe { @@ -1124,7 +1125,8 @@ impl Pal for Sys { } fn write(fd: c_int, buf: &[u8]) -> Result { - Ok(syscall::write(fd as usize, buf)? as ssize_t) + let fd = usize::try_from(fd).map_err(|_| Errno(EBADFD))?; + Ok(redox_rt::sys::posix_write(fd, buf)? as ssize_t) } fn pwrite(fd: c_int, buf: &[u8], offset: off_t) -> Result { unsafe { From 126daaa186aae3e1372e0a08162c81954f9190f4 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 30 Jun 2024 15:18:22 +0200 Subject: [PATCH 46/67] Improve i686 trampoline and fix PIC. --- redox-rt/src/arch/i686.rs | 33 ++++++++++++++++++++++++++------- redox-rt/src/arch/x86_64.rs | 9 ++++----- redox-rt/src/signal.rs | 10 +++++++++- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 07d8ae05b7..d8a6ced45a 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -1,9 +1,10 @@ use core::mem::offset_of; +use core::sync::atomic::Ordering; use syscall::*; use crate::proc::{fork_inner, FdGuard}; -use crate::signal::{inner_fastcall, RtSigarea, SigStack}; +use crate::signal::{inner_fastcall, PROC_CONTROL_STRUCT, RtSigarea, SigStack}; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 31; @@ -18,7 +19,6 @@ pub struct SigArea { pub tmp_esp: usize, pub tmp_eax: usize, pub tmp_edx: usize, - pub onstack: u64, pub disable_signals_depth: u64, } #[derive(Debug, Default)] @@ -144,7 +144,10 @@ asmfunction!(__relibc_internal_sigentry: [" add eax, 32 2: and esp, -{STACK_ALIGN} - bt gs:[{tcb_sa_off} + {sa_onstack}], eax + + mov edx, eax + add edx, edx + bt dword ptr [{pctl} + {pctl_off_actions} + edx * 8 + 4], 28 jnc 4f mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}] @@ -209,15 +212,14 @@ __relibc_internal_sigentry_crit_second: sa_tmp_edx = const offset_of!(SigArea, tmp_edx), sa_altstack_top = const offset_of!(SigArea, altstack_top), sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom), - sa_onstack = const offset_of!(SigArea, onstack), sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg), sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), sc_word = const offset_of!(Sigcontrol, word), tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch), tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), - SIGW0_PENDING_MASK = const !( - SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2 - ), + pctl_off_actions = const offset_of!(SigProcControl, actions), + pctl = sym PROC_CONTROL_STRUCT, + SIGW0_PENDING_MASK = const !0, SIGW1_PENDING_MASK = const !0, STACK_ALIGN = const 16, ]); @@ -253,3 +255,20 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { stack.regs.eip = area.tmp_eip; } } +pub unsafe fn manually_enter_trampoline() { + let c = &crate::Tcb::current().unwrap().os_specific.control; + c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? + + core::arch::asm!(" + call 2f + jmp 3f + 2: + pop dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}] + jmp __relibc_internal_sigentry + 3: + ", + tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), + sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), + ); +} diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 67a3600c65..4a921169c9 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,5 +1,5 @@ use core::mem::offset_of; -use core::sync::atomic::AtomicU8; +use core::sync::atomic::{AtomicU8, Ordering}; use syscall::data::{Sigcontrol, SigProcControl}; use syscall::error::*; @@ -360,10 +360,9 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(1); // FIXME pub unsafe fn manually_enter_trampoline() { - let _g = tmp_disable_signals(); - - let a = &Tcb::current().unwrap().os_specific.control; - a.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? + let c = &Tcb::current().unwrap().os_specific.control; + c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release); + c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86? core::arch::asm!(" lea rax, [rip + 2f] diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 2cb8da5329..5fff5ae39a 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -111,10 +111,13 @@ unsafe fn inner(stack: &mut SigStack) { // Call handler, either sa_handler or sa_siginfo depending on flag. if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction { + //let _ = syscall::write(1, alloc::format!("SIGACTION {:p}\n", sigaction).as_bytes()); sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut()); } else if let Some(handler) = handler.handler { + //let _ = syscall::write(1, alloc::format!("HANDLER {:p}\n", handler).as_bytes()); handler(stack.sig_num as c_int); } + //let _ = syscall::write(1, alloc::format!("RETURNED HANDLER\n").as_bytes()); // Disable signals while we modify the sigmask again control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); @@ -129,6 +132,8 @@ unsafe fn inner(stack: &mut SigStack) { // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered // here? And would it be possible to tail-call-optimize that? + //let _ = syscall::write(1, alloc::format!("will return to {:x?}\n", stack.regs.eip).as_bytes()); + // And re-enable them again control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release); core::sync::atomic::compiler_fence(Ordering::Acquire); @@ -388,7 +393,10 @@ pub fn setup_sighandler(area: &RtSigarea) { // equivalent to not using any altstack at all (the default). arch.altstack_top = usize::MAX; arch.altstack_bottom = 0; - arch.pctl = core::ptr::addr_of!(PROC_CONTROL_STRUCT) as usize; + #[cfg(not(target_arch = "x86"))] + { + arch.pctl = core::ptr::addr_of!(PROC_CONTROL_STRUCT) as usize; + } } #[cfg(target_arch = "x86_64")] From c0e079132a5495e6526748d6b4c6e33f4d75ddb5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 30 Jun 2024 16:19:31 +0200 Subject: [PATCH 47/67] AND rather than set sigmask inside signal. --- redox-rt/src/signal.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 5fff5ae39a..fb3b4b0958 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -83,19 +83,17 @@ unsafe fn inner(stack: &mut SigStack) { SigactionKind::Handled { handler } => handler, }; - let mut sigallow_inside = !sigaction.mask; - if !sigaction.flags.contains(SigactionFlags::NODEFER) { - sigallow_inside &= !sig_bit(stack.sig_num); - } - let sigallow_inside_lo = sigallow_inside & 0xffff_ffff; - let sigallow_inside_hi = sigallow_inside >> 32; - // Set sigmask to sa_mask and unmark the signal as pending. let prev_sigallow_lo = os.control.word[0].load(Ordering::Relaxed) >> 32; let prev_sigallow_hi = os.control.word[1].load(Ordering::Relaxed) >> 32; let prev_sigallow = prev_sigallow_lo | (prev_sigallow_hi << 32); - let sig_group = stack.sig_num / 32; + let mut sigallow_inside = !sigaction.mask & prev_sigallow; + if !sigaction.flags.contains(SigactionFlags::NODEFER) { + sigallow_inside &= !sig_bit(stack.sig_num); + } + let sigallow_inside_lo = sigallow_inside & 0xffff_ffff; + let sigallow_inside_hi = sigallow_inside >> 32; //let _ = syscall::write(1, &alloc::format!("WORD0 {:x?}\n", os.control.word).as_bytes()); let prev_w0 = os.control.word[0].fetch_add((sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32), Ordering::Relaxed); @@ -125,6 +123,7 @@ unsafe fn inner(stack: &mut SigStack) { // Update allowset again. //let _ = syscall::write(1, &alloc::format!("WORD2 {:x?}\n", os.control.word).as_bytes()); + let prev_w0 = os.control.word[0].fetch_add((prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32), Ordering::Relaxed); let prev_w1 = os.control.word[1].fetch_add((prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32), Ordering::Relaxed); //let _ = syscall::write(1, &alloc::format!("WORD3 {:x?}\n", os.control.word).as_bytes()); From a446ac194589fbf29c05a7bff6854d58f317b942 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 1 Jul 2024 13:06:00 +0200 Subject: [PATCH 48/67] Fix (rare) stack corruption on x86_64. --- redox-rt/src/arch/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 4a921169c9..9462313dde 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -28,7 +28,7 @@ pub struct SigArea { pub pctl: usize, // TODO: find out how to correctly reference that static } -#[repr(C, align(64))] +#[repr(C)] #[derive(Debug, Default)] pub struct ArchIntRegs { _pad: [usize; 2], // ensure size is divisible by 32 From 6a3d247a906ce943395c3d0e3c47c660548c5d17 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 1 Jul 2024 13:06:29 +0200 Subject: [PATCH 49/67] Clear the signal bit in the handler. --- redox-rt/src/signal.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index fb3b4b0958..ccb64d453e 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -52,6 +52,11 @@ pub struct SigStack { unsafe fn inner(stack: &mut SigStack) { let os = &Tcb::current().unwrap().os_specific; + let sig_idx = stack.sig_num; + + // Commenting out this line will stress test how the signal code responds to 'interrupt spraying'. + os.control.word[sig_idx / 32].fetch_and(!(1 << (sig_idx % 32)), Ordering::Relaxed); + // asm counts from 0 stack.sig_num += 1; From 6d5d0eb61e72afebf4df7edd55b854c546974cd3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 1 Jul 2024 17:35:19 +0200 Subject: [PATCH 50/67] Set initial sigactions to SIG_DFL and correct bits. --- redox-rt/src/signal.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index ccb64d453e..af56b33473 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -389,6 +389,17 @@ const fn sig_bit(sig: usize) -> u64 { pub fn setup_sighandler(area: &RtSigarea) { { let mut sigactions = SIGACTIONS_LOCK.lock(); + for (sig_idx, action) in PROC_CONTROL_STRUCT.actions.iter().enumerate() { + let sig = sig_idx + 1; + let bits = if matches!(sig, SIGTSTP | SIGTTIN | SIGTTOU) { + SigactionFlags::SIG_SPECIFIC + } else if matches!(sig, SIGCHLD | SIGURG | SIGWINCH) { + SigactionFlags::IGNORED + } else { + SigactionFlags::empty() + }; + action.first.store((u64::from(bits.bits()) << 32) | default_handler as u64, Ordering::Relaxed); + } } let arch = unsafe { &mut *area.arch.get() }; { From c639fd37bab12c7004eb40a4ae4ded4ac71a92e2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 1 Jul 2024 19:52:48 +0200 Subject: [PATCH 51/67] Implement sigaltstack. --- redox-rt/src/arch/i686.rs | 8 +++++ redox-rt/src/arch/x86_64.rs | 9 ++++++ redox-rt/src/signal.rs | 53 +++++++++++++++++++++++++++++++++- src/header/signal/mod.rs | 13 ++------- src/platform/linux/signal.rs | 9 ++++-- src/platform/pal/signal.rs | 2 +- src/platform/redox/libredox.rs | 5 +--- src/platform/redox/signal.rs | 51 +++++++++++++++++++++++++++++--- src/pthread/mod.rs | 4 +-- 9 files changed, 130 insertions(+), 24 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index d8a6ced45a..fce06454c1 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -272,3 +272,11 @@ pub unsafe fn manually_enter_trampoline() { sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), ); } +/// Get current stack pointer, weak granularity guarantees. +pub fn current_sp() -> usize { + let sp: usize; + unsafe { + core::arch::asm!("mov {}, esp", out(reg) sp); + } + sp +} diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 9462313dde..fc425eecf5 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -375,3 +375,12 @@ pub unsafe fn manually_enter_trampoline() { sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), ); } + +/// Get current stack pointer, weak granularity guarantees. +pub fn current_sp() -> usize { + let sp: usize; + unsafe { + core::arch::asm!("mov {}, rsp", out(reg) sp); + } + sp +} diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index af56b33473..313519cff9 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; use core::sync::atomic::{AtomicUsize, Ordering}; -use syscall::{RawAction, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; +use syscall::{RawAction, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64}; use crate::{arch::*, Tcb}; @@ -213,6 +213,7 @@ pub struct Sigaction { pub mask: u64, pub flags: SigactionFlags, } + impl Sigaction { fn ip(&self) -> usize { unsafe { @@ -446,3 +447,53 @@ pub fn current_setsighandler_struct() -> SetSighandlerData { proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, } } + +#[derive(Clone, Copy, Default, PartialEq)] +pub enum Sigaltstack { + #[default] + Disabled, + + Enabled { onstack: bool, base: *mut (), size: usize }, +} +pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigaltstack>) -> Result<()> { + let _g = tmp_disable_signals(); + let tcb = &mut *Tcb::current().unwrap().os_specific.arch.get(); + + let old = if tcb.altstack_bottom == 0 && tcb.altstack_top == usize::MAX { + Sigaltstack::Disabled + } else { + Sigaltstack::Enabled { + base: tcb.altstack_bottom as *mut (), + size: tcb.altstack_top - tcb.altstack_bottom, + onstack: (tcb.altstack_bottom..tcb.altstack_top).contains(&crate::arch::current_sp()), + } + }; + + if matches!(old, Sigaltstack::Enabled { onstack: true, .. }) && new != Some(&old) { + return Err(Error::new(EPERM)); + } + + if let Some(old_out) = old_out { + *old_out = old; + } + if let Some(new) = new { + match *new { + Sigaltstack::Disabled => { + tcb.altstack_bottom = 0; + tcb.altstack_top = usize::MAX; + } + Sigaltstack::Enabled { onstack: true, .. } => return Err(Error::new(EINVAL)), + Sigaltstack::Enabled { base, size, onstack: false } => { + if size < MIN_SIGALTSTACK_SIZE { + return Err(Error::new(ENOMEM)); + } + + tcb.altstack_bottom = base as usize; + tcb.altstack_top = base as usize + size; + } + } + } + Ok(()) +} + +pub const MIN_SIGALTSTACK_SIZE: usize = 8192; diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index c015f3f9cb..3b15084c23 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -127,16 +127,9 @@ pub unsafe extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - if !ss.is_null() { - if (*ss).ss_flags != SS_DISABLE as c_int { - return errno::EINVAL; - } - if (*ss).ss_size < MINSIGSTKSZ { - return errno::ENOMEM; - } - } - - Sys::sigaltstack(ss, old_ss) + Sys::sigaltstack(ss.as_ref(), old_ss.as_mut()) + .map(|()| 0) + .or_minus_one_errno() } #[no_mangle] diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 0fbc8493e9..8762af6a6d 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -65,8 +65,13 @@ impl PalSignal for Sys { .map(|_| ()) } - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - e(syscall!(SIGALTSTACK, ss, old_ss)) as c_int + unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno> { + e_raw(syscall!( + SIGALTSTACK, + ss.map_or_else(core::ptr::null, |x| x as *const _), + old_ss.map_or_else(core::ptr::null_mut, |x| x as *mut _) + )) + .map(|_| ()) } unsafe fn sigpending(set: *mut sigset_t) -> c_int { diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index d85c35d955..d478ec16c8 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -25,7 +25,7 @@ pub trait PalSignal: Pal { oact: Option<&mut sigaction>, ) -> Result<(), Errno>; - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int; + unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno>; unsafe fn sigpending(set: *mut sigset_t) -> c_int; diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 7001c07d72..cdcf546110 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -148,10 +148,7 @@ pub unsafe extern "C" fn redox_dup2_v1( } #[no_mangle] pub unsafe extern "C" fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult { - Error::mux(posix_read( - fd, - slice::from_raw_parts_mut(dst_base, dst_len), - )) + Error::mux(posix_read(fd, slice::from_raw_parts_mut(dst_base, dst_len))) } #[no_mangle] pub unsafe extern "C" fn redox_write_v1( diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index de8d1ee2b3..b495c590fd 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,5 +1,5 @@ use core::mem; -use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, SignalHandler}; +use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler}; use syscall::{self, Result}; use super::{ @@ -11,7 +11,7 @@ use crate::{ errno::{EINVAL, ENOSYS}, signal::{ sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, - SIG_SETMASK, SIG_UNBLOCK, + SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK, }, sys_time::{itimerval, ITIMER_REAL}, time::timespec, @@ -176,8 +176,51 @@ impl PalSignal for Sys { Ok(()) } - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - unimplemented!() + unsafe fn sigaltstack( + new_c: Option<&stack_t>, + old_c: Option<&mut stack_t>, + ) -> Result<(), Errno> { + let new = new_c + .map(|c_stack| { + let flags = usize::try_from(c_stack.ss_flags).map_err(|_| Errno(EINVAL))?; + if flags != flags & (SS_DISABLE | SS_ONSTACK) { + return Err(Errno(EINVAL)); + } + + Ok(if flags & SS_DISABLE == SS_DISABLE { + Sigaltstack::Disabled + } else { + Sigaltstack::Enabled { + onstack: false, + base: c_stack.ss_sp.cast(), + size: c_stack.ss_size, + } + }) + }) + .transpose()?; + + let mut old = old_c.as_ref().map(|_| Sigaltstack::default()); + redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut())?; + + if let (Some(old_c_stack), Some(old)) = (old_c, old) { + *old_c_stack = match old { + Sigaltstack::Disabled => stack_t { + ss_sp: core::ptr::null_mut(), + ss_size: 0, + ss_flags: SS_DISABLE.try_into().unwrap(), + }, + Sigaltstack::Enabled { + onstack, + base, + size, + } => stack_t { + ss_sp: base.cast(), + ss_size: size, + ss_flags: SS_ONSTACK.try_into().unwrap(), + }, + }; + } + Ok(()) } unsafe fn sigpending(set: *mut sigset_t) -> c_int { diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index f6751cb510..cfc56dd485 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -139,8 +139,8 @@ pub(crate) unsafe fn create( let mut current_sigmask = 0_u64; #[cfg(target_os = "redox")] { - current_sigmask = redox_rt::signal::get_sigmask() - .expect("failed to obtain sigprocmask for caller"); + current_sigmask = + redox_rt::signal::get_sigmask().expect("failed to obtain sigprocmask for caller"); } // Create a locked mutex, unlocked by the thread after it has started. From 8298417dee977af9bb1c66cb8ec376084280fa2b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 1 Jul 2024 20:10:00 +0200 Subject: [PATCH 52/67] Implement sigpending on Redox. --- redox-rt/src/signal.rs | 9 +++++++++ src/header/signal/mod.rs | 8 ++++++-- src/platform/linux/signal.rs | 11 +++++++++-- src/platform/pal/signal.rs | 2 +- src/platform/redox/signal.rs | 6 +++--- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 313519cff9..bd174fe6e8 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -497,3 +497,12 @@ pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigalt } pub const MIN_SIGALTSTACK_SIZE: usize = 8192; + +pub fn currently_pending() -> u64 { + let control = &unsafe { Tcb::current().unwrap() }.os_specific.control; + let w0 = control.word[0].load(Ordering::Relaxed); + let w1 = control.word[0].load(Ordering::Relaxed); + let pending_blocked_lo = w0 & !(w0 >> 32); + let pending_unblocked_hi = w1 & !(w0 >> 32); + pending_blocked_lo | (pending_unblocked_hi << 32) +} diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index 3b15084c23..ec6241de54 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -7,11 +7,13 @@ use cbitset::BitSet; use crate::{ header::{errno, time::timespec}, platform::{self, types::*, Pal, PalSignal, Sys}, - pthread::{self, ResultExt}, + pthread::{self, Errno, ResultExt}, }; pub use self::sys::*; +use super::errno::EFAULT; + #[cfg(target_os = "linux")] #[path = "linux.rs"] pub mod sys; @@ -241,7 +243,9 @@ pub unsafe extern "C" fn sigpause(sig: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn sigpending(set: *mut sigset_t) -> c_int { - Sys::sigpending(set) + (|| Sys::sigpending(set.as_mut().ok_or(Errno(EFAULT))?))() + .map(|()| 0) + .or_minus_one_errno() } const BELOW_SIGRTMIN_MASK: sigset_t = (1 << SIGRTMIN) - 1; diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 8762af6a6d..c92cd2ff01 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -74,8 +74,15 @@ impl PalSignal for Sys { .map(|_| ()) } - unsafe fn sigpending(set: *mut sigset_t) -> c_int { - e(syscall!(RT_SIGPENDING, set, NSIG / 8)) as c_int + fn sigpending(set: &mut sigset_t) -> Result<(), Errno> { + e_raw(unsafe { + syscall!( + RT_SIGPENDING, + set as *mut sigset_t as usize, + mem::size_of::() + ) + }) + .map(|_| ()) } fn sigprocmask( diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index d478ec16c8..a802270fa0 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -27,7 +27,7 @@ pub trait PalSignal: Pal { unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno>; - unsafe fn sigpending(set: *mut sigset_t) -> c_int; + fn sigpending(set: &mut sigset_t) -> Result<(), Errno>; fn sigprocmask( how: c_int, diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index b495c590fd..dc5e816ff2 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -223,9 +223,9 @@ impl PalSignal for Sys { Ok(()) } - unsafe fn sigpending(set: *mut sigset_t) -> c_int { - ERRNO.set(ENOSYS); - -1 + fn sigpending(set: &mut sigset_t) -> Result<(), Errno> { + *set = redox_rt::signal::currently_pending(); + Ok(()) } fn sigprocmask( From c9d22e484bc89e08828c5bffeab5677f4c8c8f57 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jul 2024 11:53:29 +0200 Subject: [PATCH 53/67] Write draft aarch64 trampoline that compiles. --- redox-rt/src/arch/aarch64.rs | 185 ++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 5 deletions(-) diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index be9afcc0cc..fc69eec092 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -1,19 +1,68 @@ +use core::mem::offset_of; + +use syscall::data::*; use syscall::error::*; use crate::proc::{fork_inner, FdGuard}; -use crate::signal::inner_c; +use crate::signal::SigStack; +use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT}; +use crate::Tcb; // Setup a stack starting from the very end of the address space, and then growing downwards. pub(crate) const STACK_TOP: usize = 1 << 47; pub(crate) const STACK_SIZE: usize = 1024 * 1024; #[derive(Debug, Default)] +#[repr(C)] pub struct SigArea { pub altstack_top: usize, pub altstack_bottom: usize, - pub tmp: usize, + pub tmp_x1_x2: [usize; 2], + pub tmp_x3_x4: [usize; 2], + pub tmp_sp: usize, pub onstack: u64, pub disable_signals_depth: u64, + pub pctl: usize, // TODO: remove +} +#[repr(C)] +#[derive(Debug, Default)] +pub struct ArchIntRegs { + pub x30: usize, + pub x29: usize, + pub x28: usize, + pub x27: usize, + pub x26: usize, + pub x25: usize, + pub x24: usize, + pub x23: usize, + pub x22: usize, + pub x21: usize, + pub x20: usize, + pub x19: usize, + pub x18: usize, + pub x17: usize, + pub x16: usize, + pub x15: usize, + pub x14: usize, + pub x13: usize, + pub x12: usize, + pub x11: usize, + pub x10: usize, + pub x9: usize, + pub x8: usize, + pub x7: usize, + pub x6: usize, + pub x5: usize, + pub x4: usize, + pub x3: usize, + pub x2: usize, + pub x1: usize, + + pub sp: usize, + pub nzcv: usize, // user-accessible PSTATE bits + + pub pc: usize, + pub x0: usize, } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS @@ -91,12 +140,112 @@ asmfunction!(__relibc_internal_fork_ret: [" "] <= [child_hook = sym child_hook]); asmfunction!(__relibc_internal_sigentry: [" + // old pc and x0 are saved in the sigcontrol struct + mrs x0, tpidr_el0 // ABI ptr + ldr x0, [x0] // TCB ptr + + // save x1-x3 and sp + stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}] + stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}] + mov x1, sp + str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}] + + sub x1, x1, 128 + and x1, x1, -16 + mov sp, x1 + + ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}] + + // load x1 and x2 with each word (tearing between x1 and x2 can occur) + // acquire ordering + add x2, x0, #{tcb_sc_off} + {sc_word} + ldaxp x1, x2, [x2] + + // reduce them by ANDing the upper and lower 32 bits + and x1, x1, x1, lsr #32 // put result in lo half + and x2, x2, x2, lsl #32 // put result in hi half + orr x1, x1, x2 // combine them into the set of pending unblocked + + // count trailing zeroes, to find signal bit + rbit x1, x1 + clz x1, x1 + mov x2, #32 + sub x1, x2, x1 + + // TODO: NOT ATOMIC! + add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action + ldxp x2, x3, [x2] + + // skip sigaltstack step if SA_ONSTACK is clear + // tbz x2, #57, 2f +2: + ldr x2, [x0, #{tcb_sc_off} + {sc_saved_pc}] + ldr x3, [x0, #{tcb_sc_off} + {sc_saved_x0}] + stp x2, x3, [sp], #-16 + + ldr x2, [x0, #{tcb_sa_off} + {sa_tmp_sp}] + mrs x3, nzcv + stp x2, x3, [sp], #-16 + + ldp x2, x3, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}] + stp x2, x3, [sp], #-16 + ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}] + stp x4, x3, [sp], #-16 + stp x6, x5, [sp], #-16 + stp x8, x7, [sp], #-16 + stp x10, x9, [sp], #-16 + stp x12, x11, [sp], #-16 + stp x14, x13, [sp], #-16 + stp x16, x15, [sp], #-16 + stp x18, x17, [sp], #-16 + stp x20, x19, [sp], #-16 + stp x22, x21, [sp], #-16 + stp x24, x23, [sp], #-16 + stp x26, x25, [sp], #-16 + stp x28, x27, [sp], #-16 + stp x30, x29, [sp], #-16 + mov x0, sp bl {inner} - // FIXME - b . -"] <= [inner = sym inner_c]); + ldp x30, x29, [sp], #16 + ldp x28, x27, [sp], #16 + ldp x26, x25, [sp], #16 + ldp x24, x23, [sp], #16 + ldp x22, x21, [sp], #16 + ldp x20, x19, [sp], #16 + ldp x18, x17, [sp], #16 + ldp x16, x15, [sp], #16 + ldp x14, x13, [sp], #16 + ldp x12, x11, [sp], #16 + ldp x10, x9, [sp], #16 + ldp x8, x7, [sp], #16 + ldp x6, x5, [sp], #16 + ldp x4, x3, [sp], #16 + ldp x2, x1, [sp], #16 + ldr x0, [sp, #8] + msr nzcv, x0 + + // x18 is reserved by ABI as 'platform register', so clobbering it should be safe. + mov x18, sp + ldr x0, [sp], #16 + mov sp, x0 + mov x0, x18 + + ldp x18, x0, [x0] + br x18 +"] <= [ + tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)), + tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)), + sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2), + sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4), + sa_tmp_sp = const offset_of!(SigArea, tmp_sp), + sa_pctl = const offset_of!(SigArea, pctl), + sc_saved_pc = const offset_of!(Sigcontrol, saved_ip), + sc_saved_x0 = const offset_of!(Sigcontrol, saved_archdep_reg), + sc_word = const offset_of!(Sigcontrol, word), + inner = sym inner_c, +]); asmfunction!(__relibc_internal_rlct_clone_ret: [" # Load registers @@ -109,3 +258,29 @@ asmfunction!(__relibc_internal_rlct_clone_ret: [" ret "] <= []); + +pub fn current_sp() -> usize { + let sp: usize; + unsafe { + core::arch::asm!("mov {}, sp", out(reg) sp); + } + sp +} + +pub unsafe fn manually_enter_trampoline() { + let ctl = &Tcb::current().unwrap().os_specific.control; + + ctl.saved_archdep_reg.set(0); + let ip_location = &ctl.saved_ip as *const _ as usize; + + core::arch::asm!(" + bl 2f + b 3f + 2: + ldr lr, [x0] + b __relibc_internal_sigentry + 3: + ", inout("x0") ip_location => _, out("lr") _); +} + +pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) {} From 5277f2f64012d9ad8777f41c8fa112f100b84aae Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jul 2024 12:19:41 +0200 Subject: [PATCH 54/67] Fix typo in currently_pending. --- redox-rt/src/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index bd174fe6e8..1d51f16286 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -501,7 +501,7 @@ pub const MIN_SIGALTSTACK_SIZE: usize = 8192; pub fn currently_pending() -> u64 { let control = &unsafe { Tcb::current().unwrap() }.os_specific.control; let w0 = control.word[0].load(Ordering::Relaxed); - let w1 = control.word[0].load(Ordering::Relaxed); + let w1 = control.word[1].load(Ordering::Relaxed); let pending_blocked_lo = w0 & !(w0 >> 32); let pending_unblocked_hi = w1 & !(w0 >> 32); pending_blocked_lo | (pending_unblocked_hi << 32) From 618643b2997e22b7730d2f66450c883422709c0e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jul 2024 12:28:58 +0200 Subject: [PATCH 55/67] Work around aarch64 bootstrap crash. --- redox-rt/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 0a864aa87a..8112c9b433 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -95,6 +95,10 @@ pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) { /// Initialize redox-rt in situations where relibc is not used pub fn initialize_freestanding() { + // TODO: This code is a hack! Integrate the ld_so TCB code into generic-rt, and then use that + // (this function will need pointers to the ELF structs normally passed in auxvs), so the TCB + // is initialized properly. + // TODO: TLS let page = unsafe { &mut *(syscall::fmap(!0, &syscall::Map { @@ -108,7 +112,13 @@ pub fn initialize_freestanding() { page.tcb_len = syscall::PAGE_SIZE; page.tls_end = (page as *mut Tcb).cast(); + #[cfg(not(target_arch = "aarch64"))] unsafe { tcb_activate(page as *mut Tcb as usize, 0) } + #[cfg(target_arch = "aarch64")] + unsafe { + let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr); + core::arch::asm!("msr tpidr_el0, {}", in(reg) abi_ptr); + } } From 5916b94707eaf99f2e1ca73ae522141f3d31b063 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jul 2024 16:54:08 +0200 Subject: [PATCH 56/67] Fix aarch64 fork_ret. --- redox-rt/src/arch/aarch64.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index fc69eec092..2a370f175a 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -116,7 +116,13 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: [" mov x0, sp bl {fork_impl} - add sp, sp, #128 + add sp, sp, #32 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x29, x30, [sp], #16 ret "] <= [fork_impl = sym fork_impl]); From 2fe1d614f81af1df0a82595a225f6cc79f2c0cad Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 2 Jul 2024 17:48:46 +0200 Subject: [PATCH 57/67] Fix aarch64 EINTR handler. --- redox-rt/src/arch/aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs index 2a370f175a..e4a5e8b54c 100644 --- a/redox-rt/src/arch/aarch64.rs +++ b/redox-rt/src/arch/aarch64.rs @@ -283,7 +283,7 @@ pub unsafe fn manually_enter_trampoline() { bl 2f b 3f 2: - ldr lr, [x0] + str lr, [x0] b __relibc_internal_sigentry 3: ", inout("x0") ip_location => _, out("lr") _); From 4ee878c4748551896ba3d5b256fb6af55cc2a844 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 3 Jul 2024 13:48:59 +0200 Subject: [PATCH 58/67] Always use fxsave, store 'YMM_UPPER' manually. --- redox-rt/src/arch/i686.rs | 41 +++++++------- redox-rt/src/arch/x86_64.rs | 110 +++++++++++++++++++++--------------- redox-rt/src/signal.rs | 34 ++++------- 3 files changed, 94 insertions(+), 91 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index fce06454c1..80296b835a 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -22,21 +22,24 @@ pub struct SigArea { pub disable_signals_depth: u64, } #[derive(Debug, Default)] -#[repr(C)] +#[repr(C, align(16))] pub struct ArchIntRegs { - pub _pad: [usize; 2], // make size divisible by 16 + pub fxsave: [u16; 29], - pub ebp: usize, - pub esi: usize, - pub edi: usize, - pub ebx: usize, - pub eax: usize, - pub ecx: usize, - pub edx: usize, + // ensure fxsave region is 16 byte aligned + pub _pad: [usize; 2], // fxsave "available" +0 - pub eflags: usize, - pub eip: usize, - pub esp: usize, + pub ebp: usize, // fxsave "available" +8 + pub esi: usize, // avail +12 + pub edi: usize, // avail +16 + pub ebx: usize, // avail +20 + pub eax: usize, // avail +24 + pub ecx: usize, // avail +28 + pub edx: usize, // avail +32 + + pub eflags: usize, // avail +36 + pub eip: usize, // avail +40 + pub esp: usize, // avail +44 } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS @@ -131,14 +134,12 @@ asmfunction!(__relibc_internal_sigentry: [" // Read first signal word mov eax, gs:[{tcb_sc_off} + {sc_word}] and eax, gs:[{tcb_sc_off} + {sc_word} + 4] - and eax, {SIGW0_PENDING_MASK} bsf eax, eax jnz 2f // Read second signal word mov eax, gs:[{tcb_sc_off} + {sc_word} + 8] and eax, gs:[{tcb_sc_off} + {sc_word} + 12] - and eax, {SIGW1_PENDING_MASK} bsf eax, eax jz 7f add eax, 32 @@ -172,17 +173,17 @@ asmfunction!(__relibc_internal_sigentry: [" push esi push ebp - sub esp, 8 + sub esp, 2 * 4 + 29 * 16 + fxsave [esp] push eax - sub esp, 12 + 512 - fxsave [esp] + sub esp, 3 * 4 mov ecx, esp call {inner} - fxrstor [esp] - add esp, 512 + 12 + 4 + 8 + fxrstor [esp + 16] + add esp, 16 + 29 * 16 + 2 * 4 pop ebp pop esi @@ -219,8 +220,6 @@ __relibc_internal_sigentry_crit_second: tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control), pctl_off_actions = const offset_of!(SigProcControl, actions), pctl = sym PROC_CONTROL_STRUCT, - SIGW0_PENDING_MASK = const !0, - SIGW1_PENDING_MASK = const !0, STACK_ALIGN = const 16, ]); diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index fc425eecf5..0b3ffa68db 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -28,18 +28,18 @@ pub struct SigArea { pub pctl: usize, // TODO: find out how to correctly reference that static } -#[repr(C)] +#[repr(C, align(16))] #[derive(Debug, Default)] pub struct ArchIntRegs { - _pad: [usize; 2], // ensure size is divisible by 32 - - pub r15: usize, - pub r14: usize, - pub r13: usize, - pub r12: usize, - pub rbp: usize, - pub rbx: usize, - pub r11: usize, + pub ymm_upper: [u128; 16], + pub fxsave: [u128; 29], + pub r15: usize, // fxsave "available" +0 + pub r14: usize, // available +8 + pub r13: usize, // available +16 + pub r12: usize, // available +24 + pub rbp: usize, // available +32 + pub rbx: usize, // available +40 + pub r11: usize, // outside fxsave, and so on pub r10: usize, pub r9: usize, pub r8: usize, @@ -174,7 +174,6 @@ asmfunction!(__relibc_internal_sigentry: [" mov rdx, rax shr rdx, 32 and eax, edx - and eax, {SIGW0_PENDING_MASK} bsf eax, eax jnz 2f @@ -183,9 +182,8 @@ asmfunction!(__relibc_internal_sigentry: [" mov rdx, rax shr rdx, 32 and eax, edx - and eax, {SIGW1_PENDING_MASK} bsf eax, eax - jz 7f + jz 6f add eax, 32 2: sub rsp, {REDZONE_SIZE} @@ -238,35 +236,63 @@ asmfunction!(__relibc_internal_sigentry: [" push r13 push r14 push r15 - sub rsp, 16 - - push rax // selected signal - - sub rsp, 4096 + 24 - - cld - mov rdi, rsp - xor eax, eax - mov ecx, 4096 + 24 - rep stosb + sub rsp, (29 + 16) * 16 // fxsave region minus available bytes + fxsave64 [rsp + 16 * 16] // TODO: self-modifying? - cmp byte ptr [rip + {supports_xsave}], 0 - je 6f + cmp byte ptr [rip + {supports_avx}], 0 + je 5f - mov eax, 0xffffffff - mov edx, eax - xsave [rsp] + // Prefer vextractf128 over vextracti128 since the former only requires AVX version 1. + vextractf128 [rsp + 15 * 16], ymm0, 1 + vextractf128 [rsp + 14 * 16], ymm1, 1 + vextractf128 [rsp + 13 * 16], ymm2, 1 + vextractf128 [rsp + 12 * 16], ymm3, 1 + vextractf128 [rsp + 11 * 16], ymm4, 1 + vextractf128 [rsp + 10 * 16], ymm5, 1 + vextractf128 [rsp + 9 * 16], ymm6, 1 + vextractf128 [rsp + 8 * 16], ymm7, 1 + vextractf128 [rsp + 7 * 16], ymm8, 1 + vextractf128 [rsp + 6 * 16], ymm9, 1 + vextractf128 [rsp + 5 * 16], ymm10, 1 + vextractf128 [rsp + 4 * 16], ymm11, 1 + vextractf128 [rsp + 3 * 16], ymm12, 1 + vextractf128 [rsp + 2 * 16], ymm13, 1 + vextractf128 [rsp + 16], ymm14, 1 + vextractf128 [rsp], ymm15, 1 +5: + push rax // selected signal + sub rsp, 8 mov rdi, rsp call {inner} - mov eax, 0xffffffff - mov edx, eax - xrstor [rsp] + add rsp, 16 + + fxrstor64 [rsp] + + cmp byte ptr [rip + {supports_avx}], 0 + je 6f + + vinsertf128 ymm0, ymm0, [rsp + 15 * 16], 1 + vinsertf128 ymm1, ymm1, [rsp + 14 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 13 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 12 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 11 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 10 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 9 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 8 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 7 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 6 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 5 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 4 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 3 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 2 * 16], 1 + vinsertf128 ymm2, ymm2, [rsp + 16], 1 + vinsertf128 ymm2, ymm2, [rsp], 1 +6: + add rsp, (29 + 16) * 16 -5: - add rsp, 4096 + 32 + 16 pop r15 pop r14 pop r13 @@ -299,14 +325,6 @@ __relibc_internal_sigentry_crit_first: __relibc_internal_sigentry_crit_second: jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}] 6: - fxsave64 [rsp] - - mov rdi, rsp - call {inner} - - fxrstor64 [rsp] - jmp 5b -7: ud2 // Spurious signal "] <= [ @@ -325,11 +343,9 @@ __relibc_internal_sigentry_crit_second: pctl_off_actions = const offset_of!(SigProcControl, actions), //pctl = sym PROC_CONTROL_STRUCT, sa_off_pctl = const offset_of!(SigArea, pctl), - supports_xsave = sym SUPPORTS_XSAVE, - SIGW0_PENDING_MASK = const !0, - SIGW1_PENDING_MASK = const !0, + supports_avx = sym SUPPORTS_AVX, REDZONE_SIZE = const 128, - STACK_ALIGN = const 64, // if xsave is used + STACK_ALIGN = const 16, ]); extern "C" { @@ -357,7 +373,7 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) { } } -static SUPPORTS_XSAVE: AtomicU8 = AtomicU8::new(1); // FIXME +static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(1); // FIXME pub unsafe fn manually_enter_trampoline() { let c = &Tcb::current().unwrap().os_specific.control; diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 1d51f16286..f99f39ebce 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -12,39 +12,24 @@ use crate::sync::Mutex; static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); pub fn sighandler_function() -> usize { - //#[cfg(target_arch = "x86_64")] - // Check OSXSAVE bit // TODO: HWCAP? - /*if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 { - __relibc_internal_sigentry_xsave as usize - } else { - __relibc_internal_sigentry_fxsave as usize - }*/ - //#[cfg(any(target_arch = "x86", target_arch = "aarch64"))] - { - __relibc_internal_sigentry as usize - } + __relibc_internal_sigentry as usize } #[repr(C)] pub struct SigStack { - #[cfg(target_arch = "x86_64")] - fx: [u8; 4096], // 64 byte aligned + #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + _pad: [usize; 1], // pad to 16 bytes alignment #[cfg(target_arch = "x86")] - fx: [u8; 512], // 16 byte aligned - - #[cfg(target_arch = "x86_64")] - _pad: [usize; 3], // pad to 192 = 3 * 64 = 168 + 24 bytes - - #[cfg(target_arch = "x86")] - _pad: [usize; 3], // pad to 64 = 4 * 16 = 52 + 12 bytes + _pad: [usize; 3], // pad to 16 bytes alignment sig_num: usize, - // x86_64: 160 bytes - // i686: 48 bytes + // x86_64: 864 bytes + // i686: 512 bytes + // aarch64: 272 bytes (SIMD TODO) pub regs: ArchIntRegs, } @@ -261,6 +246,8 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction let _sigguard = tmp_disable_signals(); let ctl = current_sigctl(); + let _guard = SIGACTIONS_LOCK.lock(); + let action = &PROC_CONTROL_STRUCT.actions[usize::from(signal) - 1]; if let Some(old) = old { @@ -298,7 +285,8 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction (new.mask, new.flags, explicit_handler) } }; - action.first.store((handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32), Ordering::Relaxed); + let new_first = (handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32); + action.first.store(new_first, Ordering::Relaxed); action.user_data.store(mask, Ordering::Relaxed); Ok(()) From 78247c8525d714f4de21da815ecf0d766462bb03 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 3 Jul 2024 16:59:09 +0200 Subject: [PATCH 59/67] Pass signal correctly to SYS_KILL. --- redox-rt/src/signal.rs | 4 ++-- src/platform/redox/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index f99f39ebce..3c21bde1a3 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -67,7 +67,7 @@ unsafe fn inner(stack: &mut SigStack) { panic!("ctl {:x?} signal {}", os.control, stack.sig_num) } SigactionKind::Default => { - syscall::exit(stack.sig_num << 8); + syscall::exit(stack.sig_num); unreachable!(); } SigactionKind::Handled { handler } => handler, @@ -344,7 +344,7 @@ bitflags::bitflags! { const STORED_FLAGS: u32 = 0xfe00_0000; fn default_handler(sig: c_int) { - syscall::exit((sig as usize) << 8); + syscall::exit(sig as usize); } #[derive(Clone, Copy)] diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 83a5cbbe1b..c1d3b645f3 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -217,7 +217,7 @@ impl Pal for Sys { } fn exit(status: c_int) -> ! { - let _ = syscall::exit(status as usize); + let _ = syscall::exit((status as usize) << 8); loop {} } From b64b0ebe18f3e9514df40b6c1316e301c8ab76ac Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 3 Jul 2024 22:15:13 +0200 Subject: [PATCH 60/67] Handle kill and killpg EINTR. --- redox-rt/src/sys.rs | 52 +++++++++++++++++++++--------------- src/platform/redox/signal.rs | 4 +-- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index e9ec7383a8..8cc3a0dbc1 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -3,33 +3,41 @@ use syscall::error::{Result, Error, EINTR}; use crate::arch::manually_enter_trampoline; use crate::signal::tmp_disable_signals; +#[inline] +fn wrapper(mut f: impl FnMut() -> Result) -> Result { + loop { + let res = f(); + + if res == Err(Error::new(EINTR)) { + unsafe { + manually_enter_trampoline(); + } + } + + return res; + } +} + // TODO: uninitialized memory? #[inline] pub fn posix_read(fd: usize, buf: &mut [u8]) -> Result { - loop { - let res = syscall::read(fd, buf); - - if res == Err(Error::new(EINTR)) { - unsafe { - manually_enter_trampoline(); - } - } - - return res; - } + wrapper(|| syscall::read(fd, buf)) } #[inline] pub fn posix_write(fd: usize, buf: &[u8]) -> Result { - loop { - let res = syscall::write(fd, buf); - - if res == Err(Error::new(EINTR)) { - unsafe { - manually_enter_trampoline(); - } - } - - return res; - + wrapper(|| syscall::write(fd, buf)) +} +#[inline] +pub fn posix_kill(pid: usize, sig: usize) -> Result<()> { + match wrapper(|| syscall::kill(pid, sig)) { + Ok(_) | Err(Error { errno: EINTR }) => Ok(()), + Err(error) => Err(error), + } +} +#[inline] +pub fn posix_killpg(pgrp: usize, sig: usize) -> Result<()> { + match wrapper(|| syscall::kill(usize::wrapping_neg(pgrp), sig)) { + Ok(_) | Err(Error { errno: EINTR }) => Ok(()), + Err(error) => Err(error), } } diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index dc5e816ff2..ce156d1dea 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -53,11 +53,11 @@ impl PalSignal for Sys { } fn kill(pid: pid_t, sig: c_int) -> c_int { - e(syscall::kill(pid as usize, sig as usize)) as c_int + e(redox_rt::sys::posix_kill(pid as usize, sig as usize).map(|()| 0)) as c_int } fn killpg(pgrp: pid_t, sig: c_int) -> c_int { - e(syscall::kill(-(pgrp as isize) as usize, sig as usize)) as c_int + e(redox_rt::sys::posix_killpg(pgrp as usize, sig as usize).map(|()| 0)) as c_int } fn raise(sig: c_int) -> c_int { From cf390d6a524a58982827ca556acabd2503e9fb44 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 4 Jul 2024 11:24:23 +0200 Subject: [PATCH 61/67] Add SIGCHLD test. --- tests/Makefile | 1 + tests/sigchld.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/sigchld.c diff --git a/tests/Makefile b/tests/Makefile index 46690fd8f2..bb3ab90946 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,6 +30,7 @@ EXPECT_NAMES=\ select \ setjmp \ sigaction \ + sigchld \ signal \ stdio/all \ stdio/buffer \ diff --git a/tests/sigchld.c b/tests/sigchld.c new file mode 100644 index 0000000000..5e8a9ce2df --- /dev/null +++ b/tests/sigchld.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_helpers.h" + +volatile sig_atomic_t atomic = 0; +volatile sig_atomic_t atomic2 = 0; + +void action(int sig, siginfo_t *info, void *context) { + (void)context; + + assert(sig == SIGCHLD); + assert(info != NULL); + atomic += 1; +} +void handler(int sig) { + assert(sig == SIGPIPE); + atomic2 += 1; +} + +int main(void) { + int child = fork(); + ERROR_IF(fork, child, == -1); + + int fds[2]; + int status = pipe(fds); + ERROR_IF(pipe, status, == -1); + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_sigaction = action; + status = sigaction(SIGCHLD, &sa, NULL); + ERROR_IF(sigaction, status, == -1); + + sa.sa_handler = handler; + status = sigaction(SIGPIPE, &sa, NULL); + ERROR_IF(sigaction, status, == -1); + + if (child == 0) { + status = close(fds[1]); + ERROR_IF(close, status, == -1); + + char buf[1]; + status = read(fds[0], buf, 1); + ERROR_IF(read, status, == -1); + puts("Child exiting."); + return EXIT_SUCCESS; + } else { + int waitpid_stat; + + close(fds[0]); + ERROR_IF(close, status, == -1); + + puts("Sending SIGSTOP..."); + status = kill(child, SIGSTOP); + ERROR_IF(kill, status, == -1); + + while (atomic == 0) { + status = sched_yield(); + ERROR_IF(sched_yield, status, == -1); + } + puts("First handler ran, checking status."); + + status = waitpid(child, &waitpid_stat, WUNTRACED); + ERROR_IF(waitpid, status, == -1); + assert(WIFSTOPPED(waitpid_stat)); + assert(WSTOPSIG(waitpid_stat) == SIGSTOP); + puts("Correct, sending SIGCONT..."); + + status = kill(child, SIGCONT); + ERROR_IF(kill, status, == -1); + + while (atomic == 1) { + status = sched_yield(); + ERROR_IF(sched_yield, status, == -1); + } + puts("Second handler ran, checking status."); + + status = waitpid(child, &waitpid_stat, 0); + ERROR_IF(waitpid, status, == -1); + assert(WIFEXITED(waitpid_stat)); + assert(WEXITSTATUS(waitpid_stat) == 0); + puts("Child exited."); + + puts("Writing to (broken) pipe."); + status = write(fds[1], "C", 1); + ERROR_IF(write, status, != -1); + assert(errno == EPIPE); + + while (atomic2 == 0) { + status = sched_yield(); + ERROR_IF(sched_yield, status, == -1); + } + puts("SIGSTOP handler successfully executed."); + return EXIT_SUCCESS; + } +} From 284f51b47e5cf4a7ce26e3cbf38b3e2320eaeddb Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 4 Jul 2024 11:31:45 +0200 Subject: [PATCH 62/67] Fix struct sigaction defintion. --- include/bits/signal.h | 14 ++++++++++++++ src/header/signal/cbindgen.toml | 3 ++- src/header/signal/mod.rs | 6 +++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/bits/signal.h b/include/bits/signal.h index 46cc2553ed..57832b5e36 100644 --- a/include/bits/signal.h +++ b/include/bits/signal.h @@ -5,4 +5,18 @@ #define SIG_IGN ((void (*)(int))1) #define SIG_ERR ((void (*)(int))-1) +struct siginfo; +typedef struct siginfo siginfo_t; +typedef unsigned long long sigset_t; + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +}; + #endif // _BITS_SIGNAL_H diff --git a/src/header/signal/cbindgen.toml b/src/header/signal/cbindgen.toml index a7055988c9..3c79a66073 100644 --- a/src/header/signal/cbindgen.toml +++ b/src/header/signal/cbindgen.toml @@ -1,4 +1,4 @@ -sys_includes = ["stdint.h", "sys/types.h", "time.h", "bits/pthread.h"] +sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "time.h", "bits/pthread.h"] include_guard = "_RELIBC_SIGNAL_H" trailer = "#include " language = "C" @@ -15,3 +15,4 @@ prefix_with_name = true [export.rename] "timespec" = "struct timespec" +"sigaction" = "struct sigaction" diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index ec6241de54..01cd57d7eb 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -35,6 +35,7 @@ pub const SIG_SETMASK: c_int = 2; #[repr(C)] #[derive(Clone, Debug)] +/// cbindgen:ignore pub struct sigaction { pub sa_handler: Option, pub sa_flags: c_ulong, @@ -52,7 +53,7 @@ pub struct sigaltstack { #[repr(C)] #[derive(Clone, Debug)] -pub struct siginfo_t { +pub struct siginfo { pub si_signo: c_int, pub si_errno: c_int, pub si_code: c_int, @@ -60,7 +61,10 @@ pub struct siginfo_t { _si_align: [usize; 0], } +/// cbindgen:ignore pub type sigset_t = c_ulonglong; +/// cbindgen:ignore +pub type siginfo_t = siginfo; pub type stack_t = sigaltstack; From 77c9e53ee2e823cf45bf2ef7afb396f1edbec37e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 4 Jul 2024 15:09:33 +0200 Subject: [PATCH 63/67] Fix sigchld test. --- tests/sigchld.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/sigchld.c b/tests/sigchld.c index 5e8a9ce2df..455f9981df 100644 --- a/tests/sigchld.c +++ b/tests/sigchld.c @@ -26,13 +26,18 @@ void handler(int sig) { } int main(void) { - int child = fork(); - ERROR_IF(fork, child, == -1); - int fds[2]; int status = pipe(fds); ERROR_IF(pipe, status, == -1); + int child = fork(); + ERROR_IF(fork, child, == -1); + + sigset_t set; + sigemptyset(&set); + status = sigprocmask(SIG_SETMASK, &set, NULL); + ERROR_IF(sigprocmask, status, == -1); + struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; @@ -75,6 +80,9 @@ int main(void) { assert(WSTOPSIG(waitpid_stat) == SIGSTOP); puts("Correct, sending SIGCONT..."); + status = write(fds[1], "C", 1); + ERROR_IF(write, status, == -1); + status = kill(child, SIGCONT); ERROR_IF(kill, status, == -1); @@ -91,7 +99,7 @@ int main(void) { puts("Child exited."); puts("Writing to (broken) pipe."); - status = write(fds[1], "C", 1); + status = write(fds[1], "B", 1); ERROR_IF(write, status, != -1); assert(errno == EPIPE); From 44db74026048dc560f44904f82f29a8bddeed856 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 5 Jul 2024 16:54:48 +0200 Subject: [PATCH 64/67] Update dependencies. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index da68a3e725..d6229d164a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ features = ["c_api"] sc = "0.2.3" [target.'cfg(target_os = "redox")'.dependencies] -redox_syscall = "0.5.1" +redox_syscall = "0.5.2" redox-rt = { path = "redox-rt" } redox-path = "0.2" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = ["redox_syscall"] } From 315ba323a46747537256d899e99d2a6dc0e5f176 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 9 Jul 2024 15:42:33 +0200 Subject: [PATCH 65/67] Move sigchld test from EXPECT_NAMES to NAMES. --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index bb3ab90946..c27e6d8573 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,7 +30,6 @@ EXPECT_NAMES=\ select \ setjmp \ sigaction \ - sigchld \ signal \ stdio/all \ stdio/buffer \ @@ -158,6 +157,7 @@ NAMES=\ $(EXPECT_NAMES) \ dirent/main \ pwd \ + sigchld \ stdio/tempnam \ stdio/tmpnam \ stdlib/bsearch \ From 67976e759e2fddee2d38f66a5b493d69a22cf1ef Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 15 Jul 2024 17:19:42 +0200 Subject: [PATCH 66/67] Switch to upstream syscall dependency. --- Cargo.lock | 24 ++++++++++++++++-------- Cargo.toml | 2 +- redox-rt/Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7164fbfd51..70d18d4531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.104" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" [[package]] name = "cfg-if" @@ -369,7 +369,7 @@ dependencies = [ "generic-rt", "goblin", "plain", - "redox_syscall", + "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", ] [[package]] @@ -379,13 +379,21 @@ source = "git+https://gitlab.redox-os.org/redox-os/event.git#36ac5a57a8573f7546d dependencies = [ "bitflags", "libredox", - "redox_syscall", + "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3)", ] [[package]] name = "redox_syscall" version = "0.5.2" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=usignal#387f1c332681a3cabe04294bce801e9c8c433df5" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3#387f1c332681a3cabe04294bce801e9c8c433df5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#387f1c332681a3cabe04294bce801e9c8c433df5" dependencies = [ "bitflags", ] @@ -414,7 +422,7 @@ dependencies = [ "redox-path", "redox-rt", "redox_event", - "redox_syscall", + "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3)", "sc", "scrypt", "sha-crypt", @@ -498,9 +506,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.68" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index d6229d164a..159262b0aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,4 +76,4 @@ panic = "abort" panic = "abort" [patch.crates-io] -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "usignal" } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", rev = "387f1c3" } diff --git a/redox-rt/Cargo.toml b/redox-rt/Cargo.toml index 0cffcdca3b..00d6d3c202 100644 --- a/redox-rt/Cargo.toml +++ b/redox-rt/Cargo.toml @@ -12,6 +12,6 @@ description = "Libc-independent runtime for Redox" bitflags = "2" goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] } plain = "0.2" -redox_syscall = "0.5.1" +redox_syscall = "0.5.2" generic-rt = { path = "../generic-rt" } From e97f26c7632b1033ca062199db5633f3236821ed Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 15 Jul 2024 17:31:12 +0200 Subject: [PATCH 67/67] Use crates.io syscall dependency. --- Cargo.lock | 19 ++++++------------- Cargo.toml | 5 +---- redox-rt/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70d18d4531..1710b7ff4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ "generic-rt", "goblin", "plain", - "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "redox_syscall", ] [[package]] @@ -379,21 +379,14 @@ source = "git+https://gitlab.redox-os.org/redox-os/event.git#36ac5a57a8573f7546d dependencies = [ "bitflags", "libredox", - "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3)", + "redox_syscall", ] [[package]] name = "redox_syscall" -version = "0.5.2" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3#387f1c332681a3cabe04294bce801e9c8c433df5" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.5.2" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#387f1c332681a3cabe04294bce801e9c8c433df5" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] @@ -422,7 +415,7 @@ dependencies = [ "redox-path", "redox-rt", "redox_event", - "redox_syscall 0.5.2 (git+https://gitlab.redox-os.org/redox-os/syscall.git?rev=387f1c3)", + "redox_syscall", "sc", "scrypt", "sha-crypt", diff --git a/Cargo.toml b/Cargo.toml index 159262b0aa..e3ebeb48ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ features = ["c_api"] sc = "0.2.3" [target.'cfg(target_os = "redox")'.dependencies] -redox_syscall = "0.5.2" +redox_syscall = "0.5.3" redox-rt = { path = "redox-rt" } redox-path = "0.2" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = ["redox_syscall"] } @@ -74,6 +74,3 @@ panic = "abort" [profile.release] panic = "abort" - -[patch.crates-io] -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", rev = "387f1c3" } diff --git a/redox-rt/Cargo.toml b/redox-rt/Cargo.toml index 00d6d3c202..33502bb75f 100644 --- a/redox-rt/Cargo.toml +++ b/redox-rt/Cargo.toml @@ -12,6 +12,6 @@ description = "Libc-independent runtime for Redox" bitflags = "2" goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] } plain = "0.2" -redox_syscall = "0.5.2" +redox_syscall = "0.5.3" generic-rt = { path = "../generic-rt" }