From 192208770d3866838a450462dd4b1fc8e2b5c91a Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Sun, 24 Nov 2024 22:07:51 +0100 Subject: Simplify scheduling by introducing an init process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scheduling is easier if there is an init process which does nothing. This way we don't have to perform hacks in order to idle in S privilege mode while touching special registers in weird ways. For now this process is kind of costly since 'wfi' is not accepted in this context, but this can be further tuned down in the future by setting TW=1 on 'mstatus', or by handling the exception and allowing it if it comes from the proper process. All of that being said, there is still work to be done as things fail when optimitzations are on. Signed-off-by: Miquel Sabaté Solà --- Makefile | 2 +- include/fbos/sched.h | 7 ++----- kernel/initrd.c | 4 +++- kernel/main.c | 16 ++-------------- kernel/trap.c | 19 ++++++++++--------- usr/src/init.S | 8 ++++++++ 6 files changed, 26 insertions(+), 30 deletions(-) create mode 100644 usr/src/init.S diff --git a/Makefile b/Makefile index a9c0223..b3642f0 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ SRC = $(filter-out kernel/fbos.ld.S, $(wildcard kernel/*.S kernel/*.c lib/*.c OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SRC))) LINKER = kernel/fbos.ld KRNL = fbos -USR = usr/bin/fizz usr/bin/buzz usr/bin/fizzbuzz +USR = usr/bin/init usr/bin/fizz usr/bin/buzz usr/bin/fizzbuzz INIT = usr/initramfs.cpio TESTS = test/test_dt test/test_initrd diff --git a/include/fbos/sched.h b/include/fbos/sched.h index c2a4b19..e05d0a1 100644 --- a/include/fbos/sched.h +++ b/include/fbos/sched.h @@ -23,10 +23,7 @@ struct task_struct { // Tasks available on this kernel. extern struct task_struct tasks[4]; -// Identifier for the next task to be run. -extern int next_task; - -// Bring the machine to idle mode. -__noreturn __kernel void idle(void); +// Switch execution to the given task id. +void switch_to(int task_id); #endif // __FBOS_SCHED_H_ diff --git a/kernel/initrd.c b/kernel/initrd.c index a5c8861..ff1f52b 100644 --- a/kernel/initrd.c +++ b/kernel/initrd.c @@ -53,7 +53,9 @@ __kernel uint64_t strtoul16(const char *str, size_t count) __kernel int get_task_id_from_name(const char *const name) { - if (strcmp(name, "usr/bin/fizz") == 0) { + if (strcmp(name, "usr/bin/init") == 0) { + return TASK_INIT; + } else if (strcmp(name, "usr/bin/fizz") == 0) { return TASK_FIZZ; } else if (strcmp(name, "usr/bin/buzz") == 0) { return TASK_BUZZ; diff --git a/kernel/main.c b/kernel/main.c index 4ed99b5..ba4ada0 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -13,9 +13,7 @@ struct task_struct tasks[4] = { [TASK_FIZZBUZZ] = { .stack = init_stack[3], .addr = nullptr, .entry_offset = 0, }, }; -int next_task; - -// TODO: this feels really brittle +// TODO __kernel void switch_to(int task_id) { const char *ddr = (const char *)tasks[task_id].addr + tasks[task_id].entry_offset; @@ -23,7 +21,6 @@ __kernel void switch_to(int task_id) asm volatile("csrc sstatus, %[mask]" : : [mask] "r"(1 << 8)); asm volatile("mv ra, %0" : : "r"(ddr)); asm volatile("csrw sepc, ra"); - asm volatile("sret"); } /* @@ -39,23 +36,14 @@ __noreturn __kernel void start_kernel(void *dtb) struct initrd_addr addr = find_dt_initrd_addr(dtb); extract_initrd((unsigned char *)addr.start, addr.end - addr.start); - next_task = TASK_UNKNOWN; - // At this point everything has already been handled: setup the interrupt // vector and enable the timer to start ticking and scheduling the three // tasks at hand. seconds_elapsed = 0; setup_interrupts(); - idle(); -} - -__noreturn __kernel void idle(void) -{ + // Loop indefinitely while preserving power. for (;;) { - if (next_task != TASK_UNKNOWN && next_task != TASK_INIT) { - switch_to(next_task); - } asm volatile("wfi"); } } diff --git a/kernel/trap.c b/kernel/trap.c index 84f8398..bf8a89e 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -59,12 +59,7 @@ __kernel __always_inline void exception_handler(uint64_t cause) die("Bad syscall\n"); } - // TODO: acknowledge 'sip' bit? - next_task = TASK_UNKNOWN; write(message, n); - - // TODO: is it safe to jump to idle here? Any preparation to be done? - idle(); } /* @@ -79,6 +74,9 @@ __kernel __always_inline void exception_handler(uint64_t cause) * all registers. It's probably a bit over the top since it also does that for * registers we never care on this kernel (e.g. floating point registers), but * it's convenient. + * + * TODO: once this properly works, switch it to assembly to avoid creepy + * statements like the sad 'goto end' one. */ __aligned(4) __s_interrupt __kernel void interrupt_handler(void) { @@ -87,6 +85,8 @@ __aligned(4) __s_interrupt __kernel void interrupt_handler(void) if (IS_EXCEPTION(cause)) { exception_handler(cause); + switch_to(TASK_INIT); + goto end; } if ((cause & TIMER_SCAUSE_MASK) == TIMER_SCAUSE_MASK) { @@ -101,13 +101,12 @@ __aligned(4) __s_interrupt __kernel void interrupt_handler(void) // BEHOLD! The fizz buzz logic! :D seconds_elapsed += 1; if ((seconds_elapsed % 15) == 0) { - next_task = TASK_FIZZBUZZ; + switch_to(TASK_FIZZBUZZ); } else if ((seconds_elapsed % 5) == 0) { - next_task = TASK_BUZZ; + switch_to(TASK_BUZZ); } else if ((seconds_elapsed % 3) == 0) { - next_task = TASK_FIZZ; + switch_to(TASK_FIZZ); } else { - next_task = TASK_UNKNOWN; } // Re-enable timer interrupts. @@ -122,6 +121,8 @@ __aligned(4) __s_interrupt __kernel void interrupt_handler(void) } else { printk("WARN: unknown interrupt just came in...\n"); } + +end:; } __kernel void setup_interrupts(void) diff --git a/usr/src/init.S b/usr/src/init.S new file mode 100644 index 0000000..6566f20 --- /dev/null +++ b/usr/src/init.S @@ -0,0 +1,8 @@ +.global _start +.text + +_start: +.Loop: + // TODO + // wfi + j .Loop -- cgit v1.2.3