aboutsummaryrefslogtreecommitdiff
path: root/kernel/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/head.S')
-rw-r--r--kernel/head.S52
1 files changed, 52 insertions, 0 deletions
diff --git a/kernel/head.S b/kernel/head.S
index c8f523d..210eb7c 100644
--- a/kernel/head.S
+++ b/kernel/head.S
@@ -1,9 +1,61 @@
+#include <fbos/image.h>
#include <fbos/mm.h>
.global _start
+.global _start_kernel
.section .head.text
+// Since this kernel boots in virtualization environments and machines that are
+// expecting a Linux kernel, we have to adhere to how bootloaders expect Linux
+// kernel images to look like. In particular, the entry of the kernel is
+// actually a Boot image header, as defined in:
+//
+// https://docs.kernel.org/arch/riscv/boot-image-header.html
+//
+// Conveniently, for machines who don't care about this (e.g. QEMU), the first
+// 64 bits correspond to two instructions that can be set up, and hence entering
+// here will simply jumpt to `_start_kernel`, our real entry.
_start:
+ // The first two words give us room for two executable instructions. Linux
+ // uses that on EFI support to first allocate a magic value for UEFI and
+ // then have a `j _start_kernel` instruction. Otherwise it just allocates
+ // the first one for `j _start_kernel` and leaves the second word empty. The
+ // latter is what we do here as well.
+ j _start_kernel
+ .word 0
+
+ // Ensure alignment for the next double word.
+ .balign 8
+
+ // Load offset. Note that this matches the PAGE_OFFSET as defined in
+ // `include/mm.h`.
+ .dword 0x200000
+
+ // Size of the image. This is *mandatory* as per bootloader request.
+ .dword _end - _start
+
+ // Flags. As defined by Linux, only one bit matters here, which is related
+ // to endianness. Setting 0 means little-endian.
+ .dword 0
+
+ // Header version.
+ .word RISCV_HEADER_VERSION
+
+ // Reserved fields.
+ .word 0
+ .dword 0
+
+ // Deprecated image magic.
+ .ascii RISCV_IMAGE_MAGIC
+ .balign 4
+
+ // Good image magic, in little-endian format.
+ .ascii RISCV_IMAGE_MAGIC2
+
+ // Reserved field.
+ .word 0
+
+_start_kernel:
// Mask all interrupts
csrw sie, zero
csrw sip, zero