From 76103215711d268b4b02f62e900f2be3032cf295 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 02:18:30 +0200 Subject: Initial commit: raisernics toy kernel - Bare-metal x86_64 UEFI kernel (PE32+, no libc) - GOP framebuffer + 8x16 bitmap font - PS/2 keyboard (polling, scancode set 1) - UART 16550 serial driver (COM1, 115200 8N1) - Bump allocator as #[global_allocator] (alloc::String, Vec, format!) - UEFI memory map capture (static buffer, ADR 0001) - Shell with 7 commands (help, echo, clear, hello, info, mem, halt) - Dual output: GOP framebuffer + serial console - Makefile: run, run-gui, debug, release, image targets - tools/: qemu.sh, boot-image.sh, debug-kernel.py --- docs/adr/0001-static-buffer-for-memory-map.md | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 docs/adr/0001-static-buffer-for-memory-map.md (limited to 'docs') diff --git a/docs/adr/0001-static-buffer-for-memory-map.md b/docs/adr/0001-static-buffer-for-memory-map.md new file mode 100644 index 0000000..75a4059 --- /dev/null +++ b/docs/adr/0001-static-buffer-for-memory-map.md @@ -0,0 +1,54 @@ +# ADR 0001 — Static .bss Buffer for UEFI Memory Map Capture + +## Status + +Accepted. + +## Context + +Before calling `ExitBootServices`, the kernel must obtain the UEFI memory map +to know which physical memory regions are available. The standard UEFI recipe +is: + +1. Call `GetMemoryMap` with a null buffer to get the required buffer size. +2. Allocate a buffer (via `AllocatePool`). +3. Call `GetMemoryMap` again to fill the buffer, receiving a `MapKey`. +4. Call `ExitBootServices(image_handle, MapKey)`. + +**Problem:** Steps 2 and 3 change the memory map themselves (the pool +allocation adds entries). After step 3 we have a valid `MapKey` for the +map *as it was during step 3*, but calling `FreePool` on the buffer +(before step 4) would change the map again and invalidate the key. +Not freeing the buffer leaks pool memory, but more importantly, the +default approach of `AllocatePool + GetMemoryMap + ExitBootServices` +between two `GetMemoryMap` calls makes the key fragile. + +## Decision + +Use a **pre-allocated static buffer in `.bss`** (64 KB) instead of +dynamically allocating a pool buffer. Because the buffer already exists, +no `AllocatePool`/`FreePool` calls happen between `GetMemoryMap` and +`ExitBootServices`. + +The sequence becomes: + +1. `GetMemoryMap(null)` → determine required size. +2. `GetMemoryMap(static_buf)` → fill the map, receive `MapKey`. +3. `ExitBootServices(image_handle, MapKey)` — no pool allocation + happened after step 2, so the key is guaranteed valid. + +If the static buffer is too small (it shouldn't be — 64 KB holds ~1300 +descriptors, real firmware typically uses ~50–150), the caller falls +back to a pool-allocated buffer. + +## Consequences + +- **Positive:** The `MapKey` is never invalidated between capture and + `ExitBootServices`. The boot sequence is simpler and more reliable. +- **Positive:** No pool memory leaks — the static buffer lives in `.bss` + and costs nothing to keep. +- **Negative:** 64 KB of `.bss` is permanently reserved (irrelevant on a + kernel that owns all memory). +- **Negative:** The buffer size is fixed at compile time; pathological + firmware with thousands of entries would require a fallback path + (implemented but never hit in practice). -- cgit v1.2.3