give each thread a syscall stack instead of the silliness from before
This commit is contained in:
parent
6d9c3f7794
commit
a3575b8997
5 changed files with 63 additions and 131 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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)());
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue