diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/dt.c | 6 | ||||
| -rw-r--r-- | kernel/fbos.ld.S | 12 | ||||
| -rw-r--r-- | kernel/head.S | 55 | ||||
| -rw-r--r-- | kernel/main.c | 18 | ||||
| -rw-r--r-- | kernel/printk.c | 23 | ||||
| -rw-r--r-- | kernel/sbi.c | 29 | ||||
| -rw-r--r-- | kernel/strlen.S | 22 |
7 files changed, 156 insertions, 9 deletions
diff --git a/kernel/dt.c b/kernel/dt.c new file mode 100644 index 0000000..55fa970 --- /dev/null +++ b/kernel/dt.c @@ -0,0 +1,6 @@ +#include <fbos/dt.h> + +__kernel void parse_dtb(uint64_t *dtb) +{ + __unused(dtb); +} diff --git a/kernel/fbos.ld.S b/kernel/fbos.ld.S index f288161..f74d90f 100644 --- a/kernel/fbos.ld.S +++ b/kernel/fbos.ld.S @@ -3,15 +3,15 @@ SECTIONS { // Ensure that the image starts at the very exact address SBI expects it to. . = LINK_ADDR; + _start = .; + . = ALIGN(PAGE_SIZE); // You would usually want to separate the head section into its own thing // instead of clumping it into the main `.text` one. Well, I'm no expert on // linker configuration, so patches are welcome :) .text : { - // The very first thing has to be the `_start` function, which is where - // SBI will jump into. Afterwards comes the rest of `.text.head`. - _start = .; - *(.text.head) + _text = .; + *(.head.text) // Aligning it to a full page is maybe a bit too much considering how // small `.text.head` really is. I just saw this same thing on the Linux @@ -23,7 +23,7 @@ SECTIONS { // that large. That is, we put first the very core of the kernel, and // the rest can go wherever. __kernel_text_start = .; - *(.text.kernel) + *(.kernel.text) __kernel_text_end = .; // And the rest. @@ -49,4 +49,6 @@ SECTIONS { .bss : { *(.bss) } + + _end = .; } diff --git a/kernel/head.S b/kernel/head.S index ba155cb..de7852b 100644 --- a/kernel/head.S +++ b/kernel/head.S @@ -1,6 +1,55 @@ +#include <fbos/mm.h> + .global _start -.section .text.head +.section .head.text _start: - // TODO - call start_kernel + // Mask all interrupts + csrw sie, zero + csrw sip, zero + + // Flush the instruction cache + fence.i + + // Reset all registers except ra, a0, a1. + li sp, 0 + li gp, 0 + li tp, 0 + li t0, 0 + li t1, 0 + li t2, 0 + li s0, 0 + li s1, 0 + li a2, 0 + li a3, 0 + li a4, 0 + li a5, 0 + li a6, 0 + li a7, 0 + li s2, 0 + li s3, 0 + li s4, 0 + li s5, 0 + li s6, 0 + li s7, 0 + li s8, 0 + li s9, 0 + li s10, 0 + li s11, 0 + li t3, 0 + li t4, 0 + li t5, 0 + li t6, 0 + csrw sscratch, 0 + + // Point tp and sp to the init task. + la tp, init_task + la sp, init_task + THREAD_SIZE + + // The `start_kernel` function requires an argument to be passed, which is + // the pointer to the `fdt` blob. The bootloader puts this on the `a1` + // register, so let's move it now to `a0`. + mv a0, a1 + + // Start the kernel. + tail start_kernel diff --git a/kernel/main.c b/kernel/main.c index 325f858..07188b9 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,12 +1,28 @@ #include <fbos/init.h> +#include <fbos/printk.h> +#include <fbos/mm.h> +#include <fbos/sched.h> +#include <fbos/dt.h> + +unsigned long init_stack[THREAD_SIZE / sizeof(unsigned long)]; + +struct task_struct init_task = { .stack = init_stack }; /* * 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 * start the whole thing. */ -__noreturn __kernel void start_kernel(void) +__noreturn __kernel void start_kernel(uintptr_t *dtb) { + // TODO: disable irqs, etc. + + printk("Welcome to FizzBuzz OS!\n"); + + parse_dtb(dtb); + + // TODO: reenable stuff + for (;;) ; } diff --git a/kernel/printk.c b/kernel/printk.c new file mode 100644 index 0000000..c0eedd9 --- /dev/null +++ b/kernel/printk.c @@ -0,0 +1,23 @@ +#include <fbos/printk.h> +#include <fbos/string.h> +#include <fbos/sbi.h> + +void __noreturn __kernel die(const char *const message) +{ + if (message) { + printk(message); + } + + for (;;) + ; +} + +void __kernel printk(const char *const message) +{ + size_t len = strlen(message); + if (!len) { + return; + } + + sbi_ecall2(DBCN_EXT, DBCN_WRITE, len, (unsigned long)message); +} diff --git a/kernel/sbi.c b/kernel/sbi.c new file mode 100644 index 0000000..ff7556c --- /dev/null +++ b/kernel/sbi.c @@ -0,0 +1,29 @@ +#include <fbos/compiler.h> +#include <fbos/sbi.h> + +/* Implementation taken from the Linux kernel (6.12) */ +__kernel struct sbi_ret __sbi_ecall(unsigned long arg0, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5, + int fid, int ext) +{ + struct sbi_ret ret; + + register uintptr_t a0 asm("a0") = (uintptr_t)(arg0); + register uintptr_t a1 asm("a1") = (uintptr_t)(arg1); + register uintptr_t a2 asm("a2") = (uintptr_t)(arg2); + register uintptr_t a3 asm("a3") = (uintptr_t)(arg3); + register uintptr_t a4 asm("a4") = (uintptr_t)(arg4); + register uintptr_t a5 asm("a5") = (uintptr_t)(arg5); + register uintptr_t a6 asm("a6") = (uintptr_t)(fid); + register uintptr_t a7 asm("a7") = (uintptr_t)(ext); + + asm volatile("ecall" + : "+r"(a0), "+r"(a1) + : "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7) + : "memory"); + + ret.error = (long)a0; + ret.value = (long)a1; + + return ret; +} diff --git a/kernel/strlen.S b/kernel/strlen.S new file mode 100644 index 0000000..6185b94 --- /dev/null +++ b/kernel/strlen.S @@ -0,0 +1,22 @@ +.globl strlen +.type strlen, @function + +/* + * Defined in include/fbos/string.h + * + * size_t strlen(const char *str) + * + * Returns (a0): string length. + * Parameter (a0): string to measure. + * Clobbers: t0, t1. + */ +strlen: + mv t1, a0 +1: + lbu t0, 0(t1) + beqz t0, 2f + addi t1, t1, 1 + j 1b +2: + sub a0, t1, a0 + ret |
