aboutsummaryrefslogtreecommitdiff
path: root/kernel/trap.c
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-11-22 23:00:46 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-11-22 23:00:46 +0100
commit7f6b234625a53d2ceb9ec80dc0172aac1cedb358 (patch)
tree4fe10fcbe2d5e90a0e673259dc895f48a76e06cd /kernel/trap.c
parent224ed7b13ceadd05d27e61d3a0fdd34beb0c7745 (diff)
downloadfbos-7f6b234625a53d2ceb9ec80dc0172aac1cedb358.tar.gz
fbos-7f6b234625a53d2ceb9ec80dc0172aac1cedb358.zip
Enable exception handling from user mode
This allows us to actually catch system calls and start to run user space programs. That being said, the whole thing is still pretty brittle, and the scheduler is not quite there yet. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'kernel/trap.c')
-rw-r--r--kernel/trap.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/kernel/trap.c b/kernel/trap.c
index 24b459b..84f8398 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -1,6 +1,7 @@
#include <fbos/init.h>
#include <fbos/sbi.h>
#include <fbos/printk.h>
+#include <fbos/sched.h>
// TODO: this is QEMU-specific. To obtain this:
// - Parse the DTB and look for the 'cpus.timebase-frequency' property.
@@ -15,6 +16,13 @@
// Mask for 'scause' to figure out if the interrupt was caused by the timer.
#define TIMER_SCAUSE_MASK 0x05
+// Mask for 'scause' to figure out if the exception was cause by U privilege
+// mode making an 'ecall'.
+#define USER_ECALL_MASK 0x08
+
+// Identifier for the 'write' system call.
+#define NR_WRITE 0x01
+
// Declared in include/fbos/init.h.
uint64_t seconds_elapsed;
@@ -38,6 +46,27 @@ __kernel void time_out_in_one_second(void)
}
}
+__kernel __always_inline void exception_handler(uint64_t cause)
+{
+ register char *message asm("a0");
+ register size_t n asm("a1");
+ register uint64_t syscall_id asm("a7");
+
+ if ((cause & USER_ECALL_MASK) != USER_ECALL_MASK) {
+ die("Don't know how to handle this exception :D\n");
+ }
+ if (syscall_id != NR_WRITE) {
+ 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();
+}
+
/*
* Direct interrupt handler. Handles interrupts such as the timer event and user
* mode entries.
@@ -57,13 +86,11 @@ __aligned(4) __s_interrupt __kernel void interrupt_handler(void)
asm volatile("csrr %0, scause" : "=r"(cause)::);
if (IS_EXCEPTION(cause)) {
- die("Don't know how to handle exceptions :D\n");
+ exception_handler(cause);
}
if ((cause & TIMER_SCAUSE_MASK) == TIMER_SCAUSE_MASK) {
- // Clear timer interrupt pending bit from the 'sip' register. Also clear
- // the timer interrupt enable so it's re-enabled after running the
- // fizz/buzz logic.
+ // Clear timer interrupt pending bit from the 'sip' register.
asm volatile("li t0, 32\n\t"
"csrc sip, t0\n\t"
"csrc sie, t0"
@@ -74,11 +101,13 @@ __aligned(4) __s_interrupt __kernel void interrupt_handler(void)
// BEHOLD! The fizz buzz logic! :D
seconds_elapsed += 1;
if ((seconds_elapsed % 15) == 0) {
- printk("Should run fizzbuzz\n");
+ next_task = TASK_FIZZBUZZ;
} else if ((seconds_elapsed % 5) == 0) {
- printk("Should run buzz\n");
+ next_task = TASK_BUZZ;
} else if ((seconds_elapsed % 3) == 0) {
- printk("Should run fizz\n");
+ next_task = TASK_FIZZ;
+ } else {
+ next_task = TASK_UNKNOWN;
}
// Re-enable timer interrupts.