add guard pages to stack; dynamically allocate user stacks; zero non-preserved registers before returning from syscalls
This commit is contained in:
parent
5821f51f02
commit
085ae6ba53
7 changed files with 113 additions and 31 deletions
|
|
@ -76,7 +76,23 @@ isr_exception_common:
|
|||
mov rax, cr3
|
||||
push rax
|
||||
mov rdi, rsp
|
||||
jmp isr_exception_c
|
||||
|
||||
call isr_exception_c
|
||||
|
||||
add rsp, 48
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
add rsp, 8
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rdx
|
||||
pop rcx
|
||||
add rsp, 8
|
||||
pop rax
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
isr_irq_common:
|
||||
push rax
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
// https://osdev.wiki/wiki/Task_State_Segment
|
||||
|
||||
#include "interrupts.h"
|
||||
#include "process.h"
|
||||
#include "paging.h"
|
||||
#include "debug.h"
|
||||
|
||||
//interrupts.asm depends on layout
|
||||
|
|
@ -63,7 +65,7 @@ const char *exception_names[32] = {
|
|||
"hypervisor injection exception", "vmm communication exception", "security exception", 0
|
||||
};
|
||||
|
||||
[[noreturn]] static void unhandled_exception(struct exception_parameter *parameter) {
|
||||
[[noreturn]] static void unhandled_exception(const struct exception_parameter *parameter) {
|
||||
|
||||
assert(parameter->exception_number < 32 && exception_names[parameter->exception_number] != 0)
|
||||
|
||||
|
|
@ -101,11 +103,25 @@ const char *exception_names[32] = {
|
|||
}
|
||||
|
||||
//referenced in interrupts.asm
|
||||
void isr_exception_c(struct exception_parameter *parameter) {
|
||||
void isr_exception_c(const struct exception_parameter *parameter) {
|
||||
|
||||
//eventually some exceptions will be handled in here
|
||||
if (running_thread != 0 &&
|
||||
parameter->exception_number == 0x0e &&
|
||||
(parameter->error_code & 0x1) == 0x0 &&
|
||||
parameter->cr2 >= (uint64_t)running_thread->stack_bottom + 4096 &&
|
||||
parameter->cr2 < (uint64_t)running_thread->stack_top) {
|
||||
|
||||
unhandled_exception(parameter);
|
||||
void *vma = (void *)(parameter->cr2 & 0xfffffffffffff000);
|
||||
unmap_page_for_process(running_thread->process, vma);
|
||||
uint64_t pma = take_free_physical_page();
|
||||
map_page_for_process(
|
||||
running_thread->process, pma,
|
||||
vma, 1, 0, 1);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
unhandled_exception(parameter);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* Calcite, src/kernel/paging.c
|
||||
* Copyright 2025 Benji Dial
|
||||
* Copyright 2025-2026 Benji Dial
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -104,9 +104,7 @@ void mark_physical_memory_free(uint64_t base, uint64_t length) {
|
|||
//defined in paging.asm
|
||||
void invlpg(void *address);
|
||||
|
||||
void map_in_kernel_page_table(
|
||||
uint64_t physical_base, void *virtual_base,
|
||||
int writable, int executable) {
|
||||
void map_in_kernel_page_table(uint64_t physical_base, void *virtual_base, int writable, int executable) {
|
||||
|
||||
uint64_t virtual_base_u64 = (uint64_t)virtual_base;
|
||||
assert(virtual_base_u64 >= 0xffffffffc0000000);
|
||||
|
|
@ -122,6 +120,18 @@ void map_in_kernel_page_table(
|
|||
|
||||
}
|
||||
|
||||
void create_kernel_guard_page(void *virtual_base) {
|
||||
|
||||
uint64_t virtual_base_u64 = (uint64_t)virtual_base;
|
||||
assert(virtual_base_u64 >= 0xffffffffc0000000);
|
||||
|
||||
uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12;
|
||||
assert(kernel_p1s[p1s_index] == 0);
|
||||
|
||||
kernel_p1s[p1s_index] = 0x2;
|
||||
|
||||
}
|
||||
|
||||
void unmap_kernel_page(void *virtual_base) {
|
||||
|
||||
uint64_t virtual_base_u64 = (uint64_t)virtual_base;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* Calcite, src/kernel/paging.h
|
||||
* Copyright 2025 Benji Dial
|
||||
* Copyright 2025-2026 Benji Dial
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -33,6 +33,9 @@ void mark_physical_memory_free(uint64_t base, uint64_t length);
|
|||
void map_in_kernel_page_table(
|
||||
uint64_t physical_base, void *virtual_base, int writable, int executable);
|
||||
|
||||
//virtual base should be page-aligned and within kernel range.
|
||||
void create_kernel_guard_page(void *virtual_base);
|
||||
|
||||
//unmaps one page. base should be page-aligned and within kernel range.
|
||||
void unmap_kernel_page(void *virtual_base);
|
||||
|
||||
|
|
|
|||
|
|
@ -69,11 +69,8 @@ void create_process(struct process *process_out) {
|
|||
|
||||
}
|
||||
|
||||
void map_page_for_process(
|
||||
struct process *process, uint64_t physical_base,
|
||||
void *virtual_base, int writable, int executable, int owned) {
|
||||
|
||||
assert(physical_base % 4096 == 0)
|
||||
static void get_page_table_entry(
|
||||
struct process *process, void *virtual_base, int *p1i_out, int *p2i_out, int *p3i_out) {
|
||||
|
||||
uint64_t vma = (uint64_t)virtual_base;
|
||||
assert(vma % 4096 == 0)
|
||||
|
|
@ -112,6 +109,21 @@ void map_page_for_process(
|
|||
process->owned_pages_bitmaps[p3i][p2i][i] = 0;
|
||||
}
|
||||
|
||||
*p1i_out = p1i;
|
||||
*p2i_out = p2i;
|
||||
*p3i_out = p3i;
|
||||
|
||||
}
|
||||
|
||||
void map_page_for_process(
|
||||
struct process *process, uint64_t physical_base,
|
||||
void *virtual_base, int writable, int executable, int owned) {
|
||||
|
||||
assert(physical_base % 4096 == 0)
|
||||
|
||||
int p1i, p2i, p3i;
|
||||
get_page_table_entry(process, virtual_base, &p1i, &p2i, &p3i);
|
||||
|
||||
assert(process->p1_virtual_bases[p3i][p2i][p1i] == 0)
|
||||
|
||||
process->p1_virtual_bases[p3i][p2i][p1i] =
|
||||
|
|
@ -123,6 +135,17 @@ void map_page_for_process(
|
|||
|
||||
}
|
||||
|
||||
void create_guard_page_for_process(struct process *process, void *virtual_base) {
|
||||
|
||||
int p1i, p2i, p3i;
|
||||
get_page_table_entry(process, virtual_base, &p1i, &p2i, &p3i);
|
||||
|
||||
assert(process->p1_virtual_bases[p3i][p2i][p1i] == 0)
|
||||
|
||||
process->p1_virtual_bases[p3i][p2i][p1i] = 0x6;
|
||||
|
||||
}
|
||||
|
||||
void unmap_page_for_process(
|
||||
struct process *process, void *virtual_base) {
|
||||
|
||||
|
|
@ -532,7 +555,8 @@ void destroy_thread(struct thread *thread) {
|
|||
|
||||
--thread->process->n_threads;
|
||||
|
||||
for (void *p = thread->syscall_stack_bottom; p < thread->syscall_stack_top; p += 4096)
|
||||
unmap_kernel_page(thread->syscall_stack_bottom);
|
||||
for (void *p = thread->syscall_stack_bottom + 4096; p < thread->syscall_stack_top; p += 4096)
|
||||
unmap_and_free_kernel_page(p);
|
||||
|
||||
if (thread->process->n_threads == 0)
|
||||
|
|
@ -545,22 +569,25 @@ void destroy_thread(struct thread *thread) {
|
|||
|
||||
}
|
||||
|
||||
#define INITIAL_STACK_SIZE (16 << 20)
|
||||
#define INITIAL_SYSCALL_STACK_SIZE 16384
|
||||
#define MAX_STACK_SIZE ((16 << 20) - 4096)
|
||||
#define INITIAL_STACK_SIZE 16384
|
||||
|
||||
#define SYSCALL_STACK_SIZE 12288
|
||||
|
||||
void create_thread(struct process *process, struct thread *thread_out) {
|
||||
|
||||
//TODO: allocate stack as needed on page faults, have guard pages, etc.
|
||||
|
||||
void *stack_bottom_vma =
|
||||
find_free_process_region(process, INITIAL_STACK_SIZE / 4096);
|
||||
find_free_process_region(process, MAX_STACK_SIZE + 4096);
|
||||
|
||||
for (int i = 0; i < INITIAL_STACK_SIZE / 4096; ++i) {
|
||||
for (int i = 0; i < MAX_STACK_SIZE - INITIAL_STACK_SIZE + 4096; i += 4096)
|
||||
create_guard_page_for_process(process, stack_bottom_vma + i);
|
||||
|
||||
for (int i = MAX_STACK_SIZE - INITIAL_STACK_SIZE + 4096; i < MAX_STACK_SIZE + 4096; i += 4096) {
|
||||
|
||||
uint64_t pma = take_free_physical_page();
|
||||
map_page_for_process(
|
||||
process, pma,
|
||||
stack_bottom_vma + i * 4096,
|
||||
stack_bottom_vma + i,
|
||||
1, 0, 1);
|
||||
|
||||
void *kvma = find_free_kernel_region(4096);
|
||||
|
|
@ -570,19 +597,21 @@ void create_thread(struct process *process, struct thread *thread_out) {
|
|||
|
||||
}
|
||||
|
||||
void *syscall_stack_bottom = find_free_kernel_region(INITIAL_SYSCALL_STACK_SIZE);
|
||||
void *syscall_stack_bottom = find_free_kernel_region(SYSCALL_STACK_SIZE + 4096);
|
||||
|
||||
for (int i = 0; i < INITIAL_SYSCALL_STACK_SIZE / 4096; ++i) {
|
||||
create_kernel_guard_page(syscall_stack_bottom);
|
||||
|
||||
for (int i = 4096; i < 4096 + SYSCALL_STACK_SIZE; i += 4096) {
|
||||
uint64_t pma = take_free_physical_page();
|
||||
map_in_kernel_page_table(
|
||||
pma, syscall_stack_bottom + i * 4096, 1, 0);
|
||||
pma, syscall_stack_bottom + i, 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->stack_top = stack_bottom_vma + 4096 + MAX_STACK_SIZE;
|
||||
thread_out->syscall_stack_bottom = syscall_stack_bottom;
|
||||
thread_out->syscall_stack_top = syscall_stack_bottom + INITIAL_SYSCALL_STACK_SIZE;
|
||||
thread_out->syscall_stack_top = syscall_stack_bottom + 4096 + SYSCALL_STACK_SIZE;
|
||||
|
||||
++process->n_threads;
|
||||
|
||||
|
|
@ -640,8 +669,6 @@ void syscall_map_framebuffer(struct framebuffer_info *info_out) {
|
|||
|
||||
}
|
||||
|
||||
#define INITIAL_FILE_HANDLE_COUNT 128
|
||||
|
||||
enum fs_access_result syscall_open_file(const char *path, file_handle_t *handle_out) {
|
||||
|
||||
assert(running_thread != 0)
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ void map_page_for_process(
|
|||
struct process *process, uint64_t physical_base,
|
||||
void *virtual_base, int writable, int executable, int owned);
|
||||
|
||||
//physical and virtual bases must be page-aligned.
|
||||
void create_guard_page_for_process(struct process *process, void *virtual_base);
|
||||
|
||||
//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(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
; Calcite, src/kernel/syscalls.asm
|
||||
; Copyright 2025 Benji Dial
|
||||
; Copyright 2025-2026 Benji Dial
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -44,6 +44,13 @@ syscall_entry:
|
|||
mov rcx, rax
|
||||
call syscall_entry_c
|
||||
|
||||
xor rdi, rdi
|
||||
xor rsi, rsi
|
||||
xor rdx, rdx
|
||||
xor r8, r8
|
||||
xor r9, r9
|
||||
xor r10, r10
|
||||
|
||||
pop r11
|
||||
pop rcx
|
||||
pop rsp
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue