diff --git a/src/kernel/process.asm b/src/kernel/process.asm index 4732fd1..d3c6bcf 100644 --- a/src/kernel/process.asm +++ b/src/kernel/process.asm @@ -18,6 +18,11 @@ bits 64 default rel +section .bss + + resb 16384 +temporary_stack: + section .text ;referenced in process.c @@ -42,3 +47,9 @@ thread_start: xor r15, r15 o64 sysret + +;referenced in process.c +global with_temporary_stack +with_temporary_stack: + mov rsp, temporary_stack + jmp rdi diff --git a/src/kernel/process.c b/src/kernel/process.c index be704a0..6867c4b 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -18,7 +18,6 @@ #include "framebuffer.h" #include "ipc-dgram.h" #include "scheduler.h" -#include "syscalls.h" #include "process.h" #include "utility.h" #include "paging.h" @@ -446,6 +445,8 @@ int syscall_start_elf(const char *path, const struct process_start_info *info) { void destroy_process(struct process *process) { + assert(process->n_threads == 0) + if (process->files) { for (int i = 0; i < process->files_buffer_size; ++i) if (process->files[i].fs != 0) @@ -499,23 +500,23 @@ void destroy_thread(struct thread *thread) { assert(thread->process->n_threads >= 1) - if (thread->process->n_threads == 1) + --thread->process->n_threads; + + for (void *p = thread->syscall_stack_bottom; p < thread->syscall_stack_top; p += 4096) + unmap_and_free_kernel_page(p); + + if (thread->process->n_threads == 0) destroy_process(thread->process); - - else { - - --thread->process->n_threads; - + else for (void *p = thread->stack_bottom; p < thread->stack_top; p += 4096) unmap_page_for_process(thread->process, p); - } - heap_dealloc(thread, sizeof(struct thread)); } #define INITIAL_STACK_SIZE (16 << 20) +#define INITIAL_SYSCALL_STACK_SIZE 16384 void create_thread(struct process *process, struct thread *thread_out) { @@ -539,9 +540,19 @@ void create_thread(struct process *process, struct thread *thread_out) { } + void *syscall_stack_bottom = find_free_kernel_region(INITIAL_SYSCALL_STACK_SIZE); + + for (int i = 0; i < INITIAL_SYSCALL_STACK_SIZE / 4096; ++i) { + uint64_t pma = take_free_physical_page(); + map_in_kernel_page_table( + pma, syscall_stack_bottom + i * 4096, 1, 0); + } + thread_out->process = process; thread_out->stack_bottom = stack_bottom_vma; thread_out->stack_top = stack_bottom_vma + INITIAL_STACK_SIZE; + thread_out->syscall_stack_bottom = syscall_stack_bottom; + thread_out->syscall_stack_top = syscall_stack_bottom + INITIAL_SYSCALL_STACK_SIZE; ++process->n_threads; @@ -553,15 +564,23 @@ void create_thread(struct process *process, struct thread *thread_out) { struct thread *running_thread = 0; +//defined in process.asm. +//function should not return. +[[noreturn]] void with_temporary_stack(void (*function)()); + [[noreturn]] static void syscall_end_thread_with_temporary_stack() { - destroy_syscall_stack(most_recent_syscall_stack); + + assert(running_thread != 0) + + struct thread *the_thread = running_thread; + running_thread = 0; + + destroy_thread(the_thread); resume_next_continuation(); + } [[noreturn]] void syscall_end_thread() { - assert(running_thread != 0) - destroy_thread(running_thread); - running_thread = 0; with_temporary_stack(&syscall_end_thread_with_temporary_stack); } diff --git a/src/kernel/process.h b/src/kernel/process.h index 1650a0d..727390e 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -83,6 +83,7 @@ struct process { //return value might be invalidated by future allocation of file handles for this process. struct process_file_info *get_file_info(struct process *process, file_handle_t handle); +//layout used in syscalls.asm struct thread { struct process *process; @@ -91,6 +92,10 @@ struct thread { void *stack_bottom; void *stack_top; + //both page-aligned + void *syscall_stack_bottom; + void *syscall_stack_top; + }; extern struct thread *running_thread; @@ -105,6 +110,7 @@ void map_page_for_process( void *virtual_base, int writable, int executable, int owned); //virtual base must be page-aligned, in bottom p3, and not zero. +//also frees physical page if owned by process. void unmap_page_for_process( struct process *process, void *virtual_base); @@ -127,6 +133,7 @@ struct process *start_elf(const char *uri); int syscall_start_elf(const char *path, const struct process_start_info *info); void destroy_process(struct process *process); +//must not be called with syscall stack of the thread being destroyed void destroy_thread(struct thread *thread); [[noreturn]] void syscall_illegal_args(); diff --git a/src/kernel/syscalls.asm b/src/kernel/syscalls.asm index 0069e36..27b59b7 100644 --- a/src/kernel/syscalls.asm +++ b/src/kernel/syscalls.asm @@ -18,133 +18,42 @@ bits 64 default rel -extern destroy_syscall_stack -extern create_syscall_stack +;defined in syscalls.c extern syscall_entry_c -section .bss - - resb 1 << 15 -temp_syscall_stack: - -available_syscall_stack_count equ 128 -available_syscall_stacks: - resq available_syscall_stack_count - -global most_recent_syscall_stack -most_recent_syscall_stack: - resq 1 +extern running_thread section .text ;system call number is in rax. ;system call arguments are in rdi, rsi, rdx. ;system call returns a value in rax. +;depends on layout of struct thread from process.h syscall_entry: + mov r8, qword [running_thread] + test r8, r8 + jz .assert_fail - xor r8, r8 -.find_stack_loop: - - mov r9, qword [available_syscall_stacks + r8 * 8] - test r9, r9 - jnz .got_syscall_stack - - inc r8 - cmp r8, available_syscall_stack_count - jne .find_stack_loop - - mov qword [temp_syscall_stack - 8], rsp - mov rsp, temp_syscall_stack - 8 - push r11 - push rcx - push rax - push rdi - push rsi - push rdx - - call create_syscall_stack - mov r9, rax - - pop rdx - pop rsi - pop rdi - pop rax - pop rcx - pop r11 - pop rsp - - jmp .common - -.got_syscall_stack: - mov qword [available_syscall_stacks + r8 * 8], 0 - -.common: - mov qword [r9 - 8], rsp - mov rsp, r9 - mov qword [most_recent_syscall_stack], rsp + mov r8, qword [r8 + 32] + mov qword [r8 - 8], rsp + mov rsp, r8 sub rsp, 8 - push r11 push rcx + push r11 mov rcx, rax call syscall_entry_c - pop rcx - pop r11 - - xor r8, r8 -.find_place_to_put_stack: - - mov r9, qword [available_syscall_stacks + r8 * 8] - test r9, r9 - jz .got_place - - inc r8 - cmp r8, available_syscall_stack_count - jne .find_stack_loop - - mov rdi, rsp - add rdi, 8 - - pop rsp - - mov qword [temp_syscall_stack - 8], rsp - mov rsp, temp_syscall_stack - 8 - push rax - push rcx - push r11 - - call destroy_syscall_stack - pop r11 pop rcx - pop rax - jmp .common_2 - -.got_place: - mov r9, rsp - add r9, 8 - mov qword [available_syscall_stacks + r8 * 8], r9 - -.common_2: pop rsp o64 sysret +.assert_fail: + ud2 + global init_syscalls init_syscalls: - sub rsp, 8 - mov qword [rsp], 0 - -.create_stack_loop: - call create_syscall_stack - mov rdi, qword [rsp] - mov qword [available_syscall_stacks + rdi * 8], rax - inc qword [rsp] - cmp rdi, available_syscall_stack_count - 1 - jne .create_stack_loop - - add rsp, 8 - mov ecx, 0xc0000080 rdmsr or al, 0x01 @@ -167,8 +76,3 @@ init_syscalls: wrmsr ret - -global with_temporary_stack -with_temporary_stack: - mov rsp, temp_syscall_stack - jmp rdi diff --git a/src/kernel/syscalls.h b/src/kernel/syscalls.h index 5c6f84a..3171a7a 100644 --- a/src/kernel/syscalls.h +++ b/src/kernel/syscalls.h @@ -25,12 +25,3 @@ void init_syscalls(); void register_syscall( int number, uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3)); - -//the top of the syscall stack of the most recently started syscall. -//kind of a hack, used in the end_thread syscall to deallocate that stack -//and in the fork_thread syscall to copy the stack. -extern void *most_recent_syscall_stack; - -//also kind of a hack. switches to temporary stack and runs f with that stack. -//f should not return. this does not touch most_recent_syscall_stack. -[[noreturn]] void with_temporary_stack(void (*f)());