Work on scheduler

This commit is contained in:
bdbrd 2025-11-08 17:05:49 +01:00
parent cbc51f523e
commit 14bced8243
8 changed files with 98 additions and 79 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
build/
iso_root/
limine/
test/

View file

@ -12,7 +12,7 @@ in the `build` folder you should have a `SFB25.iso` file.
To try out SFB/25 you can use QEMU: To try out SFB/25 you can use QEMU:
`qemu-system-x86_64 build/SFB25.iso -m 512M` `qemu-system-x86_64 build/SFB25.iso -machine q35 -m 512M`
## External projects ## External projects

17
autodebug.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
# how it works:
# Args are fed to QEMU, then GDB and everything else does shit automagically
# 1st arg: terminal name to spawn GDB
# 2nd arg: place to breakpoint in
termname=$1
breakpoint=$2
shift 2
qemu-system-x86_64 "$@" &
wait 1
"$termname" -e gdb -ex 'target remote localhost:1234' -ex 'break _start' -ex 'continue' build/SFB25.elf

View file

@ -1,8 +1,8 @@
# Timeout in seconds that Limine will use before automatically booting. # Timeout in seconds that Limine will use before automatically booting.
timeout: 5 timeout: 0
# The entry name that will be displayed in the boot menu. # The entry name that will be displayed in the boot menu.
/SFB25 (KASLR on) /SFB/25 (KASLR on)
# We use the Limine boot protocol. # We use the Limine boot protocol.
protocol: limine protocol: limine
@ -10,7 +10,7 @@ timeout: 5
kernel_path: boot():/SFB25.elf kernel_path: boot():/SFB25.elf
# Same thing, but without KASLR. # Same thing, but without KASLR.
/SFB25 (KASLR off) /SFB/25 (KASLR off)
# We use the Limine boot protocol. # We use the Limine boot protocol.
protocol: limine protocol: limine

1
src/flanterm Submodule

@ -0,0 +1 @@
Subproject commit 55d228ff16234513b0df0dd12de8bc58160fc196

View file

@ -1,47 +1,53 @@
default rel
global switch_context global switch_context
global get_context
%macro save_context 0 ; switch_context(struct context *old, struct context *new)
push rbx ; ^RDI ^RSI
push rsp
push rbp
push r12
push r13
push r14
push r15
%endmacro
%macro load_context 0
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rsp
pop rbx
%endmacro
; Switch context from old to new
; void switch_context(context *old, context* new);
; rdi rsi
switch_context: switch_context:
save_context pop r8 ; Fetch RIP from stack
mov rdi, rsp
mov rsp, rsi
load_context
retfq
; Save callee-saved registers to the old struct
mov [rdi + 0x00], rbx
mov [rdi + 0x08], rsp
mov [rdi + 0x10], rbp
mov [rdi + 0x18], r12
mov [rdi + 0x20], r13
mov [rdi + 0x28], r14
mov [rdi + 0x30], r15
mov [rdi + 0x38], r8
; Load the new context
mov rbx, [rsi + 0x00]
mov rsp, [rsi + 0x08]
mov rbp, [rsi + 0x10]
mov r12, [rsi + 0x18]
mov r13, [rsi + 0x20]
mov r14, [rsi + 0x28]
mov r15, [rsi + 0x30]
push r8
jmp [rsi + 0x38]
ret
; get_context(struct context *ctx)
get_context:
pop r8 ; Fetch RIP from stack
; Save callee-saved registers to the old struct
mov [rdi + 0x00], rbx
mov [rdi + 0x08], rsp
mov [rdi + 0x10], rbp
mov [rdi + 0x18], r12
mov [rdi + 0x20], r13
mov [rdi + 0x28], r14
mov [rdi + 0x30], r15
mov [rdi + 0x38], r8
push r8
ret

View file

