From c81bdac897a74f581605f3b4c7b4daccfb77a0c0 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 29 May 2024 11:06:15 -0300 Subject: [PATCH] signals: handle SIGBUS, SIGSEGV, SIGILL etc --- kernel-src/arch/x86-64/cpu.c | 18 ++++++++++++++++++ kernel-src/arch/x86-64/mmu.c | 10 +++++++++- kernel-src/mm/vmm.c | 5 +++-- kernel-src/sys/signal.c | 4 +++- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/kernel-src/arch/x86-64/cpu.c b/kernel-src/arch/x86-64/cpu.c index b3602e1a..b4275685 100644 --- a/kernel-src/arch/x86-64/cpu.c +++ b/kernel-src/arch/x86-64/cpu.c @@ -7,6 +7,21 @@ #define EFER_SYSCALLENABLE 1 void arch_syscall_entry(); +static void illisr(isr_t *self, context_t *ctx) { + if (ARCH_CONTEXT_ISUSER(ctx)) { + signal_signalthread(_cpu()->thread, SIGILL, true); + } else { + _panic("Invalid Opcode", ctx); + } +} + +static void div0isr(isr_t *self, context_t *ctx) { + if (ARCH_CONTEXT_ISUSER(ctx)) { + signal_signalthread(_cpu()->thread, SIGFPE, true); + } else { + _panic("Division by 0", ctx); + } +} void cpu_initstate() { arch_apic_initap(); @@ -49,4 +64,7 @@ void cpu_initstate() { "mov %%rax, %%cr0;" : : : "rax" ); + + interrupt_register(0, div0isr, NULL, IPL_IGNORE); + interrupt_register(6, illisr, NULL, IPL_IGNORE); } diff --git a/kernel-src/arch/x86-64/mmu.c b/kernel-src/arch/x86-64/mmu.c index 00040eed..09c075ec 100644 --- a/kernel-src/arch/x86-64/mmu.c +++ b/kernel-src/arch/x86-64/mmu.c @@ -278,10 +278,17 @@ static void pfisr(isr_t *self, context_t *ctx) { if (ARCH_CONTEXT_ISUSER(ctx)) signal_signalthread(_cpu()->thread, SIGSEGV, true); else - _panic("Page fault", ctx); + _panic("Page Fault", ctx); } } +static void gpfisr(isr_t *self, context_t *ctx) { + if (ARCH_CONTEXT_ISUSER(ctx)) + signal_signalthread(_cpu()->thread, SIGSEGV, true); + else + _panic("General Protection Fault", ctx); +} + void arch_mmu_init() { template = pmm_allocpage(PMM_SECTION_DEFAULT); __assert(template); @@ -326,6 +333,7 @@ void arch_mmu_init() { void arch_mmu_apswitch() { arch_mmu_switch(FROM_HHDM(template)); + interrupt_register(13, gpfisr, NULL, IPL_IGNORE); interrupt_register(14, pfisr, NULL, IPL_IGNORE); interrupt_register(0xfe, arch_mmu_tlbipi, ARCH_EOI, IPL_IGNORE); } diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index dd092518..a6057710 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -363,8 +363,9 @@ bool vmm_pagefault(void *addr, bool user, int actions) { page_t *res = NULL; int error = vmmcache_getpage(range->vnode, range->offset + mapoffset, &res); if (error == ENXIO) { - // TODO if error returned == ENXIO, raise an urgent SIGBUS on the calling thread - __assert(!"TODO: sigbus"); + // address is past the last page of the file + signal_signalthread(_cpu()->thread, SIGBUS, true); + status = true; } else if (error) { printf("vmm: error on vmmcache_getpage(): %d\n", error); status = false; diff --git a/kernel-src/sys/signal.c b/kernel-src/sys/signal.c index d2a18048..f5b65174 100644 --- a/kernel-src/sys/signal.c +++ b/kernel-src/sys/signal.c @@ -325,6 +325,7 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin goto leave; } // if not, just sleep. the sigcont won't be sent until THREAD_LEAVE and preparesleep is protecting it from a lost wakeup + context_t savecontext = *context; // save context as it could be overwritten if, for example, its the thread->context one sched_preparesleep(false); thread->signals.stopped = true; THREAD_LEAVE(thread); @@ -334,6 +335,7 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin // make sure a SIGCONT happened __assert(SIGNAL_GET(&thread->signals.pending, SIGCONT)); __assert(thread->signals.stopped == false); + *context = savecontext; // restore saved context // the stopped variable is already set by the signaling function // see if theres any other signal to deal with (such as the SIGCONT handler) return true; @@ -352,7 +354,7 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin // get where in memory to put the frame void *stack = altstack ? altstack : (void *)CTX_SP(context); #if ARCH_SIGNAL_STACK_GROWS_DOWNWARDS == 1 - stack = (void *)(((uintptr_t)stack - ARCH_SIGNAL_REDZONE_SIZE - sizeof(sigframe_t)) & ~0xf); + stack = (void *)(((uintptr_t)stack - ARCH_SIGNAL_REDZONE_SIZE - sizeof(sigframe_t)) & ~0xfl); #else #error unsupported #endif