From 32524106e85ab782c49f467e1966c23ea3f9e273 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sat, 27 Dec 2025 22:21:46 -0500 Subject: [PATCH] process/scheduler: make interface a little cleaner, don't leak continuation info --- src/kernel/entry.c | 20 ++-------- src/kernel/process.asm | 56 ++++++++++++++++++++++++++++ src/kernel/process.c | 79 ++++++++++++++++++++++++++++++---------- src/kernel/process.h | 7 ++++ src/kernel/scheduler.asm | 26 +------------ src/kernel/scheduler.c | 61 ++++++++----------------------- src/kernel/scheduler.h | 17 +++++++-- 7 files changed, 156 insertions(+), 110 deletions(-) create mode 100644 src/kernel/process.asm diff --git a/src/kernel/entry.c b/src/kernel/entry.c index d921382..1c551e7 100644 --- a/src/kernel/entry.c +++ b/src/kernel/entry.c @@ -140,7 +140,8 @@ static char cmdline_copy[MAX_CMDLINE_LENGTH + 1]; uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096; fb_physical_base = (uint64_t)fb->address - hhdm_request.response->offset; fb_base = find_free_kernel_region(fb_length); - map_kernel_region(fb_physical_base, fb_base, fb_length, 1, 0); + map_kernel_region( + fb_physical_base, fb_base, fb_length, 1, 0); //store rest of framebuffer information @@ -282,25 +283,12 @@ static const char *cmdline_look_up(const char *key) { "calcite/apps/hello/hello.elf") != FAR_SUCCESS) panic("could not look up hello.elf") - struct process *hello = heap_alloc(sizeof(struct process)); - uint64_t hello_entry; - create_process(hello); - if (load_elf(hello, &hello_entry, &root_fs, hello_node) != 1) - panic("could not load hello.elf") + if (!start_elf(&root_fs, hello_node)) + panic("could not start hello.elf") if ((*root_fs.free_node)(&root_fs, hello_node) != FAR_SUCCESS) panic("could not free hello.elf node") - struct thread *hello_thread = heap_alloc(sizeof(struct thread)); - create_thread(hello, hello_thread); - - create_user_task( - hello->p4_physical_base, - hello_entry, - (uint64_t)hello_thread->stack_top); - - running_thread = hello_thread; - resume_next_continuation(); } diff --git a/src/kernel/process.asm b/src/kernel/process.asm new file mode 100644 index 0000000..48cdc41 --- /dev/null +++ b/src/kernel/process.asm @@ -0,0 +1,56 @@ + ; Calcite, src/kernel/process.asm + ; Copyright 2025 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 + ; the Free Software Foundation, either version 3 of the License, or + ; (at your option) any later version. + ; + ; This program is distributed in the hope that it will be useful, but + ; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + ; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + ; for more details. + ; + ; You should have received a copy of the GNU General Public License along + ; with this program. If not, see . + + +bits 64 + +extern running_thread + +section .text + +;referenced in process.c +global thread_start +thread_start: + + mov rax, qword [running_thread] + test rax, rax + jnz .assert_fail + + mov qword [running_thread], rbx + + mov cr3, rbp + mov rcx, r12 + mov r11, 0x200 + + xor rax, rax + xor rbx, rbx + xor rdx, rdx + xor rdi, rdi + xor rsi, rsi + xor rbp, rbp + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + o64 sysret + +.assert_fail: + ;could be nice to handle this more gracefully in the future + ud2 diff --git a/src/kernel/process.c b/src/kernel/process.c index 25d8178..4f17557 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -284,6 +284,42 @@ int load_elf( } +//defined in process.asm. enters user mode with: +// running_thread = value of rbx when we jump here +// cr3 = value of rbp when we jump here +// rsp = value of rsp when we jump here +// rip = rcx = value of r12 when we jump here +// rflags = r11 = 0x200 (IF) +// all other registers zeroed +extern uint8_t thread_start; + +int start_elf(const struct fs_info *fs_info, void *fs_node) { + + struct process *process = heap_alloc(sizeof(struct process)); + create_process(process); + + uint64_t entry; + + if (!load_elf(process, &entry, fs_info, fs_node)) { + destroy_process(process); + return 0; + } + + struct thread *thread = heap_alloc(sizeof(struct thread)); + create_thread(process, thread); + + struct continuation_info ci; + ci.rip = (uint64_t)&thread_start; + ci.rbx = (uint64_t)thread; + ci.rbp = thread->process->p4_physical_base; + ci.rsp = (uint64_t)thread->stack_top; + ci.r12 = entry; + + add_ready_continuation(&ci); + return 1; + +} + void destroy_process(struct process *process) { for (int p3i = 0; p3i < 512; ++p3i) if (process->p3_virtual_base[p3i]) { @@ -307,6 +343,26 @@ void destroy_process(struct process *process) { heap_dealloc(process, sizeof(struct process)); } +void destroy_thread(struct thread *thread) { + + assert(thread->process->n_threads >= 1) + + if (thread->process->n_threads == 1) + destroy_process(thread->process); + + else { + + --thread->process->n_threads; + + 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) void create_thread(struct process *process, struct thread *thread_out) { @@ -319,7 +375,8 @@ void create_thread(struct process *process, struct thread *thread_out) { for (int i = 0; i < INITIAL_STACK_SIZE / 4096; ++i) { uint64_t pma = take_free_physical_page(); - map_page_for_process(process, pma, stack_bottom_vma + i * 4096, 1, 0); + map_page_for_process( + process, pma, stack_bottom_vma + i * 4096, 1, 0); void *kvma = find_free_kernel_region(4096); map_in_kernel_page_table(pma, kvma, 1, 0); @@ -339,28 +396,10 @@ void create_thread(struct process *process, struct thread *thread_out) { struct thread *running_thread = 0; [[noreturn]] void syscall_end_thread() { - assert(running_thread != 0) - assert(running_thread->process->n_threads >= 1) - - if (running_thread->process->n_threads == 1) - destroy_process(running_thread->process); - - else { - - --running_thread->process->n_threads; - - for (void *p = running_thread->stack_bottom; - p < running_thread->stack_top; p += 4096) - unmap_page_for_process(running_thread->process, p); - - } - - heap_dealloc(running_thread, sizeof(struct thread)); - + destroy_thread(running_thread); running_thread = 0; resume_next_continuation(); - } void syscall_map_framebuffer(struct framebuffer_info *info_out) { diff --git a/src/kernel/process.h b/src/kernel/process.h index 2e93612..4f4fb02 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -70,7 +70,14 @@ int load_elf( struct process *process, uint64_t *entry_out, const struct fs_info *fs_info, void *fs_node); +//returns 0 on failure, 1 on success. +//creates a process and a thread in that process, loads the elf into the process, +//and schedules a ready task that sets the running thread to the new thread and +//starts user mode at the elf's entry point. +int start_elf(const struct fs_info *fs_info, void *fs_node); + void destroy_process(struct process *process); +void destroy_thread(struct thread *thread); //returs 1 if [start, start + length) is writable by process, otherwise 0. int is_mapped_writable(struct process *process, void *start, uint64_t length); diff --git a/src/kernel/scheduler.asm b/src/kernel/scheduler.asm index ec2d14d..5fa150d 100644 --- a/src/kernel/scheduler.asm +++ b/src/kernel/scheduler.asm @@ -1,4 +1,4 @@ - ; Calcite, src/kernel/scheduler.c + ; Calcite, src/kernel/scheduler.asm ; Copyright 2025 Benji Dial ; ; This program is free software: you can redistribute it and/or modify @@ -17,30 +17,6 @@ bits 64 -;referenced in scheduler.c -global user_task_start -user_task_start: - - mov cr3, rbx - mov rcx, rbp - mov r11, 0x200 - - xor rax, rax - xor rbx, rbx - xor rdx, rdx - xor rdi, rdi - xor rsi, rsi - xor rbp, rbp - xor r8, r8 - xor r9, r9 - xor r10, r10 - xor r12, r12 - xor r13, r13 - xor r14, r14 - xor r15, r15 - - o64 sysret - ;referenced in scheduler.c global resume_continuation resume_continuation: diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index f3d4595..dd2ae77 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -19,18 +19,7 @@ #include "utility.h" #include "heap.h" -struct continuation_info { - uint64_t rip; - uint64_t rbx; - uint64_t rbp; - uint64_t rsp; - uint64_t r12; - uint64_t r13; - uint64_t r14; - uint64_t r15; -}; - -static struct continuation_info **ready_continuations = 0; +static struct continuation_info *ready_continuations = 0; static int rc_buffer_length = 0; static int rc_read_ptr = 0; static int rc_count = 0; @@ -38,34 +27,30 @@ static int rc_count = 0; #define INITIAL_RC_BUFFER_LENGTH 128 void init_scheduler() { - ready_continuations = heap_alloc(INITIAL_RC_BUFFER_LENGTH * sizeof(void *)); + ready_continuations = heap_alloc(INITIAL_RC_BUFFER_LENGTH * sizeof(struct continuation_info)); rc_buffer_length = INITIAL_RC_BUFFER_LENGTH; - for (int i = 0; i < INITIAL_RC_BUFFER_LENGTH; ++i) - ready_continuations[i] = 0; } -static void queue_continuation(struct continuation_info *info) { +void add_ready_continuation(struct continuation_info *info) { if (rc_count == rc_buffer_length) { - struct continuation_info **new_rc_buffer = - heap_alloc(2 * rc_buffer_length * sizeof(void *)); + struct continuation_info *new_rc_buffer = + heap_alloc(2 * rc_buffer_length * sizeof(struct continuation_info)); memcpy( new_rc_buffer, ready_continuations + rc_read_ptr, - (rc_buffer_length - rc_read_ptr) * sizeof(void *)); + (rc_buffer_length - rc_read_ptr) * sizeof(struct continuation_info)); memcpy( new_rc_buffer + rc_buffer_length - rc_read_ptr, ready_continuations, - rc_read_ptr * sizeof(void *)); + rc_read_ptr * sizeof(struct continuation_info)); - heap_dealloc(ready_continuations, rc_buffer_length * sizeof(void *)); + heap_dealloc(ready_continuations, rc_buffer_length * sizeof(struct continuation_info)); - new_rc_buffer[rc_buffer_length] = info; - for (int i = rc_buffer_length + 1; i < 2 * rc_buffer_length; ++i) - new_rc_buffer[i] = 0; + memcpy(&new_rc_buffer[rc_buffer_length], info, sizeof(struct continuation_info)); ready_continuations = new_rc_buffer; rc_buffer_length *= 2; @@ -75,30 +60,14 @@ static void queue_continuation(struct continuation_info *info) { } else { - ready_continuations[(rc_read_ptr + rc_count) % rc_buffer_length] = info; + memcpy( + &ready_continuations[(rc_read_ptr + rc_count) % rc_buffer_length], + info, sizeof(struct continuation_info)); ++rc_count; } } -//defined in scheduler.asm -void user_task_start(); - -void create_user_task( - uint64_t cr3, uint64_t rip, uint64_t rsp) { - - struct continuation_info *info = - heap_alloc(sizeof(struct continuation_info)); - - info->rip = (uint64_t)&user_task_start; - info->rsp = (uint64_t)rsp; - info->rbx = cr3; - info->rbp = rip; - - queue_continuation(info); - -} - //defined in scheduler.asm [[noreturn]] void resume_continuation(struct continuation_info *info); @@ -107,12 +76,12 @@ void create_user_task( while (rc_count == 0) __asm__ ("hlt"); - struct continuation_info *info = ready_continuations[rc_read_ptr]; + struct continuation_info info; + memcpy(&info, &ready_continuations[rc_read_ptr], sizeof(struct continuation_info)); - ready_continuations[rc_read_ptr] = 0; rc_read_ptr = (rc_read_ptr + 1) % rc_buffer_length; --rc_count; - resume_continuation(info); + resume_continuation(&info); } diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index cf503f3..ccdf439 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -19,9 +19,20 @@ #include +struct continuation_info { + uint64_t rip; + uint64_t rbx; + uint64_t rbp; + uint64_t rsp; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; +}; + void init_scheduler(); -void create_user_task( - uint64_t cr3, uint64_t rip, uint64_t rsp); - [[noreturn]] void resume_next_continuation(); + +//ci is copied +void add_ready_continuation(struct continuation_info *ci);