aboutsummaryrefslogtreecommitdiff
path: root/kernel/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/main.c')
-rw-r--r--kernel/main.c25
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");
}
}