aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile14
-rw-r--r--README.md13
-rw-r--r--include/fbos/compiler.h23
-rw-r--r--include/fbos/dt.h8
-rw-r--r--include/fbos/init.h11
-rw-r--r--include/fbos/mm.h13
-rw-r--r--include/fbos/printk.h7
-rw-r--r--include/fbos/sbi.h35
-rw-r--r--include/fbos/sched.h8
-rw-r--r--include/fbos/string.h8
-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
17 files changed, 281 insertions, 24 deletions
diff --git a/Makefile b/Makefile
index dae4248..b793ba8 100644
--- a/Makefile
+++ b/Makefile
@@ -18,16 +18,15 @@ endif
# no `-mcpu`, no `-mtune`, no funny business.
CC = $(CROSS_COMPILE)gcc$(CC_SUFFIX)
-AS = $(CROSS_COMPILE)as$(CC_SUFFIX)
LD = $(CROSS_COMPILE)ld
QEMU ?= qemu-system-riscv64
ISA ?= rv64imafdc_zicntr_zicsr_zifencei_zihpm_zca_zcd_zba_zbb
-ASFLAGS = -march=$(ISA) -mabi=lp64d
+ASFLAGS = -march=$(ISA) -mabi=lp64d -mcmodel=medany
CCFLAGS = $(ASFLAGS) -Iinclude/
CCFLAGS += -Werror -Wpedantic -Wall -Wextra -Wcast-align -Wcast-qual -Winit-self \
-Wmissing-include-dirs -Wredundant-decls -Wshadow -Wsign-conversion \
- -Wswitch-default -Wundef -Wunreachable-code -Wmissing-noreturn \
+ -Wswitch-default -Wundef -Wunreachable-code \
-nostdinc -nostdlib -std=gnu17
LDFLAGS = -Iinclude/ -static -melf64lriscv -z noexecstack
USRFLAGS = -static -melf64lriscv
@@ -48,6 +47,7 @@ ifeq ($(strip $(DEBUG)),)
CCFLAGS += -O3
QEMU_FLAGS += -nographic
else
+ ASFLAGS += -g
CCFLAGS += -g
QEMU_FLAGS += -s -S
endif
@@ -55,7 +55,7 @@ endif
##
# Paths
-SRC = $(wildcard kernel/head.S kernel/*.c)
+SRC = $(filter-out kernel/fbos.ld.S, $(wildcard kernel/*.S kernel/*.c))
OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SRC)))
LINKER = kernel/fbos.ld
KRNL = fbos
@@ -83,7 +83,7 @@ $(KRNL): $(OBJ) $(LINKER).S
.S.o:
$(E) " CC " $(*F)
- $(Q) $(CC) $(CCFLAGS) -c $< -o $@
+ $(Q) $(CC) $(CCFLAGS) -D__ASSEMBLY__ -c $< -o $@
##
# User space
@@ -94,8 +94,8 @@ usr: $(USR)
$(Q) find usr/bin/ -type f -executable | cpio -o --quiet -H newc > $(INIT)
usr/src/%.o: usr/src/%.S
- $(E) " AS " $(basename $@)
- $(Q) $(AS) $(ASFLAGS) -c $< -o $@
+ $(E) " CC " $(basename $@)
+ $(Q) $(CC) $(ASFLAGS) -D__ASSEMBLY__ -c $< -o $@
usr/bin/%: usr/src/%.o
$(Q) mkdir -p usr/bin/
diff --git a/README.md b/README.md
index 8ce947f..a7f8799 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,19 @@ $ make gdb GDB_EXTRA_FLAGS="-tui"
And now you have started a GDB session with a nice TUI interface.
+## Requirements
+
+We do not want to support a myriad of different scenarios, but we want to keep
+things simple. Hence, here there are some limitations/requirements:
+
+- You need a recent enough OpenSBI running on your firmware. I have tested this
+ on a QEMU which has OpenSBI v1.5, but any firmware that implements a Runtime
+ SBI version of 2.0 should be fine.
+- You are supposed to pass an `initrd` always. This kernel will not try to
+ magically come up with a made up file system or try to fetch something from an
+ existing one. An `initrd` is already provided for you on the default `make`
+ target, and that's what you are supposed to be passing to the kernel.
+
## Special thanks to
SUSE for organizing [Hack Week 24](https://hackweek.opensuse.org/24/projects).
diff --git a/include/fbos/compiler.h b/include/fbos/compiler.h
index edf24d1..5e61ebd 100644
--- a/include/fbos/compiler.h
+++ b/include/fbos/compiler.h
@@ -1,9 +1,30 @@
#ifndef __FBOS_COMPILER_H
#define __FBOS_COMPILER_H
+/*
+ * Nicer looking versions of compiler attributes.
+ */
+
#define __noreturn __attribute__((__noreturn__))
+/*
+ * Compiler attributes specific to linker sections.
+ */
+
#define __section(s) __attribute__((__section__(s)))
-#define __kernel __section(".text.kernel")
+#define __kernel __section(".kernel.text")
+
+/*
+ * Multiple aliases for 64-bit integers which have their definition on the
+ * standard library.
+ */
+
+typedef long ssize_t;
+typedef unsigned long size_t;
+typedef unsigned long uint64_t;
+typedef unsigned long uintptr_t;
+
+// Helpful macro when prototyping.
+#define __unused(x) (void)x
#endif /* __FBOS_COMPILER_H */
diff --git a/include/fbos/dt.h b/include/fbos/dt.h
new file mode 100644
index 0000000..39d8381
--- /dev/null
+++ b/include/fbos/dt.h
@@ -0,0 +1,8 @@
+#ifndef __FBOS_DT_H_
+#define __FBOS_DT_H_
+
+#include <fbos/compiler.h>
+
+void parse_dtb(uint64_t *dtb);
+
+#endif // __FBOS_DT_H_
diff --git a/include/fbos/init.h b/include/fbos/init.h
index 1eeb33a..a919405 100644
--- a/include/fbos/init.h
+++ b/include/fbos/init.h
@@ -1,8 +1,11 @@
-#ifndef FBOS_INIT_H
-#define FBOS_INIT_H
+#ifndef __FBOS_INIT_H
+#define __FBOS_INIT_H
#include <fbos/compiler.h>
-extern __noreturn __kernel void start_kernel(void);
+extern struct task_struct init_task;
-#endif /* FBOS_INIT_H */
+// The entry point for the kernel.
+__noreturn __kernel void start_kernel(uintptr_t *dtb);
+
+#endif /* __FBOS_INIT_H */
diff --git a/include/fbos/mm.h b/include/fbos/mm.h
index 2b80076..25d18ce 100644
--- a/include/fbos/mm.h
+++ b/include/fbos/mm.h
@@ -1,5 +1,5 @@
-#ifndef FBOS_MM_H
-#define FBOS_MM_H
+#ifndef __FBOS_MM_H
+#define __FBOS_MM_H
/*
* Page = 4KB.
@@ -7,10 +7,17 @@
#define PAGE_SIZE 0x1000
/*
+ * Initial size of the thread, which coincides with the size of the stack for a
+ * given thread.
+ */
+#define THREAD_SIZE_ORDER 2
+#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+
+/*
* The code will be linked to start at the first page, which will have a given
* offset.
*/
#define PAGE_OFFSET 0x80200000
#define LINK_ADDR PAGE_OFFSET
-#endif /* FBOS_MM_H */
+#endif /* __FBOS_MM_H */
diff --git a/include/fbos/printk.h b/include/fbos/printk.h
new file mode 100644
index 0000000..2c82eda
--- /dev/null
+++ b/include/fbos/printk.h
@@ -0,0 +1,7 @@
+#ifndef __FBOS_PRINTK_H_
+#define __FBOS_PRINTK_H_
+
+extern void die(const char *const message);
+extern void printk(const char *const message);
+
+#endif // __FBOS_PRINTK_H_
diff --git a/include/fbos/sbi.h b/include/fbos/sbi.h
new file mode 100644
index 0000000..a6b893d
--- /dev/null
+++ b/include/fbos/sbi.h
@@ -0,0 +1,35 @@
+#ifndef __FBOS_SBI_H_
+#define __FBOS_SBI_H_
+
+// TODO
+/* SBI_SUCCESS 0 Completed successfully */
+/* SBI_ERR_FAILED -1 Failed */
+/* SBI_ERR_NOT_SUPPORTED -2 Not supported */
+/* SBI_ERR_INVALID_PARAM -3 Invalid parameter(s) */
+/* SBI_ERR_DENIED -4 Denied or not allowed */
+/* SBI_ERR_INVALID_ADDRESS -5 Invalid address(s) */
+/* SBI_ERR_ALREADY_AVAILABLE -6 Already available */
+/* SBI_ERR_ALREADY_STARTED -7 Already started */
+/* SBI_ERR_ALREADY_STOPPED -8 Already stopped */
+/* SBI_ERR_NO_SHMEM -9 Shared memory not available */
+
+enum sbi_ext {
+ DBCN_EXT = 0x4442434E,
+};
+
+enum dbcn_actions {
+ DBCN_WRITE = 0x00,
+};
+
+struct sbi_ret {
+ long error;
+ long value;
+};
+
+extern 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);
+
+#define sbi_ecall2(ext, fid, arg0, arg1) __sbi_ecall(arg0, arg1, 0, 0, 0, 0, fid, ext)
+
+#endif // __FBOS_SBI_H_
diff --git a/include/fbos/sched.h b/include/fbos/sched.h
new file mode 100644
index 0000000..626f72f
--- /dev/null
+++ b/include/fbos/sched.h
@@ -0,0 +1,8 @@
+#ifndef __FBOS_SCHED_H_
+#define __FBOS_SCHED_H_
+
+struct task_struct {
+ void *stack;
+};
+
+#endif // __FBOS_SCHED_H_
diff --git a/include/fbos/string.h b/include/fbos/string.h
new file mode 100644
index 0000000..c3da266
--- /dev/null
+++ b/include/fbos/string.h
@@ -0,0 +1,8 @@
+#ifndef __FBOS_STRING_H_
+#define __FBOS_STRING_H_
+
+#include <fbos/compiler.h>
+
+extern size_t strlen(const char *);
+
+#endif // __FBOS_STRING_H_
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