From b5ff0aabd561c1befcc583aa0d7139fddabda27b Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Sun, 9 Jul 2017 21:34:38 -0600 Subject: [PATCH] WIP: Signal handling --- src/consts.rs | 12 +++++-- src/context/context.rs | 18 +++++++--- src/context/switch.rs | 33 +++++++++++++---- src/scheme/sys/context.rs | 3 ++ src/start.rs | 33 ++++++++--------- src/syscall/mod.rs | 25 +++++++++++-- src/syscall/process.rs | 74 +++++++++++++++++++++++++++++++-------- 7 files changed, 151 insertions(+), 47 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 149c9b45..c8acb394 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -46,8 +46,13 @@ /// Size of user stack pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB + /// Offset to user sigstack + pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; + /// Size of user sigstack + pub const USER_SIGSTACK_SIZE: usize = 256 * 1024; // 256 KB + /// Offset to user TLS - pub const USER_TLS_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; + pub const USER_TLS_OFFSET: usize = USER_SIGSTACK_OFFSET + PML4_SIZE; /// Offset to user temporary image (used when cloning) pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE; @@ -61,8 +66,11 @@ /// Offset to user temporary stack (used when cloning) pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE; + /// Offset to user temporary sigstack (used when cloning) + pub const USER_TMP_SIGSTACK_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; + /// Offset to user temporary tls (used when cloning) - pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; + pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_SIGSTACK_OFFSET + PML4_SIZE; /// Offset for usage in other temporary pages pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE; diff --git a/src/context/context.rs b/src/context/context.rs index f35a5d02..a059614c 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -1,6 +1,7 @@ use alloc::arc::Arc; use alloc::boxed::Box; use collections::{BTreeMap, Vec, VecDeque}; +use core::mem; use spin::Mutex; use context::arch; @@ -8,7 +9,8 @@ use context::file::File; use context::memory::{Grant, Memory, SharedMemory, Tls}; use device; use scheme::{SchemeNamespace, FileHandle}; -use syscall::data::Event; +use syscall::data::{Event, SigAction}; +use syscall::flag::SIG_DFL; use sync::{WaitMap, WaitQueue}; /// Unique identifier for a context (i.e. `pid`). @@ -69,6 +71,8 @@ pub struct Context { pub heap: Option<SharedMemory>, /// User stack pub stack: Option<Memory>, + /// User signal stack + pub sigstack: Option<Memory>, /// User Thread local storage pub tls: Option<Tls>, /// User grants @@ -83,8 +87,8 @@ pub struct Context { pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>, /// The open files in the scheme pub files: Arc<Mutex<Vec<Option<File>>>>, - /// Singal handlers - pub handlers: Arc<Mutex<BTreeMap<u8, usize>>>, + /// Singal actions + pub actions: Arc<Mutex<Vec<SigAction>>>, } impl Context { @@ -111,6 +115,7 @@ impl Context { image: Vec::new(), heap: None, stack: None, + sigstack: None, tls: None, grants: Arc::new(Mutex::new(Vec::new())), name: Arc::new(Mutex::new(Vec::new())), @@ -118,7 +123,12 @@ impl Context { events: Arc::new(WaitQueue::new()), env: Arc::new(Mutex::new(BTreeMap::new())), files: Arc::new(Mutex::new(Vec::new())), - handlers: Arc::new(Mutex::new(BTreeMap::new())), + actions: Arc::new(Mutex::new(vec![SigAction { + sa_handler: unsafe { mem::transmute(SIG_DFL) }, + sa_mask: [0; 2], + sa_flags: 0, + sa_restorer: unsafe { mem::transmute(0usize) }, + }; 128])), } } diff --git a/src/context/switch.rs b/src/context/switch.rs index fd560c93..fdd05292 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -1,9 +1,12 @@ +use core::mem; use core::sync::atomic::Ordering; use context::{arch, contexts, Context, Status, CONTEXT_ID}; -use interrupt::irq::PIT_TICKS; +use start::usermode; +use syscall::flag::{SIG_DFL, SIG_IGN}; use gdt; use interrupt; +use interrupt::irq::PIT_TICKS; use syscall; use time; @@ -118,19 +121,35 @@ pub unsafe fn switch() -> bool { } extern "C" fn signal_handler(sig: usize) { - let handler = { + let action = { let contexts = contexts(); let context_lock = contexts.current().expect("context::signal_handler not inside of context"); let context = context_lock.read(); - let handlers = context.handlers.lock(); - handlers.get(&(sig as u8)).map_or(0, |sig| *sig) + let actions = context.actions.lock(); + actions[sig] }; - println!("Signal handler: {}, {:X}", sig, handler); + println!("Signal handler: {:X}, {:?}", sig, action); - if handler == 0 { + let handler = action.sa_handler as usize; + let restorer = action.sa_restorer as usize; + if handler == SIG_DFL { + println!("Exit {:X}", sig); syscall::exit(sig); + } else if handler == SIG_IGN { + println!("Ignore"); } else { - // TODO: Call handler + println!("Call {:X}", handler); + + unsafe { + let mut sp = ::USER_SIGSTACK_OFFSET + ::USER_SIGSTACK_SIZE - 256; + + sp = (sp / 16) * 16; + + sp -= mem::size_of::<usize>(); + *(sp as *mut usize) = restorer; + + usermode(handler, sp, sig); + } } } diff --git a/src/scheme/sys/context.rs b/src/scheme/sys/context.rs index a28820dc..f0bec7e7 100644 --- a/src/scheme/sys/context.rs +++ b/src/scheme/sys/context.rs @@ -72,6 +72,9 @@ pub fn resource() -> Result<Vec<u8>> { if let Some(ref stack) = context.stack { memory += stack.size(); } + if let Some(ref sigstack) = context.sigstack { + memory += sigstack.size(); + } let memory_string = if memory >= 1024 * 1024 * 1024 { format!("{} GB", memory / 1024 / 1024 / 1024) diff --git a/src/start.rs b/src/start.rs index bf9dedac..faac4b42 100644 --- a/src/start.rs +++ b/src/start.rs @@ -156,25 +156,26 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, bsp_table: usize, stack_start: usi kmain_ap(cpu_id); } -pub unsafe fn usermode(ip: usize, sp: usize) -> ! { +pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { // Go to usermode - asm!("mov ds, ax - mov es, ax - mov fs, bx - mov gs, ax - push rax - push rcx - push rdx - push rsi - push rdi + asm!("mov ds, r10d + mov es, r10d + mov fs, r11d + mov gs, r10d + push r10 + push r12 + push r13 + push r14 + push r15 iretq" : // No output because it never returns - : "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment - "{rbx}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment - "{rcx}"(sp), // Stack pointer - "{rdx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag - "{rsi}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment - "{rdi}"(ip) // IP + : "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment + "{r11}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment + "{r12}"(sp), // Stack pointer + "{r13}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag + "{r14}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment + "{r15}"(ip) // IP + "{rdi}"(arg) // Argument : // No clobers because it never returns : "intel", "volatile"); unreachable!(); diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index f2d69b45..74c602ef 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -12,7 +12,7 @@ pub use self::process::*; pub use self::time::*; pub use self::validate::*; -use self::data::TimeSpec; +use self::data::{SigAction, TimeSpec}; use self::error::{Error, Result, ENOSYS}; use self::number::*; @@ -70,7 +70,14 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize }, _ => match a { SYS_YIELD => sched_yield(), - SYS_NANOSLEEP => nanosleep(validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, validate_slice_mut(c as *mut TimeSpec, 1).ok().map(|rem| &mut rem[0])), + SYS_NANOSLEEP => nanosleep( + validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, + if c == 0 { + None + } else { + Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?) + } + ), SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?), SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32), SYS_BRK => brk(b), @@ -80,7 +87,6 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_EXIT => exit((b & 0xFF) << 8), SYS_KILL => kill(ContextId::from(b), c), SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into), - SYS_SIGNAL => signal(b, c), SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), SYS_IOPL => iopl(b, stack), @@ -95,6 +101,19 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_SETREUID => setreuid(b as u32, c as u32), SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)), SYS_SETREGID => setregid(b as u32, c as u32), + SYS_SIGACTION => sigaction( + b, + if c == 0 { + None + } else { + Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?) + }, + if d == 0 { + None + } else { + Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?) + } + ), SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c), SYS_PHYSALLOC => physalloc(b), SYS_PHYSFREE => physfree(b, c), diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 2b5e426b..7fcc79d0 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -18,7 +18,7 @@ use context::ContextId; use elf::{self, program_header}; use scheme::{self, FileHandle}; use syscall; -use syscall::data::Stat; +use syscall::data::{SigAction, Stat}; use syscall::error::*; use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, O_CLOEXEC, SIG_DFL, WNOHANG}; use syscall::validate::{validate_slice, validate_slice_mut}; @@ -79,13 +79,14 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { let mut image = vec![]; let mut heap_option = None; let mut stack_option = None; + let mut sigstack_option = None; let mut tls_option = None; let grants; let name; let cwd; let env; let files; - let handlers; + let actions; // Copy from old process { @@ -195,6 +196,24 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { stack_option = Some(new_stack); } + if let Some(ref sigstack) = context.sigstack { + let mut new_sigstack = context::memory::Memory::new( + VirtualAddress::new(::USER_TMP_SIGSTACK_OFFSET), + sigstack.size(), + entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, + false + ); + + unsafe { + intrinsics::copy(sigstack.start_address().get() as *const u8, + new_sigstack.start_address().get() as *mut u8, + sigstack.size()); + } + + new_sigstack.remap(sigstack.flags()); + sigstack_option = Some(new_sigstack); + } + if let Some(ref tls) = context.tls { let mut new_tls = context::memory::Tls { master: tls.master, @@ -252,9 +271,9 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { } if flags & CLONE_SIGHAND == CLONE_SIGHAND { - handlers = context.handlers.clone(); + actions = context.actions.clone(); } else { - handlers = Arc::new(Mutex::new(context.handlers.lock().clone())); + actions = Arc::new(Mutex::new(context.actions.lock().clone())); } } @@ -441,6 +460,12 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { context.stack = Some(stack); } + // Setup user sigstack + if let Some(mut sigstack) = sigstack_option { + sigstack.move_to(VirtualAddress::new(::USER_SIGSTACK_OFFSET), &mut new_table, &mut temporary_page); + context.sigstack = Some(sigstack); + } + // Setup user TLS if let Some(mut tls) = tls_option { tls.mem.move_to(VirtualAddress::new(::USER_TLS_OFFSET), &mut new_table, &mut temporary_page); @@ -455,7 +480,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { context.files = files; - context.handlers = handlers; + context.actions = actions; } } @@ -470,12 +495,14 @@ fn empty(context: &mut context::Context, reaping: bool) { assert!(context.image.is_empty()); assert!(context.heap.is_none()); assert!(context.stack.is_none()); + assert!(context.sigstack.is_none()); assert!(context.tls.is_none()); } else { // Unmap previous image, heap, grants, stack, and tls context.image.clear(); drop(context.heap.take()); drop(context.stack.take()); + drop(context.sigstack.take()); drop(context.tls.take()); } @@ -673,6 +700,14 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { true )); + // Map stack + context.sigstack = Some(context::memory::Memory::new( + VirtualAddress::new(::USER_SIGSTACK_OFFSET), + ::USER_SIGSTACK_SIZE, + entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, + true + )); + // Map TLS if let Some((master, file_size, size)) = tls_option { let tls = context::memory::Tls { @@ -737,7 +772,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { let files = Arc::new(Mutex::new(context.files.lock().clone())); context.files = files.clone(); - context.handlers = Arc::new(Mutex::new(BTreeMap::new())); + context.actions = Arc::new(Mutex::new(vec![SigAction { + sa_handler: unsafe { mem::transmute(SIG_DFL) }, + sa_mask: [0; 2], + sa_flags: 0, + sa_restorer: unsafe { mem::transmute(0usize) }, + }; 128])); let vfork = context.vfork; context.vfork = false; @@ -819,7 +859,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { } // Go to usermode - unsafe { usermode(entry, sp); } + unsafe { usermode(entry, sp, 0); } } pub fn exit(status: usize) -> ! { @@ -971,18 +1011,22 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> { } } -pub fn signal(sig: usize, handler: usize) -> Result<usize> { +pub fn sigaction(sig: usize, act_opt: Option<&SigAction>, oldact_opt: Option<&mut SigAction>) -> Result<usize> { if sig > 0 && sig <= 0x7F { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - let mut handlers = context.handlers.lock(); - let previous = if handler == SIG_DFL { - handlers.remove(&(sig as u8)) - } else { - handlers.insert(sig as u8, handler) - }; - Ok(previous.unwrap_or(0)) + let mut actions = context.actions.lock(); + + if let Some(oldact) = oldact_opt { + *oldact = actions[sig]; + } + + if let Some(act) = act_opt { + actions[sig] = *act; + } + + Ok(0) } else { Err(Error::new(EINVAL)) } -- GitLab