From 6a7ae04d2e57d2cbbc795319d074027527643bf3 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sat, 10 Sep 2016 09:59:18 +0200 Subject: [PATCH] add basic support to save / restore the user thread context - currently, signal handling is ignored! --- hermit/arch/x86/include/asm/stddef.h | 40 +++++++++++- hermit/arch/x86/kernel/Makefile | 2 +- hermit/arch/x86/kernel/entry.asm | 73 +++++++++++++++++++++ hermit/arch/x86/kernel/syscall.c | 98 ++++++++++++++++++++++++++++ hermit/include/hermit/syscall.h | 10 +++ hermit/usr/newlib | 2 +- 6 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 hermit/arch/x86/kernel/syscall.c diff --git a/hermit/arch/x86/include/asm/stddef.h b/hermit/arch/x86/include/asm/stddef.h index 2985ad5c6..c40070bde 100644 --- a/hermit/arch/x86/include/asm/stddef.h +++ b/hermit/arch/x86/include/asm/stddef.h @@ -114,7 +114,39 @@ typedef unsigned short wchar_t; typedef wchar_t wint_t; #endif -/// This defines what the stack looks like after the task context is saved. +/// This defines registers, which are saved for a "user-level" context swicth +typedef struct mregs { + /// R15 register + uint64_t r15; + /// R14 register + uint64_t r14; + /// R13 register + uint64_t r13; + /// R12 register + uint64_t r12; + /// R9 register + uint64_t r9; + /// R8 register + uint64_t r8; + /// RDI register + uint64_t rdi; + /// RSI register + uint64_t rsi; + /// RBP register + uint64_t rbp; + /// RBX register + uint64_t rbx; + /// RDX register + uint64_t rdx; + /// RCX register + uint64_t rcx; + /// RSP register + uint64_t rsp; + /// RIP + uint64_t rip; +} mregs_t; + +/// This defines what the stack looks like after the task context is saved struct state { /// GS register uint64_t gs; @@ -165,6 +197,12 @@ struct state { uint64_t ss; }; +typedef struct { + void *ss_sp; /* Stack base or pointer. */ + int ss_flags; /* Flags. */ + size_t ss_size; /* Stack size. */ +} stack_t; + const int32_t is_single_kernel(void); #ifdef __cplusplus diff --git a/hermit/arch/x86/kernel/Makefile b/hermit/arch/x86/kernel/Makefile index 06654ea4c..df969fd2f 100644 --- a/hermit/arch/x86/kernel/Makefile +++ b/hermit/arch/x86/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c pci.c vga.c uart.c +C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c pci.c vga.c uart.c syscall.c ASM_source := entry.asm string.asm MODULE := arch_x86_kernel diff --git a/hermit/arch/x86/kernel/entry.asm b/hermit/arch/x86/kernel/entry.asm index 46a000ea0..150f3f81c 100644 --- a/hermit/arch/x86/kernel/entry.asm +++ b/hermit/arch/x86/kernel/entry.asm @@ -493,6 +493,79 @@ isrsyscall: o64 sysret %endif +extern save_fpu_state +global getcontext +align 64 +getcontext: + cli + ; save general purpose regsiters + mov QWORD [rdi + 0x00], r15 + mov QWORD [rdi + 0x08], r14 + mov QWORD [rdi + 0x10], r13 + mov QWORD [rdi + 0x18], r12 + mov QWORD [rdi + 0x20], r9 + mov QWORD [rdi + 0x28], r8 + mov QWORD [rdi + 0x30], rdi + mov QWORD [rdi + 0x38], rsi + mov QWORD [rdi + 0x40], rbp + mov QWORD [rdi + 0x48], rbx + mov QWORD [rdi + 0x50], rdx + mov QWORD [rdi + 0x58], rcx + lea rax, [rsp + 0x08] + mov QWORD [rdi + 0x60], rax + mov rax, QWORD [rsp] + mov QWORD [rdi + 0x68], rax + ; restore FPU state + add rdi, 0x80 + call [save_fpu_state] + sub rdi, 0x80 + xor rax, rax + sti + ret + +extern restore_fpu_state +global setcontext +align 64 +setcontext: + cli + ; restore FPU state + add rdi, 0x80 + call [restore_fpu_state] + sub rdi, 0x80 + ; restore general purpose registers + mov r15, QWORD [rdi + 0x00] + mov r14, QWORD [rdi + 0x08] + mov r13, QWORD [rdi + 0x10] + mov r12, QWORD [rdi + 0x18] + mov r9, QWORD [rdi + 0x20] + mov r8, QWORD [rdi + 0x28] + mov rdi, QWORD [rdi + 0x30] + mov rsi, QWORD [rdi + 0x38] + mov rbp, QWORD [rdi + 0x40] + mov rbx, QWORD [rdi + 0x48] + mov rdx, QWORD [rdi + 0x50] + mov rcx, QWORD [rdi + 0x58] + mov rsp, QWORD [rdi + 0x60] + push QWORD [rdi + 0x68] + xor rax, rax + sti + ret + +global __startcontext +align 64 +__startcontext: + mov rsp, rbx + pop rdi + cmp rdi, 0 + je Lno_context + + call setcontext + +Lno_context: + extern exit + call exit + jmp $ + global switch_context align 64 switch_context: diff --git a/hermit/arch/x86/kernel/syscall.c b/hermit/arch/x86/kernel/syscall.c new file mode 100644 index 000000000..7de4d0203 --- /dev/null +++ b/hermit/arch/x86/kernel/syscall.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +void __startcontext(void); + +void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) +{ + va_list ap; + + if (BUILTIN_EXPECT(!ucp, 0)) + return; + + //kprintf("sys_makecontext %p, func %p, stack 0x%zx, task %d\n", ucp, func, ucp->uc_stack.ss_sp, per_core(current_task)->id); + + size_t* stack = (size_t*) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + stack -= (argc > 6 ? argc - 6 : 0) + 1; + uint32_t idx = (argc > 6 ? argc - 6 : 0) + 1; + + /* Align stack and reserve space for trampoline address. */ + stack = (size_t*) ((((size_t) stack) & ~0xFULL) - 0x8); + + /* Setup context */ + ucp->uc_mregs.rip = (size_t) func; + ucp->uc_mregs.rbx = (size_t) &stack[idx]; + ucp->uc_mregs.rsp = (size_t) stack; + + stack[0] = (size_t) &__startcontext; + stack[idx] = (size_t) ucp->uc_link; // link to the next context + + va_start(ap, argc); + for (int i = 0; i < argc; i++) + { + switch (i) + { + case 0: + ucp->uc_mregs.rdi = va_arg(ap, size_t); + break; + case 1: + ucp->uc_mregs.rsi = va_arg(ap, size_t); + break; + case 2: + ucp->uc_mregs.rdx = va_arg(ap, size_t); + break; + case 3: + ucp->uc_mregs.rcx = va_arg(ap, size_t); + break; + case 4: + ucp->uc_mregs.r8 = va_arg(ap, size_t); + break; + case 5: + ucp->uc_mregs.r9 = va_arg(ap, size_t); + break; + default: + /* copy value on stack */ + stack[i - 5] = va_arg(ap, size_t); + break; + } + } + va_end(ap); +} + +int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) +{ + //TODO: implementation is missing + + kprintf("WARNING: sys_swapcontext is currently not implemented: %p <=> %p\n", oucp, ucp); + return -ENOSYS; +} diff --git a/hermit/include/hermit/syscall.h b/hermit/include/hermit/syscall.h index 8bb061672..a7da385fb 100644 --- a/hermit/include/hermit/syscall.h +++ b/hermit/include/hermit/syscall.h @@ -93,6 +93,16 @@ void sys_yield(void); int sys_kill(tid_t dest, int signum); int sys_signal(signal_handler_t handler); +typedef struct ucontext { + mregs_t uc_mregs; + union fpu_state uc_fpu; + struct ucontext *uc_link; + stack_t uc_stack; +} ucontext_t; + +void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...); +int swapcontext(ucontext_t *oucp, const ucontext_t *ucp); + #define __NR_exit 0 #define __NR_write 1 #define __NR_open 2 diff --git a/hermit/usr/newlib b/hermit/usr/newlib index d3539f7d5..ba4dae88b 160000 --- a/hermit/usr/newlib +++ b/hermit/usr/newlib @@ -1 +1 @@ -Subproject commit d3539f7d58c1ae43acdd4e67b845103dfcae36c7 +Subproject commit ba4dae88bdc2fda079fc96cf70e7b238282229ca