diff options
Diffstat (limited to 'kernel/main.c')
| -rw-r--r-- | kernel/main.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/kernel/main.c b/kernel/main.c index 968c9d5..4ed99b5 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -13,6 +13,19 @@ struct task_struct tasks[4] = { [TASK_FIZZBUZZ] = { .stack = init_stack[3], .addr = nullptr, .entry_offset = 0, }, }; +int next_task; + +// TODO: this feels really brittle +__kernel void switch_to(int task_id) +{ + const char *ddr = (const char *)tasks[task_id].addr + tasks[task_id].entry_offset; + + asm volatile("csrc sstatus, %[mask]" : : [mask] "r"(1 << 8)); + asm volatile("mv ra, %0" : : "r"(ddr)); + asm volatile("csrw sepc, ra"); + asm volatile("sret"); +} + /* * This is the main entry point of the kernel after head.S is done. This * function can (and will) assume that everything has been reset and that we can @@ -26,15 +39,23 @@ __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) +{ for (;;) { - // Put the machine on low power consumption since we are not doing - // anything fancy here. + if (next_task != TASK_UNKNOWN && next_task != TASK_INIT) { + switch_to(next_task); + } asm volatile("wfi"); } } |
