]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
signal: add SA_SIGINFO and sigaction ABI
authorTulio A M Mendes <[email protected]>
Mon, 9 Feb 2026 23:25:14 +0000 (20:25 -0300)
committerTulio A M Mendes <[email protected]>
Mon, 9 Feb 2026 23:25:14 +0000 (20:25 -0300)
Makefile
include/process.h
include/signal.h [new file with mode: 0644]
src/arch/x86/idt.c
src/kernel/syscall.c
user/init.c

index f635b928e63e6e10cd7c79ef921eb659a86ded45..582d1aaad4b53bb9248117f73ef5f17fc48f6d62 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -119,10 +119,10 @@ $(MKINITRD): tools/mkinitrd.c
        @gcc tools/mkinitrd.c -o $(MKINITRD)
 
 $(USER_ELF): user/init.c user/linker.ld
-       @i686-elf-gcc -m32 -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(USER_ELF) user/init.c user/errno.c
+       @i686-elf-gcc -m32 -I include -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(USER_ELF) user/init.c user/errno.c
 
 $(ECHO_ELF): user/echo.c user/linker.ld
-       @i686-elf-gcc -m32 -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(ECHO_ELF) user/echo.c user/errno.c
+       @i686-elf-gcc -m32 -I include -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(ECHO_ELF) user/echo.c user/errno.c
 
 $(INITRD_IMG): $(MKINITRD) $(USER_ELF) $(ECHO_ELF)
        @./$(MKINITRD) $(INITRD_IMG) $(USER_ELF):bin/init.elf $(ECHO_ELF):bin/echo.elf
index 7065bd4767cf6a3ce880f7b870131c3ae8648077..c1aee4893f9357b63b9d91515cc9d7c1d85383ba 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdint.h>
 #include "idt.h" // For struct registers
 #include "fs.h"
