WIP: Signal handling

This commit is contained in:
Jeremy Soller
2017-07-09 21:34:38 -06:00
parent 7e52541f39
commit b5ff0aabd5
7 changed files with 151 additions and 47 deletions

View File

@@ -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;

View File

@@ -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])),
}
}

View File

@@ -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);
}
}
}

View File

@@ -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)

View File

@@ -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!();

View File

@@ -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),

View File

@@ -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))
}