From 3749696d3e5ec962f57226660e316c540fe9295d Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Thu, 18 Jul 2013 08:53:28 +0900 Subject: [PATCH] simple signal handler and kill(2) support. --- arch/x86/kernel/include/signal.h | 18 +++++ arch/x86/kernel/include/syscall_list.h | 2 + kernel/include/process.h | 13 +++ kernel/mem.c | 2 + kernel/process.c | 13 +++ kernel/syscall.c | 107 ++++++++++++++++++++++++- 6 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 arch/x86/kernel/include/signal.h diff --git a/arch/x86/kernel/include/signal.h b/arch/x86/kernel/include/signal.h new file mode 100644 index 00000000..6a35e5b6 --- /dev/null +++ b/arch/x86/kernel/include/signal.h @@ -0,0 +1,18 @@ +#define _NSIG 64 +#define _NSIG_BPW 64 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +struct sigaction { + void (*sa_handler)(int); + unsigned long sa_flags; + void (*sa_restorer)(int); + sigset_t sa_mask; +}; + +struct k_sigaction { + struct sigaction sa; +}; diff --git a/arch/x86/kernel/include/syscall_list.h b/arch/x86/kernel/include/syscall_list.h index c7cc285e..1ad33cda 100644 --- a/arch/x86/kernel/include/syscall_list.h +++ b/arch/x86/kernel/include/syscall_list.h @@ -25,6 +25,7 @@ SYSCALL_HANDLED(11, munmap) SYSCALL_HANDLED(12, brk) SYSCALL_HANDLED(13, rt_sigaction) SYSCALL_HANDLED(14, rt_sigprocmask) +SYSCALL_HANDLED(15, rt_sigreturn) SYSCALL_DELEGATED(16, ioctl) SYSCALL_DELEGATED(17, pread64) SYSCALL_DELEGATED(18, pwrite64) @@ -35,6 +36,7 @@ SYSCALL_HANDLED(28, madvise) SYSCALL_HANDLED(39, getpid) SYSCALL_HANDLED(56, clone) SYSCALL_HANDLED(60, exit) +SYSCALL_HANDLED(62, kill) SYSCALL_DELEGATED(63, uname) SYSCALL_DELEGATED(72, fcntl) SYSCALL_DELEGATED(79, getcwd) diff --git a/kernel/include/process.h b/kernel/include/process.h index 3a8058b3..46d3b036 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -6,6 +6,7 @@ #include #include #include +#include #define VR_NONE 0x0 #define VR_STACK 0x1 @@ -53,6 +54,12 @@ struct vm_regions { struct process_vm; +struct sig_handler { + // TODO: lock; + int use; + struct k_sigaction action[_NSIG]; +}; + struct process { int pid; int status; @@ -74,6 +81,12 @@ struct process { int *clear_child_tid; unsigned long tlsblock_base, tlsblock_limit; } thread; + + int signal; + struct sig_handler *sighandler; + ihk_mc_kernel_context_t sigctx; + char sigstack[512]; + unsigned long sigrc; // return code of rt_sigreturn (x86_64: rax reg.) }; struct process_vm { diff --git a/kernel/mem.c b/kernel/mem.c index 8a7949ff..e408ac76 100644 --- a/kernel/mem.c +++ b/kernel/mem.c @@ -73,6 +73,7 @@ void sbox_write(int offset, unsigned int value); static void query_free_mem_interrupt_handler(void *priv) { +#ifdef ATTACHED_MIC dkprintf("query free mem handler!\n"); int pages = ihk_pagealloc_query_free(pa_allocator); @@ -81,6 +82,7 @@ static void query_free_mem_interrupt_handler(void *priv) sbox_write(SBOX_SCRATCH0, pages); sbox_write(SBOX_SCRATCH1, 1); +#endif } static struct ihk_mc_interrupt_handler query_free_mem_handler = { diff --git a/kernel/process.c b/kernel/process.c index 74e1e196..7509a14c 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -54,6 +54,14 @@ struct process *create_process(unsigned long user_pc) memset(proc, 0, sizeof(struct process)); ihk_atomic_set(&proc->refcount, 2); /* one for exit, another for wait */ + proc->sighandler = kmalloc(sizeof(struct sig_handler), IHK_MC_AP_NOWAIT); + if(!proc->sighandler){ + ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES); + return NULL; + } + memset(proc->sighandler, '\0', sizeof(struct sig_handler)); + proc->sighandler->use = 1; + ihk_mc_init_user_process(&proc->ctx, &proc->uctx, ((char *)proc) + KERNEL_STACK_NR_PAGES * PAGE_SIZE, user_pc, 0); @@ -61,6 +69,7 @@ struct process *create_process(unsigned long user_pc) proc->vm = (struct process_vm *)(proc + 1); if(init_process_vm(proc, proc->vm) != 0){ + kfree(proc->sighandler); ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES); return NULL; } @@ -95,6 +104,10 @@ struct process *clone_process(struct process *org, unsigned long pc, ihk_atomic_inc(&org->vm->refcount); proc->vm = org->vm; + // TODO: lock + proc->sighandler = org->sighandler; + org->sighandler->use++; + ihk_mc_spinlock_init(&proc->spin_sleep_lock); proc->spin_sleep = 0; diff --git a/kernel/syscall.c b/kernel/syscall.c index 2b0fcca2..7f7aac98 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -813,6 +813,28 @@ SYSCALL_DECLARE(set_tid_address) return cpu_local_var(current)->pid; } +SYSCALL_DECLARE(kill) +{ + int pid = ihk_mc_syscall_arg0(ctx); + int sig = ihk_mc_syscall_arg1(ctx); + + struct process *proc = cpu_local_var(current); + + if(proc->pid == pid){ + proc->signal = sig; + return 0; + } + + if(pid <= 0) { return -EINVAL; } + // search pid + // check kill permission + if(sig == 0) { + return 0; + } else { + return -EPERM; + } +} + // see linux-2.6.34.13/kernel/signal.c SYSCALL_DECLARE(tgkill) { @@ -835,11 +857,87 @@ SYSCALL_DECLARE(set_robust_list) return -ENOSYS; } +int +do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) +{ + struct process *proc = cpu_local_var(current); + struct k_sigaction *k; + // TODO: sigmask + + k = proc->sighandler->action + sig - 1; + if(oact) + memcpy(oact, k, sizeof(struct k_sigaction)); + if(act){ + memcpy(k, act, sizeof(struct k_sigaction)); + } + return 0; +} + SYSCALL_DECLARE(rt_sigaction) { - // kprintf("sys_rt_sigaction called. returning zero...\n"); - return 0; + int sig = ihk_mc_syscall_arg0(ctx); + const struct sigaction *act = (const struct sigaction *)ihk_mc_syscall_arg1(ctx); + struct sigaction *oact = (struct sigaction *)ihk_mc_syscall_arg2(ctx); + size_t sigsetsize = ihk_mc_syscall_arg3(ctx); + struct k_sigaction new_sa, old_sa; + int rc; + + //if (sigsetsize != sizeof(sigset_t)) + //return -EINVAL; + + if(act) + memcpy(&new_sa.sa, act, sizeof new_sa.sa); + rc = do_sigaction(sig, act? &new_sa: NULL, oact? &old_sa: NULL); + if(oact) + memcpy(oact, &old_sa.sa, sizeof old_sa.sa); + + return rc; } + +static void +check_signal(unsigned long rc) +{ + struct process *proc = cpu_local_var(current); + struct k_sigaction *k; + int sig = proc->signal; + + proc->signal = 0; + if(sig){ + k = proc->sighandler->action + sig - 1; + if(k->sa.sa_handler){ + unsigned long *usp; /* user stack */ + char *kspbottom; + long w; + asm volatile ("movq %%gs:24,%0" : "=r" (usp)); + asm volatile ("movq %%gs:132,%0" : "=r" (kspbottom)); + memcpy(proc->sigstack, kspbottom - 120, 120); + proc->sigrc = rc; + usp--; + *usp = (unsigned long)k->sa.sa_restorer; + w = 56 + 3; + asm volatile ("pushq %0" :: "r" (w)); + asm volatile ("pushq %0" :: "r" (usp)); + w = 1 << 9; + asm volatile ("pushq %0" :: "r" (w)); + w = 48 + 3; + asm volatile ("pushq %0" :: "r" (w)); + asm volatile ("pushq %0" :: "r" (k->sa.sa_handler)); + asm volatile ("iretq"); + } + } +} + +SYSCALL_DECLARE(rt_sigreturn) +{ + struct process *proc = cpu_local_var(current); + char *kspbottom; + asm volatile ("movq %%gs:132,%0" : "=r" (kspbottom)); + memcpy(kspbottom - 120, proc->sigstack, 120); + + return proc->sigrc; +} + + SYSCALL_DECLARE(rt_sigprocmask) { // kprintf("sys_rt_sigprocmask called. returning zero...\n"); @@ -1129,6 +1227,7 @@ long syscall(int num, ihk_mc_user_context_t *ctx) cpu_enable_interrupt(); + #if 0 if(num != 24) // if not sched_yield #endif @@ -1170,7 +1269,9 @@ long syscall(int num, ihk_mc_user_context_t *ctx) ihk_mc_syscall_sp(ctx)); l = syscall_generic_forwarding(num, ctx); } - + + check_signal(l); + return l; }