+#include "signal.h"
 
 typedef enum {
     PROCESS_READY,
@@ -39,14 +40,17 @@ struct process {
     int has_user_regs;
     struct registers user_regs;
 
-    // Minimal signals: handler pointers, blocked mask and pending mask.
-    // handlers[i] == 0 => default
-    // handlers[i] == 1 => ignore
-    // handlers[i] >= 2 => user handler address
-    uintptr_t sig_handlers[PROCESS_MAX_SIG];
+    // Minimal signals: per-signal action, blocked mask and pending mask.
+    // sa_handler == 0 => default
+    // sa_handler == 1 => ignore
+    // sa_handler >= 2 => user handler address
+    struct sigaction sigactions[PROCESS_MAX_SIG];
     uint32_t sig_blocked_mask;
     uint32_t sig_pending_mask;
 
+    // For SIGSEGV: last page fault address (CR2) captured in ring3.
+    uintptr_t last_fault_addr;
+
     int waiting;
     int wait_pid;
     int wait_result_pid;
diff --git a/include/signal.h b/include/signal.h
new file mode 100644 (file)
index 0000000..e6b0973
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef SIGNAL_H
+#define SIGNAL_H
+
+#include <stdint.h>
+
+#define SA_SIGINFO 0x00000004U
+
+struct sigaction {
+    uintptr_t sa_handler;
+    uintptr_t sa_sigaction;
+    uint32_t sa_mask;
+    uint32_t sa_flags;
+};
+
+struct siginfo {
+    int si_signo;
+    int si_code;
+    void* si_addr;
+};
+
+typedef struct siginfo siginfo_t;
+
+struct ucontext {
+    uint32_t reserved;
+};
+
+typedef struct ucontext ucontext_t;
+
+#endif
index f8373f2c1c2724b0ffaf41eb832d5f096bd15569..c0e32ac5d8a2a7349493d9abb9179b6176b13047 100644 (file)
@@ -5,6 +5,7 @@
 #include "spinlock.h"
 #include "uaccess.h"
 #include "syscall.h"
+#include "signal.h"
 #include <stddef.h>
 
 #define IDT_ENTRIES 256
@@ -70,7 +71,8 @@ static void deliver_signals_to_usermode(struct registers* regs) {
 
     current_process->sig_pending_mask &= ~(1U << (uint32_t)sig);
 
-    const uintptr_t h = current_process->sig_handlers[sig];
+    const struct sigaction act = current_process->sigactions[sig];
+    const uintptr_t h = (act.sa_flags & SA_SIGINFO) ? act.sa_sigaction : act.sa_handler;
     if (h == 1) {
         return;
     }
@@ -87,19 +89,37 @@ static void deliver_signals_to_usermode(struct registers* regs) {
 
     // Build a sigframe + a tiny user trampoline that calls SYSCALL_SIGRETURN.
     // Stack layout at handler entry (regs->useresp):
-    //   [esp+0] return address -> trampoline
-    //   [esp+4] int sig
-    // Below that: trampoline code bytes, below that: sigframe.
+    //   non-SA_SIGINFO:
+    //     [esp+0] return address -> trampoline
+    //     [esp+4] int sig
+    //   SA_SIGINFO:
+    //     [esp+0] return address -> trampoline
+    //     [esp+4] int sig
+    //     [esp+8] siginfo_t*
+    //     [esp+12] ucontext_t*
+    // Below that: trampoline code bytes, below that: siginfo + ucontext + sigframe.
 
     struct sigframe f;
     f.magic = SIGFRAME_MAGIC;
     f.saved = *regs;
 
     const uint32_t tramp_size = 14U;
-    const uint32_t base = regs->useresp - (8U + tramp_size + (uint32_t)sizeof(f));
+    const uint32_t callframe_size = (act.sa_flags & SA_SIGINFO) ? 16U : 8U;
+
+    struct siginfo info;
+    info.si_signo = sig;
+    info.si_code = 1;
+    info.si_addr = (sig == 11) ? (void*)current_process->last_fault_addr : NULL;
+
+    struct ucontext uctx;
+    uctx.reserved = 0;
+
+    const uint32_t base = regs->useresp - (callframe_size + tramp_size + (uint32_t)sizeof(info) + (uint32_t)sizeof(uctx) + (uint32_t)sizeof(f));
     const uint32_t retaddr_slot = base;
-    const uint32_t tramp_addr = base + 8U;
-    const uint32_t sigframe_addr = tramp_addr + tramp_size;
+    const uint32_t tramp_addr = base + callframe_size;
+    const uint32_t siginfo_addr = tramp_addr + tramp_size;
+    const uint32_t uctx_addr = siginfo_addr + (uint32_t)sizeof(info);
+    const uint32_t sigframe_addr = uctx_addr + (uint32_t)sizeof(uctx);
 
     // Trampoline bytes:
     //   mov eax, SYSCALL_SIGRETURN
@@ -128,6 +148,8 @@ static void deliver_signals_to_usermode(struct registers* regs) {
     tramp[9] = (uint8_t)((sigframe_addr >> 24) & 0xFFU);
 
     if (copy_to_user((void*)(uintptr_t)sigframe_addr, &f, sizeof(f)) < 0 ||
+        copy_to_user((void*)(uintptr_t)siginfo_addr, &info, sizeof(info)) < 0 ||
+        copy_to_user((void*)(uintptr_t)uctx_addr, &uctx, sizeof(uctx)) < 0 ||
         copy_to_user((void*)(uintptr_t)tramp_addr, tramp, sizeof(tramp)) < 0) {
         const int SIG_SEGV = 11;
         process_exit_notify(128 + SIG_SEGV);
@@ -136,15 +158,30 @@ static void deliver_signals_to_usermode(struct registers* regs) {
         for (;;) __asm__ volatile("hlt");
     }
 
-    uint32_t callframe[2];
-    callframe[0] = tramp_addr;
-    callframe[1] = (uint32_t)sig;
-    if (copy_to_user((void*)(uintptr_t)retaddr_slot, callframe, sizeof(callframe)) < 0) {
-        const int SIG_SEGV = 11;
-        process_exit_notify(128 + SIG_SEGV);
-        __asm__ volatile("sti");
-        schedule();
-        for (;;) __asm__ volatile("hlt");
+    if ((act.sa_flags & SA_SIGINFO) == 0) {
+        uint32_t callframe[2];
+        callframe[0] = tramp_addr;
+        callframe[1] = (uint32_t)sig;
+        if (copy_to_user((void*)(uintptr_t)retaddr_slot, callframe, sizeof(callframe)) < 0) {
+            const int SIG_SEGV = 11;
+            process_exit_notify(128 + SIG_SEGV);
+            __asm__ volatile("sti");
+            schedule();
+            for (;;) __asm__ volatile("hlt");
+        }
+    } else {
+        uint32_t callframe[4];
+        callframe[0] = tramp_addr;
+        callframe[1] = (uint32_t)sig;
+        callframe[2] = siginfo_addr;
+        callframe[3] = uctx_addr;
+        if (copy_to_user((void*)(uintptr_t)retaddr_slot, callframe, sizeof(callframe)) < 0) {
+            const int SIG_SEGV = 11;
+            process_exit_notify(128 + SIG_SEGV);
+            __asm__ volatile("sti");
+            schedule();
+            for (;;) __asm__ volatile("hlt");
+        }
     }
 
     regs->useresp = retaddr_slot;
@@ -290,6 +327,9 @@ void isr_handler(struct registers* regs) {
                 if ((regs->cs & 3U) == 3U) {
                     const int SIG_SEGV = 11;
                     if (current_process) {
+                        uint32_t cr2;
+                        __asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
+                        current_process->last_fault_addr = (uintptr_t)cr2;
                         current_process->sig_pending_mask |= (1U << (uint32_t)SIG_SEGV);
                     }
                     deliver_signals_to_usermode(regs);
index 4af02cda8cb73b6ae02095ba6271d4eccdddd01f..1e42f847f676e235f5f77cd852b78cc83f331545 100644 (file)
@@ -897,17 +897,24 @@ static int syscall_getpgrp_impl(void) {
     return (int)current_process->pgrp_id;
 }
 
-static int syscall_sigaction_impl(int sig, uintptr_t handler, uintptr_t* old_out) {
+static int syscall_sigaction_impl(int sig, const struct sigaction* user_act, struct sigaction* user_oldact) {
     if (!current_process) return -EINVAL;
     if (sig <= 0 || sig >= PROCESS_MAX_SIG) return -EINVAL;
 
-    if (old_out) {
-        if (user_range_ok(old_out, sizeof(*old_out)) == 0) return -EFAULT;
-        uintptr_t oldh = current_process->sig_handlers[sig];
-        if (copy_to_user(old_out, &oldh, sizeof(oldh)) < 0) return -EFAULT;
+    if (user_oldact) {
+        if (user_range_ok(user_oldact, sizeof(*user_oldact)) == 0) return -EFAULT;
+        struct sigaction old = current_process->sigactions[sig];
+        if (copy_to_user(user_oldact, &old, sizeof(old)) < 0) return -EFAULT;
+    }
+
+    if (!user_act) {
+        return 0;
     }
 
-    current_process->sig_handlers[sig] = handler;
+    if (user_range_ok(user_act, sizeof(*user_act)) == 0) return -EFAULT;
+    struct sigaction act;
+    if (copy_from_user(&act, user_act, sizeof(act)) < 0) return -EFAULT;
+    current_process->sigactions[sig] = act;
     return 0;
 }
 
@@ -1155,9 +1162,9 @@ static void syscall_handler(struct registers* regs) {
 
     if (syscall_no == SYSCALL_SIGACTION) {
         int sig = (int)regs->ebx;
-        uintptr_t handler = (uintptr_t)regs->ecx;
-        uintptr_t* old_out = (uintptr_t*)regs->edx;
-        regs->eax = (uint32_t)syscall_sigaction_impl(sig, handler, old_out);
+        const struct sigaction* act = (const struct sigaction*)regs->ecx;
+        struct sigaction* oldact = (struct sigaction*)regs->edx;
+        regs->eax = (uint32_t)syscall_sigaction_impl(sig, act, oldact);
         return;
     }
 
index a7a0ef77cfff61bbe3eb8a895f7a9a3346162512..4095acb7cae46d21e13aa6062660276a153f9a28 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "user_errno.h"
 
+#include "signal.h"
+
 enum {
     SYSCALL_WRITE = 1,
     SYSCALL_EXIT  = 2,
@@ -173,17 +175,35 @@ static void write_hex32(uint32_t v) {
     (void)sys_write(1, b, 8);
 }
 
-static int sys_sigaction(int sig, void (*handler)(int), uintptr_t* old_out) {
+static int sys_sigaction2(int sig, const struct sigaction* act, struct sigaction* oldact) {
     int ret;
     __asm__ volatile(
         "int $0x80"
         : "=a"(ret)
-        : "a"(SYSCALL_SIGACTION), "b"(sig), "c"(handler), "d"(old_out)
+        : "a"(SYSCALL_SIGACTION), "b"(sig), "c"(act), "d"(oldact)
         : "memory"
     );
     return __syscall_fix(ret);
 }
 
+static int sys_sigaction(int sig, void (*handler)(int), uintptr_t* old_out) {
+    struct sigaction act;
+    act.sa_handler = (uintptr_t)handler;
+    act.sa_sigaction = 0;
+    act.sa_mask = 0;
+    act.sa_flags = 0;
+
+    struct sigaction oldact;
+    struct sigaction* oldp = old_out ? &oldact : 0;
+
+    int r = sys_sigaction2(sig, &act, oldp);
+    if (r < 0) return r;
+    if (old_out) {
+        *old_out = oldact.sa_handler;
+    }
+    return 0;
+}
+
 static int sys_select(uint32_t nfds, uint64_t* readfds, uint64_t* writefds, uint64_t* exceptfds, int32_t timeout) {
     int ret;
     __asm__ volatile(
@@ -462,6 +482,17 @@ static void sigsegv_exit_handler(int sig) {
     sys_exit(0);
 }
 
+static void sigsegv_info_handler(int sig, siginfo_t* info, void* uctx) {
+    (void)uctx;
+    static const char msg[] = "[init] SIGSEGV siginfo handler invoked\n";
+    (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+    const uintptr_t expected = 0x12345000U;
+    if (sig == SIGSEGV && info && (uintptr_t)info->si_addr == expected) {
+        sys_exit(0);
+    }
+    sys_exit(1);
+}
+
 void _start(void) {
     __asm__ volatile(
         "mov $0x23, %ax\n"
@@ -1385,13 +1416,19 @@ void _start(void) {
         }
 
         if (pid == 0) {
-            if (sys_sigaction(SIGSEGV, sigsegv_exit_handler, 0) < 0) {
+            struct sigaction act;
+            act.sa_handler = 0;
+            act.sa_sigaction = (uintptr_t)sigsegv_info_handler;
+            act.sa_mask = 0;
+            act.sa_flags = SA_SIGINFO;
+
+            if (sys_sigaction2(SIGSEGV, &act, 0) < 0) {
                 static const char msg[] = "[init] sigaction(SIGSEGV) failed\n";
                 (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
                 sys_exit(1);
             }
 
-            *(volatile uint32_t*)0x0 = 123;
+            *(volatile uint32_t*)0x12345000U = 123;
             sys_exit(2);
         }