From dcd4d0daeb9aff8c0e5770981ef236846217619f Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 21 Jul 2023 15:45:02 +0300 Subject: [PATCH] Kernel/LibC: Add bareboness signals You can now call raise() to raise a signal. Signal handlers are not yet supported, but the handling works :) --- kernel/CMakeLists.txt | 1 + kernel/arch/x86_64/PageTable.cpp | 11 +++++++ kernel/arch/x86_64/Signal.S | 51 ++++++++++++++++++++++++++++++++ kernel/arch/x86_64/linker.ld | 8 ++++- kernel/include/kernel/Process.h | 4 +++ kernel/kernel/Process.cpp | 24 +++++++++++++++ kernel/kernel/Syscall.cpp | 3 ++ kernel/kernel/kernel.cpp | 4 +-- libc/CMakeLists.txt | 1 + libc/include/signal.h | 3 ++ libc/include/sys/syscall.h | 1 + libc/signal.cpp | 8 +++++ libc/unistd.cpp | 6 ++++ userspace/Shell/main.cpp | 4 +++ 14 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 kernel/arch/x86_64/Signal.S create mode 100644 libc/signal.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 91af117d6..e024ef654 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -75,6 +75,7 @@ if("${BANAN_ARCH}" STREQUAL "x86_64") arch/x86_64/IDT.cpp arch/x86_64/interrupts.S arch/x86_64/PageTable.cpp + arch/x86_64/Signal.S arch/x86_64/Thread.S ) elseif("${BANAN_ARCH}" STREQUAL "i386") diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index a290195ad..c009269a4 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -11,6 +11,9 @@ extern uint8_t g_kernel_end[]; extern uint8_t g_kernel_execute_start[]; extern uint8_t g_kernel_execute_end[]; +extern uint8_t g_userspace_start[]; +extern uint8_t g_userspace_end[]; + namespace Kernel { @@ -120,6 +123,14 @@ namespace Kernel g_kernel_execute_end - g_kernel_execute_start, Flags::Execute | Flags::Present ); + + // Map userspace memory + map_range_at( + V2P(g_userspace_start), + (vaddr_t)g_userspace_start, + g_userspace_end - g_userspace_start, + Flags::Execute | Flags::UserSupervisor | Flags::Present + ); } BAN::ErrorOr PageTable::create_userspace() diff --git a/kernel/arch/x86_64/Signal.S b/kernel/arch/x86_64/Signal.S new file mode 100644 index 000000000..1c565d435 --- /dev/null +++ b/kernel/arch/x86_64/Signal.S @@ -0,0 +1,51 @@ +.section .userspace, "aw" + +.global signal_trampoline +signal_trampoline: + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rbp + pushq %rdi + pushq %rsi + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + xchgw %bx, %bx + + movq 128(%rsp), %rdi + movq 120(%rsp), %rax + call *%rax + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rsi + popq %rdi + popq %rbp + popq %rdx + popq %rcx + popq %rbx + popq %rax + + addq $16, %rsp + + ret + +.global test_signal +test_signal: + movq $99, %rax + int $0x80 + ret \ No newline at end of file diff --git a/kernel/arch/x86_64/linker.ld b/kernel/arch/x86_64/linker.ld index 4e37c00c0..14dbf3894 100644 --- a/kernel/arch/x86_64/linker.ld +++ b/kernel/arch/x86_64/linker.ld @@ -11,7 +11,13 @@ SECTIONS { g_kernel_execute_start = .; *(.multiboot) - *(.text) + *(.text.*) + } + .userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET) + { + g_userspace_start = .; + *(.userspace) + g_userspace_end = .; } .rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET) { diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 997d1ecf5..2dd291a75 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -100,6 +100,10 @@ namespace Kernel BAN::ErrorOr sys_alloc(size_t); BAN::ErrorOr sys_free(void*); + BAN::ErrorOr sys_signal(int, void (*)(int)); + BAN::ErrorOr sys_kill(pid_t pid, int signal); + BAN::ErrorOr sys_raise(int signal, uintptr_t& return_rsp, uintptr_t& return_rip); + BAN::ErrorOr sys_termid(char*) const; BAN::ErrorOr sys_clock_gettime(clockid_t, timespec*) const; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 3e861999c..1f8d18b18 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -14,6 +14,9 @@ #include #include +extern "C" void signal_trampoline(); +extern "C" void test_signal(); + namespace Kernel { @@ -788,6 +791,27 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_raise(int signal, uintptr_t& return_rsp, uintptr_t& return_rip) + { + if (signal < _SIGMIN || signal > _SIGMAX) + return BAN::Error::from_errno(EINVAL); + + ASSERT(&Process::current() == this); + + LockGuard lock_guard(m_lock); + asm volatile("cli"); + + uintptr_t* return_rsp_ptr = (uintptr_t*)return_rsp; + *--return_rsp_ptr = return_rip; + *--return_rsp_ptr = signal; + *--return_rsp_ptr = (uintptr_t)test_signal; + + return_rsp = (uintptr_t)return_rsp_ptr; + return_rip = (uintptr_t)signal_trampoline; + + return 0; + } + BAN::ErrorOr Process::sys_setuid(uid_t uid) { if (uid < 0 || uid >= 1'000'000'000) diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 219828ffb..1171a87d0 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -140,6 +140,9 @@ namespace Kernel case SYS_DUP2: ret = Process::current().sys_dup2((int)arg1, (int)arg2); break; + case SYS_RAISE: + ret = Process::current().sys_raise((int)arg1, interrupt_stack.rsp, interrupt_stack.rip); + break; default: dwarnln("Unknown syscall {}", syscall); break; diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index feaf010d0..2da4c5fb7 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -98,8 +98,8 @@ namespace BAN::Formatter } -extern "C" uintptr_t g_kernel_start; -extern "C" uintptr_t g_kernel_end; +extern "C" uint8_t g_userspace_start[]; +extern "C" uint8_t g_userspace_end[]; static void init2(void*); diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 85d4103d1..d11defbdc 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -9,6 +9,7 @@ set(LIBC_SOURCES fcntl.cpp printf_impl.cpp pwd.cpp + signal.cpp stdio.cpp stdlib.cpp string.cpp diff --git a/libc/include/signal.h b/libc/include/signal.h index ff62b93fe..a1a042a4f 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -74,6 +74,9 @@ struct sigevent #define SIGRTMIN 29 #define SIGRTMAX (SIGRTMIN+32) +#define _SIGMIN SIGABRT +#define _SIGMAX SIGRTMAX + #define SIG_BLOCK 1 #define SIG_UNBLOCK 2 #define SIG_SETMASK 3 diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 32be089ea..677f694e6 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -41,6 +41,7 @@ __BEGIN_DECLS #define SYS_CLOCK_GETTIME 34 #define SYS_PIPE 35 #define SYS_DUP2 36 +#define SYS_RAISE 37 __END_DECLS diff --git a/libc/signal.cpp b/libc/signal.cpp new file mode 100644 index 000000000..b15dfad6f --- /dev/null +++ b/libc/signal.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +int raise(int sig) +{ + return syscall(SYS_RAISE, sig); +} \ No newline at end of file diff --git a/libc/unistd.cpp b/libc/unistd.cpp index 5ca5e3203..1b15a2250 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -266,6 +266,12 @@ long syscall(long syscall, ...) ret = Kernel::syscall(SYS_DUP2, fildes, fildes2); break; } + case SYS_RAISE: + { + int signal = va_arg(args, int); + ret = Kernel::syscall(SYS_RAISE, signal); + break; + } default: puts("LibC: Unhandeled syscall"); ret = -ENOSYS; diff --git a/userspace/Shell/main.cpp b/userspace/Shell/main.cpp index 74325842f..4d119d550 100644 --- a/userspace/Shell/main.cpp +++ b/userspace/Shell/main.cpp @@ -260,6 +260,10 @@ int execute_command(BAN::Vector& args) while (*current) printf("%s\n", *current++); } + else if (args.front() == "raise"sv) + { + raise(SIGSEGV); + } else if (args.front() == "cd"sv) { if (args.size() > 2)