From 2fa2fb2220f71390b2976b101e3a605ed87f38da Mon Sep 17 00:00:00 2001 From: mintsuki Date: Tue, 22 Mar 2022 05:43:38 +0100 Subject: [PATCH] docs: Initial Limine protocol draft --- PROTOCOL.md | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 PROTOCOL.md diff --git a/PROTOCOL.md b/PROTOCOL.md new file mode 100644 index 00000000..b88da038 --- /dev/null +++ b/PROTOCOL.md @@ -0,0 +1,137 @@ +# The Limine Boot Protocol + +The Limine boot protocol is a modern, minimal, fast, and extensible boot +protocol, with a focus on backwards and forwards compatibility, +created from the experienced gained by working on the +[stivale boot protocols](https://github.com/stivale). + +This file serves as the official centralised collection of features that +the Limine boot protocol is composed of. Other bootloaders may support extra +unofficial features, but it is strongly recommended to avoid fragmentation +and submit new features by opening a pull request to this repository. + +## Features + +The protocol is centered around the concept of request/response - collectively +named "features" - where the kernel requests some action or information from +the bootloader, and the bootloader responds accordingly, if it is capable of +doing so. + +In C terms, a feature is composed of 2 structure: the request, and the response. + +A request has 3 mandatory members at the beginning of the structure: +```c +struct limine_example_request { + uint64_t id[4]; + uint64_t revision; + struct limine_example_response *response; + ... optional members follow ... +}; +``` +* `id` - The ID of the request. This is an 8-byte aligned magic number that the +bootloader will scan for inside the executable file to find requests. Requests +may be located anywhere inside the executable as long as they are 8-byte +aligned. There may only be 1 of the same request. The bootloader will refuse +to boot an executable with multiple of the same request IDs. +* `revision` - The revision of the request that the kernel provides. This is +bumped whenever new members or functionality are added to the request structure. +Bootloaders process requests in a backwards compatible manner, *always*. This +means that if the bootloader does not support the revision of the request, +it will process the request as if were the highest revision that the bootloader +supports. +* `response` - This field is filled in by the bootloader at load time, with a +pointer to the response structure, if the request was successfully processed. +If the request is unsupported or was not successfully processed, this field +is *left untouched*, meaning that if it was set to `NULL`, it will stay that +way. + +A response has only 1 mandatory member at the beginning of the structure: +```c +struct limine_example_response { + uint64_t revision; + ... optional members follow ... +}; +``` +* `revision` - Like for requests, bootloaders will instead mark responses with a +revision number. This revision is not coupled between requests and responses, +as they are bumped individually when new members are added or functionality is +changed. Bootloaders will set the revision to the one they provide, and this is +*always backwards compatible*, meaning higher revisions support all that lower +revisions do. + +This is all there is to features. For a list of official Limine features, read +the "Feature List" section below. + +## Executable memory layout + +The protocol mandates kernels to load themselves at or above +`0xffffffff80000000`. Lower half kernels are *not supported*. + +At handoff, the kernel will be properly loaded and mapped with appropriate +MMU permissions at the requested virtual memory address (provided it is at +or above `0xffffffff80000000`). + +No specific physical memory placement is guaranteed. In order to determine +where the kernel is loaded in physical memory, see the Kernel Address feature +below. + +Alongside the loaded kernel, the bootloader will set up memory mappings as such: +``` + Base Physical Address - Size -> Virtual address + 0x0000000000001000 - 4 GiB plus any additional memory map entry -> 0x0000000000001000 + 0x0000000000000000 - 4 GiB plus any additional memory map entry -> HHDM start +``` +Where HHDM start is returned by the Higher Half Direct Map feature (see below). +These mappings are supervisor, read, write, execute (-rwx). + +The bootloader page tables are in bootloader-reclaimable memory (see Memory Map +feature below), and their specific layout is undefined as long as they provide +the above memory mappings. + +If the kernel is a position independent executable, the bootloader is free to +relocate it as it sees fit, potentially performing KASLR (as specified by the +config). + +## Entry machine state + +### x86_64 + +`rip` will be the entry point as defined as part of the executable file format, +unless the an Entry Point feature is requested (see below), in which case, +the value of `rip` is going to be taken from there. + +At entry all segment registers are loaded as 64 bit code/data segments, limits +and bases are ignored since this is 64-bit mode. + +The GDT register is loaded to point to a GDT, in bootloader-reserved memory, +with at least the following entries, starting at offset 0: + + - Null descriptor + - 16-bit code descriptor. Base = `0`, limit = `0xffff`. Readable. + - 16-bit data descriptor. Base = `0`, limit = `0xffff`. Writable. + - 32-bit code descriptor. Base = `0`, limit = `0xffffffff`. Readable. + - 32-bit data descriptor. Base = `0`, limit = `0xffffffff`. Writable. + - 64-bit code descriptor. Base and limit irrelevant. Readable. + - 64-bit data descriptor. Base and limit irrelevant. Writable. + +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`). +If 5-level paging is requested and available, then 5-level paging is enabled +(LA57 bit in `cr4`). +The NX bit will be enabled (NX bit in `EFER`). + +The A20 gate is opened. + +Legacy PIC and IO APIC IRQs are all masked. + +If booted by EFI/UEFI, boot services are exited. + +`rsp` is set to point to a stack, in bootloader-reserved memory, which is +at least 8KiB (8192 bytes) in size. An invalid return address of 0 is pushed +to the stack before jumping to the kernel. + +All other general purpose registers are set to 0.