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;
|
uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096;
|
||||||
fb_physical_base = (uint64_t)fb->address - hhdm_request.response->offset;
|
fb_physical_base = (uint64_t)fb->address - hhdm_request.response->offset;
|
||||||
fb_base = find_free_kernel_region(fb_length);
|
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
|
//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)
|
"calcite/apps/hello/hello.elf") != FAR_SUCCESS)
|
||||||
panic("could not look up hello.elf")
|
panic("could not look up hello.elf")
|
||||||
|
|
||||||
struct process *hello = heap_alloc(sizeof(struct process));
|
if (!start_elf(&root_fs, hello_node))
|
||||||
uint64_t hello_entry;
|
panic("could not start hello.elf")
|
||||||
create_process(hello);
|
|
||||||
if (load_elf(hello, &hello_entry, &root_fs, hello_node) != 1)
|
|
||||||
panic("could not load hello.elf")
|
|
||||||
|
|
||||||
if ((*root_fs.free_node)(&root_fs, hello_node) != FAR_SUCCESS)
|
if ((*root_fs.free_node)(&root_fs, hello_node) != FAR_SUCCESS)
|
||||||
panic("could not free hello.elf node")
|
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();
|
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) {
|
void destroy_process(struct process *process) {
|
||||||
for (int p3i = 0; p3i < 512; ++p3i)
|
for (int p3i = 0; p3i < 512; ++p3i)
|
||||||
if (process->p3_virtual_base[p3i]) {
|
if (process->p3_virtual_base[p3i]) {
|
||||||
|
|
@ -307,6 +343,26 @@ void destroy_process(struct process *process) {
|
||||||
heap_dealloc(process, sizeof(struct 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)
|
#define INITIAL_STACK_SIZE (16 << 20)
|
||||||
|
|
||||||
void create_thread(struct process *process, struct thread *thread_out) {
|
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) {
|
for (int i = 0; i < INITIAL_STACK_SIZE / 4096; ++i) {
|
||||||
|
|
||||||
uint64_t pma = take_free_physical_page();
|
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);
|
void *kvma = find_free_kernel_region(4096);
|
||||||
map_in_kernel_page_table(pma, kvma, 1, 0);
|
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;
|
struct thread *running_thread = 0;
|
||||||
|
|
||||||
[[noreturn]] void syscall_end_thread() {
|
[[noreturn]] void syscall_end_thread() {
|
||||||
|
|
||||||
assert(running_thread != 0)
|
assert(running_thread != 0)
|
||||||
assert(running_thread->process->n_threads >= 1)
|
destroy_thread(running_thread);
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
running_thread = 0;
|
running_thread = 0;
|
||||||
resume_next_continuation();
|
resume_next_continuation();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void syscall_map_framebuffer(struct framebuffer_info *info_out) {
|
void syscall_map_framebuffer(struct framebuffer_info *info_out) {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,14 @@ int load_elf(
|
||||||
struct process *process, uint64_t *entry_out,
|
struct process *process, uint64_t *entry_out,
|
||||||
const struct fs_info *fs_info, void *fs_node);
|
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_process(struct process *process);
|
||||||
|
void destroy_thread(struct thread *thread);
|
||||||
|
|
||||||
//returs 1 if [start, start + length) is writable by process, otherwise 0.
|
//returs 1 if [start, start + length) is writable by process, otherwise 0.
|
||||||
int is_mapped_writable(struct process *process, void *start, uint64_t length);
|
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
|
; Copyright 2025 Benji Dial
|
||||||
;
|
;
|
||||||
; This program is free software: you can redistribute it and/or modify
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -17,30 +17,6 @@
|
||||||
|
|
||||||
bits 64
|
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
|
;referenced in scheduler.c
|
||||||
global resume_continuation
|
global resume_continuation
|
||||||
resume_continuation:
|
resume_continuation:
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,7 @@
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
|
||||||
struct continuation_info {
|
static struct continuation_info *ready_continuations = 0;
|
||||||
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 int rc_buffer_length = 0;
|
static int rc_buffer_length = 0;
|
||||||
static int rc_read_ptr = 0;
|
static int rc_read_ptr = 0;
|
||||||
static int rc_count = 0;
|
static int rc_count = 0;
|
||||||
|
|
@ -38,34 +27,30 @@ static int rc_count = 0;
|
||||||
#define INITIAL_RC_BUFFER_LENGTH 128
|
#define INITIAL_RC_BUFFER_LENGTH 128
|
||||||
|
|
||||||
void init_scheduler() {
|
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;
|
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) {
|
if (rc_count == rc_buffer_length) {
|
||||||
|
|
||||||
struct continuation_info **new_rc_buffer =
|
struct continuation_info *new_rc_buffer =
|
||||||
heap_alloc(2 * rc_buffer_length * sizeof(void *));
|
heap_alloc(2 * rc_buffer_length * sizeof(struct continuation_info));
|
||||||
|
|
||||||
memcpy(
|
memcpy(
|
||||||
new_rc_buffer,
|
new_rc_buffer,
|
||||||
ready_continuations + rc_read_ptr,
|
ready_continuations + rc_read_ptr,
|
||||||
(rc_buffer_length - rc_read_ptr) * sizeof(void *));
|
(rc_buffer_length - rc_read_ptr) * sizeof(struct continuation_info));
|
||||||
|
|
||||||
memcpy(
|
memcpy(
|
||||||
new_rc_buffer + rc_buffer_length - rc_read_ptr,
|
new_rc_buffer + rc_buffer_length - rc_read_ptr,
|
||||||
ready_continuations,
|
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;
|
memcpy(&new_rc_buffer[rc_buffer_length], info, sizeof(struct continuation_info));
|
||||||
for (int i = rc_buffer_length + 1; i < 2 * rc_buffer_length; ++i)
|
|
||||||
new_rc_buffer[i] = 0;
|
|
||||||
|
|
||||||
ready_continuations = new_rc_buffer;
|
ready_continuations = new_rc_buffer;
|
||||||
rc_buffer_length *= 2;
|
rc_buffer_length *= 2;
|
||||||
|
|
@ -75,30 +60,14 @@ static void queue_continuation(struct continuation_info *info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
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;
|
++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
|
//defined in scheduler.asm
|
||||||
[[noreturn]] void resume_continuation(struct continuation_info *info);
|
[[noreturn]] void resume_continuation(struct continuation_info *info);
|
||||||
|
|
||||||
|
|
@ -107,12 +76,12 @@ void create_user_task(
|
||||||
while (rc_count == 0)
|
while (rc_count == 0)
|
||||||
__asm__ ("hlt");
|
__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_read_ptr = (rc_read_ptr + 1) % rc_buffer_length;
|
||||||
--rc_count;
|
--rc_count;
|
||||||
|
|
||||||
resume_continuation(info);
|
resume_continuation(&info);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,20 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#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 init_scheduler();
|
||||||
|
|
||||||
void create_user_task(
|
|
||||||
uint64_t cr3, uint64_t rip, uint64_t rsp);
|
|
||||||
|
|
||||||
[[noreturn]] void resume_next_continuation();
|
[[noreturn]] void resume_next_continuation();
|
||||||
|
|
||||||
|
//ci is copied
|
||||||
|
void add_ready_continuation(struct continuation_info *ci);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue