process/scheduler: make interface a little cleaner, don't leak continuation info
This commit is contained in:
parent
bb10b27152
commit
32524106e8
7 changed files with 156 additions and 110 deletions
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
|||
56
src/kernel/process.asm
Normal file
56
src/kernel/process.asm
Normal file
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,20 @@
|
|||
|
||||
#include <stdint.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;
|
||||
};
|
||||
|
||||
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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue