give each thread a syscall stack instead of the silliness from before

This commit is contained in:
Benji Dial 2025-12-31 20:02:59 -05:00
parent 6d9c3f7794
commit a3575b8997
5 changed files with 63 additions and 131 deletions

View file

@ -18,6 +18,11 @@
bits 64 bits 64
default rel default rel
section .bss
resb 16384
temporary_stack:
section .text section .text
;referenced in process.c ;referenced in process.c
@ -42,3 +47,9 @@ thread_start:
xor r15, r15 xor r15, r15
o64 sysret o64 sysret
;referenced in process.c
global with_temporary_stack
with_temporary_stack:
mov rsp, temporary_stack
jmp rdi

View file

@ -18,7 +18,6 @@
#include "framebuffer.h" #include "framebuffer.h"
#include "ipc-dgram.h" #include "ipc-dgram.h"
#include "scheduler.h" #include "scheduler.h"
#include "syscalls.h"
#include "process.h" #include "process.h"
#include "utility.h" #include "utility.h"
#include "paging.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) { void destroy_process(struct process *process) {
assert(process->n_threads == 0)
if (process->files) { if (process->files) {
for (int i = 0; i < process->files_buffer_size; ++i) for (int i = 0; i < process->files_buffer_size; ++i)
if (process->files[i].fs != 0) if (process->files[i].fs != 0)
@ -499,23 +500,23 @@ void destroy_thread(struct thread *thread) {
assert(thread->process->n_threads >= 1) 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); destroy_process(thread->process);
else
else {
--thread->process->n_threads;
for (void *p = thread->stack_bottom; p < thread->stack_top; p += 4096) for (void *p = thread->stack_bottom; p < thread->stack_top; p += 4096)
unmap_page_for_process(thread->process, p); unmap_page_for_process(thread->process, p);
}
heap_dealloc(thread, sizeof(struct thread)); heap_dealloc(thread, sizeof(struct thread));
} }
#define INITIAL_STACK_SIZE (16 << 20) #define INITIAL_STACK_SIZE (16 << 20)
#define INITIAL_SYSCALL_STACK_SIZE 16384
void create_thread(struct process *process, struct thread *thread_out) { 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->process = process;
thread_out->stack_bottom = stack_bottom_vma; thread_out->stack_bottom = stack_bottom_vma;
thread_out->stack_top = stack_bottom_vma + INITIAL_STACK_SIZE; 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; ++process->n_threads;
@ -553,15 +564,23 @@ void create_thread(struct process *process, struct thread *thread_out) {
struct thread *running_thread = 0; 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() { [[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(); resume_next_continuation();
} }
[[noreturn]] void syscall_end_thread() { [[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); with_temporary_stack(&syscall_end_thread_with_temporary_stack);
} }

View file

@ -83,6 +83,7 @@ struct process {
//return value might be invalidated by future allocation of file handles for this 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); struct process_file_info *get_file_info(struct process *process, file_handle_t handle);
//layout used in syscalls.asm
struct thread { struct thread {
struct process *process; struct process *process;
@ -91,6 +92,10 @@ struct thread {
void *stack_bottom; void *stack_bottom;
void *stack_top; void *stack_top;
//both page-aligned
void *syscall_stack_bottom;
void *syscall_stack_top;
}; };
extern struct thread *running_thread; extern struct thread *running_thread;
@ -105,6 +110,7 @@ void map_page_for_process(
void *virtual_base, int writable, int executable, int owned); void *virtual_base, int writable, int executable, int owned);
//virtual base must be page-aligned, in bottom p3, and not zero. //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( void unmap_page_for_process(
struct process *process, void *virtual_base); 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); int syscall_start_elf(const char *path, const struct process_start_info *info);
void destroy_process(struct process *process); void destroy_process(struct process *process);
//must not be called with syscall stack of the thread being destroyed
void destroy_thread(struct thread *thread); void destroy_thread(struct thread *thread);
[[noreturn]] void syscall_illegal_args(); [[noreturn]] void syscall_illegal_args();

View file

@ -18,133 +18,42 @@
bits 64 bits 64
default rel default rel
extern destroy_syscall_stack ;defined in syscalls.c
extern create_syscall_stack
extern syscall_entry_c extern syscall_entry_c
section .bss extern running_thread
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
section .text section .text
;system call number is in rax. ;system call number is in rax.
;system call arguments are in rdi, rsi, rdx. ;system call arguments are in rdi, rsi, rdx.
;system call returns a value in rax. ;system call returns a value in rax.
;depends on layout of struct thread from process.h
syscall_entry: syscall_entry:
mov r8, qword [running_thread]
test r8, r8
jz .assert_fail
xor r8, r8 mov r8, qword [r8 + 32]
.find_stack_loop: mov qword [r8 - 8], rsp
mov rsp, r8
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
sub rsp, 8 sub rsp, 8
push r11
push rcx push rcx
push r11
mov rcx, rax mov rcx, rax
call syscall_entry_c 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 r11
pop rcx 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 pop rsp
o64 sysret o64 sysret
.assert_fail:
ud2
global init_syscalls global init_syscalls
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 mov ecx, 0xc0000080
rdmsr rdmsr
or al, 0x01 or al, 0x01
@ -167,8 +76,3 @@ init_syscalls:
wrmsr wrmsr
ret ret
global with_temporary_stack
with_temporary_stack:
mov rsp, temp_syscall_stack
jmp rdi

View file

@ -25,12 +25,3 @@ void init_syscalls();
void register_syscall( void register_syscall(
int number, int number,
uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3)); 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)());