@ -16,7 +16,6 @@ int next_pid = 1;
void idle_task(){ void idle_task(){
kprintf("Hello world from bruhd task!\n"); kprintf("Hello world from bruhd task!\n");
for(;;);
} }
void test_task(){ void test_task(){
@ -26,45 +25,33 @@ void test_task(){
/* Setup a process structure */ /* Setup a process structure */
proc *alloc_process(void){ proc *alloc_process(void){
asm("cli"); proc *proc_list = get_cpu_struct()->process_list;
cpu_state *state = get_cpu_struct();
kprintf("hi10\n");
proc *proc_list = state->process_list;
uint8_t *sp;
for(uint64_t i = 0; i < PROC_MAX; i++){ for(uint64_t i = 0; i < PROC_MAX; i++){
if(proc_list[i].state == UNUSED){ if(proc_list[i].state == UNUSED){
/* Set the process ready to be executed */ proc *p = &proc_list[i];
kprintf("hi6\n");
proc_list[i].state = READY;
proc_list[i].kstack = kmalloc(INITIAL_STACK_SIZE);
if(proc_list[i].kstack == NULL){ p->state = READY;
klog(LOG_ERROR, __func__, "Failed to alloc stack"); kprintf("pstate = 0x{x}\n", READY);
} kprintf("actual: 0x{x}\n", p->state);
kprintf("hi7\n"); p->kstack = kmalloc(INITIAL_STACK_SIZE);
proc_list[i].pid = next_pid++; p->pid = next_pid++;
sp = (uint8_t*)((uint64_t)proc_list[i].kstack + INITIAL_STACK_SIZE); memset(&p->context, 0, sizeof(context));
proc_list[i].context.rip = 0; p->context.rbp = (uint64_t)p->kstack;
proc_list[i].context.rsp = (uint64_t)sp; p->context.rsp = (uint64_t)p->context.rbp + INITIAL_STACK_SIZE;
kprintf("actua2l: 0x{x}\n", p->state);
kprintf("hi8\n"); return p;
asm("sti");
return &proc_list[i];
} }
} }
asm("sti");
return NULL; kprintf("Couldn't find free process!");
} }
kstatus add_task(uint64_t *entry){ kstatus add_task(uint64_t *entry){
proc *proc = alloc_process(); proc *proc = alloc_process();
@ -79,28 +66,31 @@ kstatus add_task(uint64_t *entry){
} }
void scheduler_init(){ void scheduler_init(){
if(!get_cpu_struct_initialized()){
kprintf("sched: cpu struct not initialized!");
kkill();
}
cpu_state *state = get_cpu_struct(); cpu_state *state = get_cpu_struct();
if(state->current_process != NULL){ if(state->current_process != NULL){
kprintf("sched: scheduler on CPU {d} already initialized!\n", state->lapic_id); kprintf("sched: scheduler on CPU {d} already initialized!\n", state->lapic_id);
kkill(); kkill();
} }
kprintf("hi1\n"); kprintf("hi1\n");
proc *proc_list = state->process_list; proc *proc_list = state->process_list;
/* Put the idle task */ memset(proc_list, 0, sizeof(proc) * 512);
proc idle = {0, 0, 0, READY, {0, 0, 0, 0, 0, 0, 0, 0, 0}};
/* Make the idle structure the firstr process */ int pid = add_task((uint64_t*)idle_task);
proc_list[0] = idle;
kprintf("hi2\n");
add_task((uint64_t*)test_task); add_task((uint64_t*)test_task);
kprintf("hi5\n");
for(;;){ for(;;){
for(int i = 0; i < PROC_MAX; i++){ for(int i = 0; i < PROC_MAX; i++){
if(proc_list[i].state == READY){ if(proc_list[i].state == READY){
kprintf("Hell yeah");
context old_state = state->current_process->context; context old_state = state->current_process->context;
@ -118,6 +108,7 @@ void scheduler_tick(){
cpu_state *state = get_cpu_struct(); cpu_state *state = get_cpu_struct();
proc *proc_list = state->process_list; proc *proc_list = state->process_list;
switch_context(&state->current_process->context, &state->scheduler_context);
} }

View file

@ -3,15 +3,15 @@
#pragma once #pragma once
typedef enum proc_state { typedef enum proc_state {
RUNNING, RUNNING = 3,
READY, READY = 2,
SLEEPING, SLEEPING = 1,
UNUSED = 0 UNUSED = 0
}proc_state; }proc_state;
typedef struct context { typedef struct context {
uint64_t rbx, rsp, rbp, r12, r13, r14, r15; uint64_t rbx, rsp, rbp, r12, r13, r14, r15;
uint64_t rip, rflags; uint64_t rip;
} __attribute((packed))context; } __attribute((packed))context;
typedef struct proc { typedef struct proc {