aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fbos.ld.S10
-rw-r--r--kernel/head.S52
2 files changed, 59 insertions, 3 deletions
diff --git a/kernel/fbos.ld.S b/kernel/fbos.ld.S
index f74d90f..160a5cb 100644
--- a/kernel/fbos.ld.S
+++ b/kernel/fbos.ld.S
@@ -1,8 +1,11 @@
#include <fbos/mm.h>
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
SECTIONS {
// Ensure that the image starts at the very exact address SBI expects it to.
- . = LINK_ADDR;
+ . = LOAD_OFFSET;
_start = .;
. = ALIGN(PAGE_SIZE);
@@ -10,8 +13,9 @@ SECTIONS {
// instead of clumping it into the main `.text` one. Well, I'm no expert on
// linker configuration, so patches are welcome :)
.text : {
+ // head.S
+ KEEP(*(.head.text))
_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
@@ -19,7 +23,7 @@ SECTIONS {
. = ALIGN(PAGE_SIZE);
// From now on the rest of the `.text` could just be a continuation, but
- // I further split it into `.text.kernel` so the jump from head isn't
+ // I further split it into `.kernel.text` so the jump from head isn't
// that large. That is, we put first the very core of the kernel, and
// the rest can go wherever.
__kernel_text_start = .;
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