92 lines
5.4 KiB
Markdown
92 lines
5.4 KiB
Markdown
# danos documentation
|
|
|
|
Notes on how danos boots and draws, written to explain the *why* behind the code
|
|
rather than restate it. Roughly in the order things happen at runtime:
|
|
|
|
1. **[efi.md](efi.md) — EFI / the boot process.** How UEFI firmware finds and
|
|
runs the bootloader, what the loader gathers before `ExitBootServices`, how it
|
|
loads the kernel ELF, and the ABI contract for the jump into the kernel. Start
|
|
here.
|
|
2. **[gop.md](gop.md) — the Graphics Output Protocol.** How UEFI exposes graphics
|
|
modes (unlike fixed VGA modes), how we detect the monitor's native resolution
|
|
from EDID and switch to it, and the pixel formats we accept or reject.
|
|
3. **[framebuffer.md](framebuffer.md) — the framebuffer.** What the linear
|
|
framebuffer the loader hands over actually is, and what **pitch** (stride)
|
|
means versus width — the detail you have to get right to avoid a skewed image.
|
|
4. **[memory-map.md](memory-map.md) — the memory map.** How the loader learns what
|
|
physical RAM exists and hands it to the kernel in danos's own neutral format,
|
|
rather than leaking UEFI's memory descriptors across the boundary.
|
|
5. **[frame-allocator.md](frame-allocator.md) — the physical frame allocator.** The
|
|
bitmap allocator that hands out and reclaims 4 KiB physical frames from that
|
|
map — the primitive page tables and the heap are built on.
|
|
6. **[interrupts.md](interrupts.md) — interrupts and exceptions.** The GDT, IDT and
|
|
TSS, the exception stubs, and the handler that reports a CPU fault in red instead
|
|
of letting it triple-fault into a silent reset.
|
|
7. **[paging.md](paging.md) — the kernel's page tables.** Building our own 4-level
|
|
page tables, identity-mapping the low 4 GiB, and switching CR3 off the firmware's
|
|
tables onto ours.
|
|
8. **[device-interrupts.md](device-interrupts.md) — device interrupts.** The Local
|
|
APIC and its timer — the kernel's first interrupt that is *handled and returned
|
|
from*, giving it a heartbeat.
|
|
9. **[heap.md](heap.md) — the kernel heap.** A growable free-list allocator built on
|
|
the VMM, exposed as a `std.mem.Allocator` so std containers work — dynamic
|
|
allocation for the kernel.
|
|
10. **[scheduling.md](scheduling.md) — the scheduler.** Fixed-priority preemptive
|
|
multitasking: kernel threads, the context switch, O(1) priority selection, and
|
|
blocking (sleep, wait queues) — the leap to a running system.
|
|
11. **[ipc.md](ipc.md) — inter-process communication.** Bounded blocking
|
|
message-passing channels — the backbone the microkernel's isolated servers will
|
|
talk over.
|
|
12. **[halting.md](halting.md) — halting.** Why a kernel can't just "exit", and
|
|
how `while (true) hlt` parks the CPU safely once there's nothing left to do.
|
|
|
|
Start with the north star:
|
|
|
|
- **[vision.md](vision.md) — the vision.** danos is aiming to be a real-time
|
|
microkernel: minimal kernel, drivers/services isolated in user space, preemptive
|
|
scheduling with timing guarantees. The *why* that shapes everything below.
|
|
|
|
Cutting across all of these:
|
|
|
|
- **[arch.md](arch.md) — the architecture split.** How CPU-specific code is kept
|
|
behind a build-time `arch` module so the generic kernel never names x86_64,
|
|
leaving room for other systems (e.g. an AArch64 Raspberry Pi) later.
|
|
- **[sysv.md](sysv.md) — the calling convention.** What "the kernel is SysV" means,
|
|
and why the loader→kernel boundary has to pin it (the RDI-vs-RCX handoff).
|
|
- **[testing.md](testing.md) — testing.** How the kernel is tested by booting it in
|
|
QEMU and asserting on its serial output — reproducibly, and structured so the
|
|
same tests run across architectures.
|
|
|
|
## How the pieces relate
|
|
|
|
The boot flow ties them together: UEFI runs the loader ([efi.md](efi.md)), which
|
|
queries the **GOP** to pick a graphics mode ([gop.md](gop.md)), hands the kernel a
|
|
**framebuffer** to draw into ([framebuffer.md](framebuffer.md)) and a **memory
|
|
map** of physical RAM ([memory-map.md](memory-map.md)); the kernel turns that map
|
|
into a **frame allocator** ([frame-allocator.md](frame-allocator.md)), installs
|
|
its **descriptor tables** so CPU faults are caught ([interrupts.md](interrupts.md)),
|
|
builds its own **page tables** and switches onto them ([paging.md](paging.md)),
|
|
brings up the **heap** for dynamic allocation ([heap.md](heap.md)), starts the
|
|
**scheduler** ([scheduling.md](scheduling.md)) and the **timer** that preempts it
|
|
([device-interrupts.md](device-interrupts.md)) — with tasks blocking, sleeping and
|
|
passing messages over **[IPC](ipc.md)** channels — runs, its CPU-specific bits
|
|
behind the [arch](arch.md) boundary, and when idle, or on a panic, it **halts**
|
|
([halting.md](halting.md)).
|
|
|
|
## Source map
|
|
|
|
| Area | Code |
|
|
|------|------|
|
|
| Bootloader (UEFI app) | `src/efi.zig` → `BOOTX64.efi` |
|
|
| Kernel entry, panic, bring-up | `src/main.zig` |
|
|
| Shared loader↔kernel contract (`BootInfo`, `Framebuffer`, `MemoryMap`, ABI) | `src/root.zig` |
|
|
| Physical frame allocator | `src/pmm.zig` |
|
|
| Kernel heap (`std.mem.Allocator`) | `src/heap.zig` |
|
|
| Scheduler (fixed-priority preemptive; blocking, wait queues) | `src/sched.zig` |
|
|
| IPC channels (message passing) | `src/ipc.zig` |
|
|
| Framebuffer text console (mirrors to serial) | `src/console.zig` |
|
|
| In-kernel test cases | `src/tests.zig` |
|
|
| Arch-specific kernel code (`halt`, GDT/IDT/TSS, exception + interrupt stubs, page tables, APIC/timer, serial, linker script) | `src/arch/x86_64/` |
|
|
| Build + `run-efi` (QEMU/OVMF) | `build.zig` |
|
|
| QEMU integration test harness | `test/qemu_test.py` |
|