diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index c1a11cd278e89760d09d9adef203c81e6c163372..cc1fa646556bdcfca589ea53cb2921276b12fb48 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 24ff85f5a1ad0fc1cb01d82e66a2b0b57e3e8f1e..e45cfa4c4c84c30699de8ad7eeacfae5f348663c 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<impl FnMut(u32, bool) -> 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); + + // 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); - (_, Sigaction::Default) => (), - (_, Sigaction::Handled { .. }) => (), + // 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 625ac730c0a3e4f1aa1602c71a060a9c6f3952dc..59d0390eda9f536c88f6a01effb118b83451518b 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, }, }; }