From 94a87fe25c5ec021daf16edd64058ed6a37aba7d Mon Sep 17 00:00:00 2001 From: Minep Date: Mon, 13 Jun 2022 15:40:28 +0100 Subject: [PATCH] feat: add signal handling support (not tested!) --- lunaix-os/.gitignore | 1 + lunaix-os/bx_enh_dbg.ini | 8 +-- lunaix-os/includes/hal/cpu.h | 2 + lunaix-os/includes/lunaix/process.h | 70 +++++++++++++------ lunaix-os/includes/lunaix/signal.h | 29 ++++++++ lunaix-os/includes/lunaix/syscall.h | 6 +- lunaix-os/kernel/asm/x86/interrupt.S | 49 ++++++++++++- lunaix-os/kernel/asm/x86/syscall.S | 7 +- lunaix-os/kernel/sched.c | 6 +- lunaix-os/kernel/signal.c | 101 +++++++++++++++++++++++++++ 10 files changed, 245 insertions(+), 34 deletions(-) create mode 100644 lunaix-os/includes/lunaix/signal.h create mode 100644 lunaix-os/kernel/signal.c diff --git a/lunaix-os/.gitignore b/lunaix-os/.gitignore index 2b8398e..0b666f6 100644 --- a/lunaix-os/.gitignore +++ b/lunaix-os/.gitignore @@ -4,3 +4,4 @@ playground/ .vscode/*.log .VSCodeCounter/ .idea +bx_enh_dbg.ini \ No newline at end of file diff --git a/lunaix-os/bx_enh_dbg.ini b/lunaix-os/bx_enh_dbg.ini index 5e8e298..3486095 100644 --- a/lunaix-os/bx_enh_dbg.ini +++ b/lunaix-os/bx_enh_dbg.ini @@ -19,8 +19,8 @@ isLittleEndian = TRUE DefaultAsmLines = 512 DumpWSIndex = 2 DockOrder = 0x123 -ListWidthPix[0] = 257 -ListWidthPix[1] = 318 -ListWidthPix[2] = 367 -MainWindow = 0, 0, 743, 500 +ListWidthPix[0] = 203 +ListWidthPix[1] = 249 +ListWidthPix[2] = 287 +MainWindow = 2536, 358, 743, 500 FontName = Normal diff --git a/lunaix-os/includes/hal/cpu.h b/lunaix-os/includes/hal/cpu.h index fe633d0..af56120 100644 --- a/lunaix-os/includes/hal/cpu.h +++ b/lunaix-os/includes/hal/cpu.h @@ -3,6 +3,8 @@ #include +#define SEL_RPL(selector) ((selector)&0x3) + typedef unsigned int reg32; typedef unsigned short reg16; diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 76ecacc..e429060 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -1,12 +1,13 @@ #ifndef __LUNAIX_PROCESS_H #define __LUNAIX_PROCESS_H -#include #include -#include -#include #include +#include +#include #include +#include +#include // 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。 #define KERNEL_PID -1 @@ -20,16 +21,27 @@ #define PROC_TERMMASK 0x6 - -struct proc_mm { +struct proc_mm +{ heap_context_t u_heap; struct mm_region* regions; }; -struct proc_info { +struct proc_sig +{ + void* signal_handler; + int sig_num; + isr_param prev_context; +}; + +#define PROC_SIG_SIZE sizeof(struct proc_sig) // size=84 + +struct proc_info +{ pid_t pid; struct proc_info* parent; - isr_param intr_ctx; + isr_param intr_ctx; // size=76 + uintptr_t ustack_top; struct llist_header siblings; struct llist_header children; struct proc_mm mm; @@ -38,47 +50,59 @@ struct proc_info { uint8_t state; int32_t exit_code; int32_t k_status; + sigset_t sig_pending; + sigset_t sig_mask; + void* sig_handler[_SIG_NUM]; struct lx_timer* timer; }; extern volatile struct proc_info* __current; +pid_t +alloc_pid(); -pid_t alloc_pid(); - -void init_proc(struct proc_info *pcb); +void +init_proc(struct proc_info* pcb); /** * @brief 向系统发布一个进程,使其可以被调度。 - * - * @param process + * + * @param process */ -void push_process(struct proc_info* process); +void +push_process(struct proc_info* process); -pid_t destroy_process(pid_t pid); +pid_t +destroy_process(pid_t pid); -void setup_proc_mem(struct proc_info* proc, uintptr_t kstack_from); +void +setup_proc_mem(struct proc_info* proc, uintptr_t kstack_from); /** * @brief 复制当前进程(LunaixOS的类 fork (unix) 实现) - * + * */ -pid_t dup_proc(); +pid_t +dup_proc(); /** * @brief 创建新进程(LunaixOS的类 CreateProcess (Windows) 实现) - * + * */ -void new_proc(); +void +new_proc(); /** * @brief 终止(退出)当前进程 - * + * */ -void terminate_proc(int exit_code); +void +terminate_proc(int exit_code); -int orphaned_proc(pid_t pid); +int +orphaned_proc(pid_t pid); -struct proc_info* get_process(pid_t pid); +struct proc_info* +get_process(pid_t pid); #endif /* __LUNAIX_PROCESS_H */ diff --git a/lunaix-os/includes/lunaix/signal.h b/lunaix-os/includes/lunaix/signal.h new file mode 100644 index 0000000..c98441a --- /dev/null +++ b/lunaix-os/includes/lunaix/signal.h @@ -0,0 +1,29 @@ +#ifndef __LUNAIX_SIGNAL_H +#define __LUNAIX_SIGNAL_H + +#define _SIG_NUM 8 + +#define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig))) + +#define _SIGSEGV 0 +#define _SIGALRM 1 +#define _SIGCHLD 2 +#define _SIGCLD SIGCHLD +#define _SIGINT 3 +#define _SIGKILL 4 +#define _SIGSTOP 5 +#define _SIGCONT 6 + +#define _SIGNAL_UNMASKABLE ((1 << _SIGKILL) | (1 << _SIGSTOP)) + +#define _SIG_BLOCK 1 +#define _SIG_UNBLOCK 2 +#define _SIG_SETMASK 3 + +typedef unsigned int sigset_t; +typedef void (*sighandler_t)(int); + +void +signal_dispatch(); + +#endif /* __LUNAIX_SIGNAL_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index c19d501..9cb7764 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -13,6 +13,10 @@ #define __SYSCALL__exit 8 #define __SYSCALL_wait 9 #define __SYSCALL_waitpid 10 +#define __SYSCALL_sigreturn 11 +#define __SYSCALL_sigprocmask 12 +#define __SYSCALL_signal 13 +#define __SYSCALL_pause 14 #define __SYSCALL_MAX 0x100 @@ -52,7 +56,7 @@ syscall(unsigned int callcode) asmlinkage rettype __lxsys_##name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3)) #define __DEFINE_LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \ - asmlinkage rettype __lxsys_##nam( \ + asmlinkage rettype __lxsys_##name( \ __PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4)) #define __LXSYSCALL(rettype, name) \ diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index e0cda17..62c9ec5 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -1,6 +1,7 @@ #define __ASM__ #include #include +#include #define __ASM_INTR_DIAGNOSIS .macro isr_template vector, no_error_code=1 @@ -38,10 +39,10 @@ interrupt_wrapper: /* - Stack layout + Stack layout (layout of struct isr_param) msa: [ss] [esp] - eflags + eflags > offset = 48 + 16 = 64 cs eip err_code @@ -62,6 +63,7 @@ las: Least Significant Address msa: Most Significant Address */ + cld pushl %esp subl $16, %esp @@ -88,6 +90,12 @@ movw %ax, %ds movw %ax, %es + # 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息, + # 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备 + movl (__current), %eax + movl 68(%esp), %ebx # 取出esp + movl %ebx, 84(%eax) # 存入__current->ustack_top + 1: movl %esp, %eax andl $0xfffffff0, %esp @@ -98,6 +106,7 @@ .global soft_iret soft_iret: + cli popl %esp popl %eax @@ -124,3 +133,39 @@ popl %eax #endif iret + + handle_signal: + # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性! + # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈! + popl %eax # arg1: addr of proc_sig structure in user stack + leal 8(%eax), %ebx + + pushl 72(%ebx) # proc_sig->prev_context.ss + pushl %eax # esp + pushl 64(%ebx) # proc_sig->prev_context.eflags + pushl $UCODE_SEG # cs + pushl $sig_wrapper # eip for sig wrapper + + movw $UDATA_SEG, %cx # switch data seg to user mode + movw %cx, %es + movw %cx, %ds + movw %cx, %fs + movw %cx, %gs + + iret + + sig_wrapper: # in user mode + movl %esp, %eax + and $0xfffffff0, %esp + subl $8, %esp + pushl %eax # Addr to proc_sig structure + pushl 4(%eax) # proc_sig->sig_num ---- 16 bytes aligned + + call (%eax) # invoke signal handler + + # invoke the sigreturn syscall to exit the signal wrapper + movl $__SYSCALL_sigreturn, %eax + movl 4(%esp), %ebx + int $LUNAIX_SYS_CALL + + ud2 # never reach! \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index 2e36196..e97cc6f 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -18,6 +18,9 @@ .long __lxsys_exit .long __lxsys_wait .long __lxsys_waitpid /* 10 */ + .long __lxsys_sigreturn + .long __lxsys_sigprocmask + .long __lxsys_signal 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 @@ -58,6 +61,4 @@ popl %ebp - ret - - + ret \ No newline at end of file diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index 442921e..7f124c4 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -1,12 +1,14 @@ #include #include + #include #include + #include #include #include #include - +#include #include #include #include @@ -58,6 +60,8 @@ run(struct proc_info* proc) apic_done_servicing(); + signal_dispatch(); + asm volatile("pushl %0\n" "jmp soft_iret\n" ::"r"(&__current->intr_ctx) : "memory"); diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c new file mode 100644 index 0000000..3edb2f4 --- /dev/null +++ b/lunaix-os/kernel/signal.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +extern struct scheduler sched_ctx; /* kernel/sched.c */ + +void* default_handlers[_SIG_NUM] = { + // TODO: 添加默认handler +}; + +void +signal_dispatch() +{ + // if (!(SEL_RPL(__current->intr_ctx.cs))) { + // // 同特权级间调度不进行信号处理 + // return; + // } + + if (!__current->sig_pending) { + // 没有待处理信号 + return; + } + + int sig_selected = + 31 - __builtin_clz(__current->sig_pending & ~__current->sig_mask); + + __current->sig_pending = __current->sig_pending & ~(1 << sig_selected); + + if (!__current->sig_handler[sig_selected] && + !default_handlers[sig_selected]) { + // 如果该信号没有handler,则忽略 + return; + } + + uintptr_t ustack = __current->ustack_top; + + if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) { + // 用户栈没有空间存放信号上下文 + return; + } + + struct proc_sig* sig_ctx = + (struct proc_sig*)(ustack - sizeof(struct proc_sig)); + + sig_ctx->prev_context = __current->intr_ctx; + sig_ctx->sig_num = sig_selected; + sig_ctx->signal_handler = __current->sig_handler[sig_selected]; + + if (!sig_ctx->signal_handler) { + // 如果没有用户自定义的Handler,则使用系统默认Handler。 + sig_ctx->signal_handler = default_handlers[sig_selected]; + } + + asm volatile("pushl %0\n" + "jmp handle_signal" ::"r"(sig_ctx)); +} + +__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) +{ + __current->intr_ctx = sig_ctx->prev_context; + schedule(); +} + +__DEFINE_LXSYSCALL3(int, + sigprocmask, + int, + how, + const sigset_t, + *set, + sigset_t, + *oldset) +{ + *oldset = __current->sig_mask; + if (how == _SIG_BLOCK) { + __current->sig_mask |= *set; + } else if (how == _SIG_UNBLOCK) { + __current->sig_mask &= ~(*set); + } else if (how == _SIG_SETMASK) { + __current->sig_mask = *set; + } else { + return 0; + } + __current->sig_mask &= ~_SIGNAL_UNMASKABLE; + return 1; +} + +__DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) +{ + if (signum < 0 || signum >= _SIG_NUM) { + return -1; + } + + if (((1 << signum) & _SIGNAL_UNMASKABLE)) { + return -1; + } + + __current->sig_handler[signum] = (void*)handler; + + return 0; +} \ No newline at end of file -- 2.27.0