reclaiming uefi memory

This commit is contained in:
2026-07-03 19:31:32 +01:00
parent 50f3610768
commit 21b9691486
6 changed files with 79 additions and 48 deletions
+30 -22
View File
@@ -32,8 +32,7 @@ Defined in `src/root.zig`, the shared loader↔kernel contract:
```zig
pub const MemoryKind = enum(u32) {
usable, // free RAM the kernel may allocate
reserved, // firmware / kernel image — real RAM, but never hand out
reclaimable, // usable once boot-time structures are done with
reserved, // firmware / kernel image / boot stack — real RAM, never hand out
acpi_tables, // parse, then reclaim
acpi_nvs, // preserve across sleep
mmio, // device registers / reserved address space — not RAM at all
@@ -72,11 +71,19 @@ pub const BootInfo = extern struct {
Two functions in `src/efi.zig`, called from `exitBootServices`:
- **`classify`** maps each UEFI descriptor to a `MemoryKind`:
`conventional_memory → usable`; `boot_services_code`/`boot_services_data →
reclaimable` (free once we've exited); `acpi_reclaim_memory → acpi_tables`;
`acpi_memory_nvs → acpi_nvs`; **everything else → reserved** (the safe default).
Our own `loader_data` — the kernel image and these buffers — falls into
`reserved`, so it won't be handed out until the kernel deliberately reclaims it.
`conventional_memory` **and** `boot_services_code`/`boot_services_data → usable`;
`acpi_reclaim_memory → acpi_tables`; `acpi_memory_nvs → acpi_nvs`; **everything
else → reserved** (the safe default). Our own `loader_data` — the kernel image and
these buffers — falls into `reserved`.
Folding boot-services memory into `usable` is deliberate: we've already called
ExitBootServices, so it's free RAM now, and doing the classification *here* (in
the loader) means the kernel never learns about a UEFI-specific "reclaimable"
state — it just sees usable RAM. The one catch is that our stack lives in
boot-services memory and the kernel starts out running on it, so
`convertMemoryMap` keeps the single region containing the current stack pointer
`reserved`. All the boot-protocol knowledge stays on the loader side of the
boundary; the kernel's frame allocator has no idea any of this happened.
One subtlety: **a region that isn't writeback-cacheable (the descriptor's `wb`
attribute) is classified `mmio` regardless of type.** UEFI overloads
@@ -126,18 +133,17 @@ for (regions) |r| {
```
danos: physical memory
total RAM : 0.12 GiB (127 MiB) - RAM the firmware reported
usable : 77 MiB - free now; owned by the frame allocator
reclaimable: 44 MiB - UEFI boot-services memory, free after exit
reserved : 6 MiB - kernel image, ACPI, runtime services
regions : 35 - entries in the firmware memory map
usable : 121 MiB - free RAM (incl. reclaimed boot-services memory)
reserved : 6 MiB - kernel image, boot stack, ACPI, runtime services
regions : 28 - entries in the firmware memory map
```
The `usable` figure is only ~77 of ~127 MiB because most of the rest is
`reclaimable` boot-services memory — real RAM we'll take back once we implement
reclaiming, not memory that's gone. `total` counts only writeback-cacheable RAM,
so the ~12 GiB PCIe address hole is excluded (it's `mmio`), and the three RAM
categories summing back to the firmware's total is the sanity check that nothing
was dropped.
`usable` is ~121 of ~127 MiB because the loader already folded the boot-services
memory into it — so the frame allocator gets it all with no special step. The ~6 MiB
`reserved` is the kernel image, the boot stack's region, ACPI, and runtime services.
`total` counts only writeback-cacheable RAM, so the ~12 GiB PCIe address hole is
excluded (it's `mmio`), and the RAM categories summing back to the firmware's total
is the sanity check that nothing was dropped.
## How Raspberry Pi will fit
@@ -150,11 +156,13 @@ never knows the difference.
## What's next
This page is plumbing plus classification only. The map's first consumer, the
**physical frame allocator**, is built directly on the `usable` regions here —
see [frame-allocator.md](frame-allocator.md). Still to come after that:
**physical frame allocator**, is built directly on the `usable` regions here — which
already include the reclaimed boot-services memory the loader folded in (see
[frame-allocator.md](frame-allocator.md)). Still to come:
- Reclaiming `reclaimable` regions, and carefully freeing `reserved` `loader_data`
(kernel image, these buffers) once the kernel is done reading them.
- Paging / the kernel's own page tables, then a heap.
- Freeing the `reserved` `loader_data` (these boot-time buffers) once the kernel is
done reading the map.
- Capturing the ACPI RSDP from the UEFI configuration table before exit (the same
"grab it before ExitBootServices" pattern), for when ACPI parsing arrives.
See the roadmap in [efi.md](efi.md) for where this sits in the boot flow.