aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/dt.c6
-rw-r--r--kernel/fbos.ld.S12
-rw-r--r--kernel/head.S55
-rw-r--r--kernel/main.c18
-rw-r--r--kernel/printk.c23
-rw-r--r--kernel/sbi.c29
-rw-r--r--kernel/strlen.S22
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