diff --git a/kernel-src/include/kernel/signal.h b/kernel-src/include/kernel/signal.h index ab59892e..2d68a970 100644 --- a/kernel-src/include/kernel/signal.h +++ b/kernel-src/include/kernel/signal.h @@ -161,7 +161,7 @@ void signal_signalthread(struct thread_t *thread, int signal, bool urgent); void signal_pending(struct thread_t *, sigset_t *sigset); void signal_suspend(sigset_t *sigset); int signal_wait(sigset_t *sigset, timespec_t *timeout, siginfo_t *siginfo, int *signum); -bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uint64_t syscallret, uint64_t syscallerrno); +bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uint64_t syscallret, uint64_t syscallerrno, bool *need_context_switch); extern int signal_defaultactions[NSIG]; #endif diff --git a/kernel-src/include/x86-64/arch/signal.h b/kernel-src/include/x86-64/arch/signal.h index b395e486..76ce003d 100644 --- a/kernel-src/include/x86-64/arch/signal.h +++ b/kernel-src/include/x86-64/arch/signal.h @@ -9,13 +9,89 @@ #define ARCH_SIGNAL_GETFROMRETURN(x) +#define MCONTEXT_REG_R8 0 +#define MCONTEXT_REG_R9 1 +#define MCONTEXT_REG_R10 2 +#define MCONTEXT_REG_R11 3 +#define MCONTEXT_REG_R12 4 +#define MCONTEXT_REG_R13 5 +#define MCONTEXT_REG_R14 6 +#define MCONTEXT_REG_R15 7 +#define MCONTEXT_REG_RDI 8 +#define MCONTEXT_REG_RSI 9 +#define MCONTEXT_REG_RBP 10 +#define MCONTEXT_REG_RBX 11 +#define MCONTEXT_REG_RDX 12 +#define MCONTEXT_REG_RAX 13 +#define MCONTEXT_REG_RCX 14 +#define MCONTEXT_REG_RSP 15 +#define MCONTEXT_REG_RIP 16 +#define MCONTEXT_REG_EFL 17 +#define MCONTEXT_REG_CSGSFS 18 +#define MCONTEXT_REG_ERR 19 +#define MCONTEXT_REG_TRAPNO 20 +#define MCONTEXT_REG_OLDMASK 21 +#define MCONTEXT_REG_CR2 22 +#define MCONTEXT_NGREG 23 + typedef struct { - void *restorer; + unsigned long gregs[MCONTEXT_NGREG]; + uint8_t fpu_state[512]; + unsigned long __reserved1[8]; +} mcontext_t; + +// this structure should have a part of it matching the ucontext from the abi +// which then gets its address returned by the ARCH_SIGFRAME_GET_UCONTEXT_POINTER macro +typedef struct { + void *restorer; // for return from signal + + // ucontext starts here + unsigned long uc_flags; // can be zero + void *uc_link; // unused for signals stack_t oldstack; + mcontext_t mcontext; sigset_t oldmask; + + // astral bits context_t context; extracontext_t extracontext; siginfo_t siginfo; } sigframe_t; +#define ARCH_SIGFRAME_GET_UCONTEXT_POINTER(x) (&(x)->uc_flags) + +static inline void arch_sigframe_prepare_mcontext(sigframe_t *sigframe) { + context_t *context = &sigframe->context; + extracontext_t *extracontext = &sigframe->extracontext; + unsigned long *gregs = sigframe->mcontext.gregs; + uint8_t *fpu_state = sigframe->mcontext.fpu_state; + + gregs[MCONTEXT_REG_R8] = context->r8; + gregs[MCONTEXT_REG_R9] = context->r9; + gregs[MCONTEXT_REG_R10] = context->r10; + gregs[MCONTEXT_REG_R11] = context->r11; + gregs[MCONTEXT_REG_R12] = context->r12; + gregs[MCONTEXT_REG_R13] = context->r13; + gregs[MCONTEXT_REG_R14] = context->r14; + gregs[MCONTEXT_REG_R15] = context->r15; + gregs[MCONTEXT_REG_RDI] = context->rdi; + gregs[MCONTEXT_REG_RSI] = context->rsi; + gregs[MCONTEXT_REG_RBP] = context->rbp; + gregs[MCONTEXT_REG_RBX] = context->rbx; + gregs[MCONTEXT_REG_RDX] = context->rdx; + gregs[MCONTEXT_REG_RAX] = context->rax; + gregs[MCONTEXT_REG_RCX] = context->rcx; + gregs[MCONTEXT_REG_RSP] = context->rsp; + gregs[MCONTEXT_REG_RIP] = context->rip; + gregs[MCONTEXT_REG_EFL] = context->rflags; + gregs[MCONTEXT_REG_CSGSFS] = 0; + gregs[MCONTEXT_REG_ERR] = context->error; + gregs[MCONTEXT_REG_TRAPNO] = 0; + gregs[MCONTEXT_REG_OLDMASK] = 0; + gregs[MCONTEXT_REG_CR2] = context->cr2; + + memcpy(fpu_state, extracontext->fx, 512); +} + + #endif diff --git a/kernel-src/sys/scheduler/scheduler.c b/kernel-src/sys/scheduler/scheduler.c index e118288e..c779d504 100644 --- a/kernel-src/sys/scheduler/scheduler.c +++ b/kernel-src/sys/scheduler/scheduler.c @@ -162,7 +162,7 @@ typedef struct { } checkargs_t; // SHOULD NOT BE CALLED WITH THE SCHEDULER STACK -static void userspacecheck(void *_args) { +static bool userspacecheck(void *_args) { checkargs_t *args = _args; thread_t *thread = current_thread(); @@ -171,7 +171,10 @@ static void userspacecheck(void *_args) { sched_threadexit(); } - while (signal_check(thread, args->context, args->syscall, args->syscallret, args->syscallerrno)) ; + bool need_context_switch = false; + + while (signal_check(thread, args->context, args->syscall, args->syscallret, args->syscallerrno, &need_context_switch)) ; + return need_context_switch; } static void checktrampoline(context_t *context, void *_args) { @@ -203,7 +206,10 @@ __attribute__((no_caller_saved_registers)) void sched_userspacecheck(context_t * if (&args < (checkargs_t *)current_cpu()->schedulerstack && &args >= (checkargs_t *)((uintptr_t)current_cpu()->schedulerstack - SCHEDULER_STACK_SIZE)) { arch_context_saveandcall(checktrampoline, current_thread()->kernelstacktop, &args); } else { - userspacecheck(&args); + if (userspacecheck(&args)) { + // need context switch + arch_context_switch(context); + } } current_cpu()->intstatus = intstatus; diff --git a/kernel-src/sys/signal.c b/kernel-src/sys/signal.c index c8958ede..13f08bd6 100644 --- a/kernel-src/sys/signal.c +++ b/kernel-src/sys/signal.c @@ -423,7 +423,7 @@ void signal_signalproc(struct proc_t *proc, int signal) { } // returns true if should retry check -bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uint64_t syscallret, uint64_t syscallerrno) { +bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uint64_t syscallret, uint64_t syscallerrno, bool *need_context_switch) { bool retry = false; proc_t *proc = thread->proc; @@ -563,6 +563,7 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin } memcpy(&sigframe.context, context, sizeof(context_t)); memcpy(&sigframe.extracontext, &thread->extracontext, sizeof(extracontext_t)); + arch_sigframe_prepare_mcontext(&sigframe); // TODO siginfo if (usercopy_touser(stack, &sigframe, sizeof(sigframe_t))) { @@ -591,11 +592,13 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin CTX_SP(context) = (uint64_t)stack; CTX_ARG0(context) = signal; CTX_ARG1(context) = 0; // TODO pass siginfo - CTX_ARG2(context) = 0; // TODO ucontext + CTX_ARG2(context) = (uint64_t)ARCH_SIGFRAME_GET_UCONTEXT_POINTER((sigframe_t*)stack); // reset handler if asked for if (action->flags & SA_RESETHAND) memset(action, 0, sizeof(sigaction_t)); + + *need_context_switch = true; } leave: