diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fbos.ld.S | 10 | ||||
| -rw-r--r-- | kernel/head.S | 52 |
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 |
