From abc2ec7bb5382fcf0aa865272680f45062b7fdef Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 30 Jul 2024 23:24:42 +0200 Subject: [PATCH] Add prototype ucontext_t support. --- redox-rt/src/arch/i686.rs | 6 ++-- redox-rt/src/arch/x86_64.rs | 5 +++- redox-rt/src/signal.rs | 55 +++++++++++++++++++++++++----------- src/platform/linux/signal.rs | 42 +++++++++++++++++++++++++++ src/platform/redox/signal.rs | 53 ++++++++++++++++++++++++++++++++-- 5 files changed, 138 insertions(+), 23 deletions(-) diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index 9889ff3a2..f425a6c1f 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -222,13 +222,13 @@ asmfunction!(__relibc_internal_sigentry: [" push eax push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ptr}] - sub esp, 2 * 4 + sub esp, 24 mov ecx, esp call {inner} - fxrstor [esp + 16] - add esp, 16 + 29 * 16 + 2 * 4 + fxrstor [esp + 32] + add esp, 32 + 29 * 16 + 2 * 4 pop ebp pop esi diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index a0756c128..1faf2ab0c 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -1,5 +1,6 @@ use core::{ mem::offset_of, + ptr::NonNull, sync::atomic::{AtomicU8, Ordering}, }; @@ -33,6 +34,7 @@ pub struct SigArea { pub altstack_bottom: usize, pub disable_signals_depth: u64, pub last_sig_was_restart: bool, + pub last_sigstack: Option<NonNull<SigStack>>, } #[repr(C, align(16))] @@ -301,11 +303,12 @@ asmfunction!(__relibc_internal_sigentry: [" 5: push rax // selected signal push fs:[{tcb_sa_off} + {sa_tmp_ptr}] + sub rsp, 48 // alloc space for ucontext fields mov rdi, rsp call {inner} - add rsp, 16 + add rsp, 64 fxrstor64 [rsp + 16 * 16] diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 529d1b356..4e9ca55cd 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -1,6 +1,7 @@ use core::{ cell::{Cell, UnsafeCell}, ffi::{c_int, c_void}, + ptr::NonNull, sync::atomic::{AtomicU8, AtomicUsize, Ordering}, }; @@ -22,14 +23,19 @@ pub fn sighandler_function() -> usize { __relibc_internal_sigentry as usize } +/// ucontext_t representation #[repr(C)] pub struct SigStack { #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] - _pad: [usize; 0], // pad to 16 bytes alignment + _pad: [usize; 1], // pad from 7*8 to 64 #[cfg(target_arch = "x86")] - _pad: [usize; 2], // pad to 16 bytes alignment + _pad: [usize; 0], // don't pad from 8*4 + pub link: *mut SigStack, + + pub old_stack: PosixStackt, + pub old_mask: u64, sival: usize, sig_num: usize, @@ -38,10 +44,35 @@ pub struct SigStack { // aarch64: 272 bytes (SIMD TODO) pub regs: ArchIntRegs, } +#[repr(C)] +pub struct PosixStackt { + pub sp: *mut (), + pub flags: i32, + pub size: usize, +} + +#[repr(C)] +// TODO: This struct is for practical reasons locked to Linux's ABI, but avoid redefining +// it here. Alternatively, check at compile time that the structs are equivalent. +pub struct SiginfoAbi { + pub si_signo: i32, + pub si_errno: i32, + pub si_code: i32, + pub si_pid: i32, // pid_t + pub si_uid: i32, // uid_t + pub si_addr: *mut (), // *mut c_void + pub si_status: i32, + pub si_value: usize, // sigval +} #[inline(always)] unsafe fn inner(stack: &mut SigStack) { let os = &Tcb::current().unwrap().os_specific; + + let stack_ptr = NonNull::from(&mut *stack); + stack.link = core::mem::replace(&mut (*os.arch.get()).last_sigstack, Some(stack_ptr)) + .map_or_else(core::ptr::null_mut, |x| x.as_ptr()); + let signals_were_disabled = (*os.arch.get()).disable_signals_depth > 0; let _targeted_thread_not_process = stack.sig_num >= 64; @@ -119,21 +150,11 @@ unsafe fn inner(stack: &mut SigStack) { if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction { + stack.old_mask = ((prev_w1 >> 32) << 32) | (prev_w0 & 0xffff_ffff); + // TODO: stack.old_stack + //let _ = syscall::write(1, alloc::format!("SIGACTION {:p}\n", sigaction).as_bytes()); - // TODO: This struct is for practical reasons locked to Linux's ABI, but avoid redefining - // it here. Alternatively, check at compile time that the structs are equivalent. - #[repr(C)] - struct siginfo { - si_signo: c_int, - si_errno: c_int, - si_code: c_int, - si_pid: c_int, // TODO pid_t - si_uid: c_int, // TODO uid_t - si_addr: *mut c_void, - si_status: c_int, - si_value: usize, // TODO union - } - let info = siginfo { + let info = SiginfoAbi { si_signo: stack.sig_num as c_int, si_addr: core::ptr::null_mut(), si_code: 0, // TODO: SIG_QUEUE/SIG_USER/etc @@ -146,7 +167,7 @@ unsafe fn inner(stack: &mut SigStack) { sigaction( stack.sig_num as c_int, core::ptr::addr_of!(info).cast(), - core::ptr::null_mut(), // TODO + stack as *mut SigStack as *mut (), ); } else if let Some(handler) = handler.handler { //let _ = syscall::write(1, alloc::format!("HANDLER {:p}\n", handler).as_bytes()); diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index b1d4d2e06..a6ec22fb3 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -14,6 +14,48 @@ use crate::{ }, }; +// Mirrors the ucontext_t struct from the libc crate on Linux. +#[repr(C)] +pub struct ucontext_t { + pub uc_flags: c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: sigset_t, + __private: [u8; 512], +} +#[repr(C)] +pub struct _libc_fpstate { + pub cwd: u16, + pub swd: u16, + pub ftw: u16, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcr_mask: u32, + pub _st: [_libc_fpxreg; 8], + pub _xmm: [_libc_xmmreg; 16], + __private: [u64; 12], +} +#[repr(C)] +pub struct _libc_fpxreg { + pub significand: [u16; 4], + pub exponent: u16, + __private: [u16; 3], +} + +#[repr(C)] +pub struct _libc_xmmreg { + pub element: [u32; 4], +} +#[repr(C)] +pub struct mcontext_t { + pub gregs: [i64; 23], // TODO: greg_t? + pub fpregs: *mut _libc_fpstate, + __private: [u64; 8], +} + impl PalSignal for Sys { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int { e(syscall!(GETITIMER, which, out)) as c_int diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 6f343754c..3be1da844 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,5 +1,7 @@ -use core::mem; -use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler}; +use core::mem::{self, offset_of}; +use redox_rt::signal::{ + SigStack, Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler, +}; use syscall::{self, Result}; use super::{ @@ -20,6 +22,53 @@ use crate::{ platform::ERRNO, }; +#[repr(C)] +pub struct ucontext_t { + #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + _pad: [usize; 1], // pad from 7*8 to 64 + + #[cfg(target_arch = "x86")] + _pad: [usize; 0], // don't pad from 8*4 + + pub uc_link: *mut ucontext_t, + pub uc_stack: stack_t, + pub uc_sigmask: sigset_t, + _sival: usize, + _signum: usize, + pub uc_mcontext: mcontext_t, +} + +const _: () = { + const fn assert_eq(a: usize, b: usize) { + if a != b { + panic!("compile-time struct verification failed"); + } + } + assert_eq(offset_of!(ucontext_t, uc_link), offset_of!(SigStack, link)); + assert_eq( + offset_of!(ucontext_t, uc_stack), + offset_of!(SigStack, old_stack), + ); + assert_eq( + offset_of!(ucontext_t, uc_sigmask), + offset_of!(SigStack, old_mask), + ); + assert_eq( + offset_of!(ucontext_t, uc_mcontext), + offset_of!(SigStack, regs), + ); +}; + +#[repr(C)] +pub struct mcontext_t { + #[cfg(target_arch = "x86")] + _opaque: [u8; 512], + #[cfg(target_arch = "x86-64")] + _opaque: [u8; 864], + #[cfg(target_arch = "aarch64")] + _opaque: [u8; 272], +} + impl PalSignal for Sys { unsafe fn getitimer(which: c_int, out: *mut itimerval) -> c_int { let path = match which { -- GitLab