From 312cc56a7d86d1cbac72d961d6ccaad999a23ac0 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Thu, 23 Apr 2020 23:36:01 +0200 Subject: [PATCH] Add draft of stivale specification --- STIVALE.md | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 STIVALE.md diff --git a/STIVALE.md b/STIVALE.md new file mode 100644 index 00000000..aa22ed62 --- /dev/null +++ b/STIVALE.md @@ -0,0 +1,115 @@ +# stivale boot protocol specification + +The stivale boot protocol aims to be a *simple* to implement protocol which +provides the kernel with most of the features one may need in a *modern* +x86_64 context. + +## General information + +In order to have a stivale compliant kernel, one must have a kernel executable +in the `elf64` format and have a `.stivalehdr` section (described below). +Other executable formats are not supported. + +stivale natively supports and encourages higher half kernels. +The kernel can load itself at `0xffffffff80100000` (as defined in the linker script) +and the bootloader will take care of everything, no AT linker script directives needed. + +If the kernel loads itself in the lower half (`0x100000` or higher), the bootloader +will not perform the higher half relocation. + +The kernel MUST NOT overwrite anything below `0x100000` (physical memory) as that +is where the bootloader memory structures reside. +Once the kernel is DONE depending on the bootloader (for page tables, structures, ...) +then these areas can be reclaimed if one wants. + +The kernel MUST NOT request to load itself at an address lower than `0x100000` +(or `0xffffffff80100000` for higher half kernels) for the same reasons as above. + +## Kernel entry machine state + +`rip` will be the entry point as defined in the ELF file. + +At entry, the bootloader will have setup paging such that there is a 4GiB identity +mapped block of memory at `0x0000000000000000`, a 2GiB mapped area of memory +that maps from `0x0000000000000000` physical to `0x0000000080000000` physical +to `0xffffffff80000000` virtual. This area is for the higher half kernels. +Further more, a 4GiB area of memory from `0x0000000000000000` physical to +`0x0000000100000000` physical to `0xffff800000000000` virtual is mapped. + +The kernel should NOT modify the bootloader page tables, and it should only use them +to bootstrap its own virtual memory manager and its own page tables. + +At entry all segment registers are loaded as 64 bit code/data segments, limits and +bases are ignored since this is Long Mode. + +DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load +its own GDT as soon as possible and not rely on the bootloader's. + +The IDT is in an undefined state. Kernel must load its own. + +IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined. + +PG is enabled (`cr0`), PE is enabled (`cr0`), PAE is enabled (`cr4`), +LME is enabled (`EFER`). + +The A20 gate is enabled. + +`rsp` is set to the requested stack as per stivale header. + +`rdi` will point to the stivale structure (described below). + +## stivale header (.stivalehdr) + +The kernel executable shall have a section `.stivalehdr` which will contain +the header that the bootloader will parse. + +Said header looks like this: +```c +struct stivale_header { + uint64_t stack; // This is the stack address which will be in RSP + // when the kernel is loaded. + + uint16_t flags; // Flags + // bit 0 0 = text mode, 1 = graphics mode + // All other bits undefined. + + uint16_t framebuffer_width; // These 3 values are parsed if a graphics mode + uint16_t framebuffer_height; // is requested. If all values are set to 0 + uint16_t framebuffer_bpp; // then the bootloader will pick the best possible + // video mode automatically (recommended). +} __attribute__((packed)); +``` + +## stivale structure + +The stivale structure returned by the bootloader looks like this: +```c +struct stivale_struct { + uint64_t cmdline; // Pointer to a null-terminated cmdline + uint64_t memory_map_addr; // Pointer to the memory map + uint64_t memory_map_entries; // Count of memory map entries + uint64_t framebuffer_addr; // Address of the framebuffer and related info + uint16_t framebuffer_pitch; + uint16_t framebuffer_width; + uint16_t framebuffer_height; + uint16_t framebuffer_bpp; + uint64_t rsdp; // Pointer to the ACPI RSDP structure + uint64_t module_count; // Count of modules that stivale loaded according to config + uint64_t modules; // Pointer to the first entry in the linked list of modules +} __attribute__((packed)); +``` + +## Modules + +The `modules` variable points to the first entry of the linked list of module +structures. +A module structure looks like this: +```c +struct stivale_module { + uint64_t begin; // Address where the module is loaded + uint64_t end; // End address of the module + char string[128]; // String passed to the module (by config file) + uint64_t next; // Pointer to the next module (if any), check module_count + // in the stivale_struct +} __attribute__((packed)); +```