boot: separate BIOS from UEFI
boot/bios/ now holds the MBR, the El Torito stub and the real-mode stage 2; boot/uefi/ is empty and documented. Separate directories rather than #ifdefs, because the two share almost nothing. A BIOS loader lives in 16-bit real mode, reaches the firmware through software interrupts, and walks itself up into long mode. A UEFI loader is a 64-bit PE that the firmware has already placed in long mode with paging on, calling services through a table of function pointers. What they do share is the hand-off contract, which boot/README.md now writes down: ELF segments placed, long mode, a 24-byte-entry memory map at E820_MAP_ADDR, framebuffer geometry at VBE_INFO_ADDR. That contract is the point of documenting it now. UEFI's GetMemoryMap returns EFI_MEMORY_DESCRIPTORs, and the right move is to translate them into the entries kernel/arch/x86_64/e820.c already parses rather than teach the kernel a second format. Build output paths under $(BUILD)/boot are unchanged; only sources moved.
This commit is contained in:
parent
8a4ac03ea9
commit
08a1a9033a
19 changed files with 125 additions and 33 deletions
|
|
@ -142,14 +142,14 @@ no room to add so much as a print statement.
|
|||
|
||||
Split into two stages, the standard way real bootloaders solve this:
|
||||
|
||||
- **Stage 1** (`boot/bootasm.S`, still the literal MBR sector, still
|
||||
- **Stage 1** (`boot/bios/bootasm.S`, still the literal MBR sector, still
|
||||
≤510 bytes) does exactly one thing: raw IDE PIO (LBA28) reads
|
||||
`STAGE2_SECTORS` (16) sectors starting at disk sector 1 into memory at
|
||||
`0x7E00`, then jumps there. Nothing else fits, nothing else is needed.
|
||||
(Caught a real bug writing this: `outb $0x1F7,%al`-style immediates
|
||||
silently truncate to 8 bits — ports 0x1F2-0x1F7 are all > 0xFF and need
|
||||
the `%dx` register form, or you're hitting the wrong I/O port entirely.)
|
||||
- **Stage 2** (`boot/stage2.S` + `boot/stage2main.c`, loaded at `0x7E00`,
|
||||
- **Stage 2** (`boot/bios/stage2.S` + `boot/bios/stage2main.c`, loaded at `0x7E00`,
|
||||
occupies disk sectors 1-16) does everything stage 1 used to skip straight
|
||||
to, plus a boot banner (BIOS teletype, real mode, before the VBE mode
|
||||
switch — note this only reaches the video device, not serial, so it
|
||||
|
|
@ -287,7 +287,7 @@ across a long `ls`-heavy session to see what's actually climbing.
|
|||
|
||||
## 6. Boot speed
|
||||
|
||||
Two cheap, real wins in `boot/stage2main.c`, no functional changes:
|
||||
Two cheap, real wins in `boot/bios/stage2main.c`, no functional changes:
|
||||
|
||||
- `progress_tick()` (called once per 512-byte disk sector) used to trigger
|
||||
a full progress-bar redraw — border plus fill, a few thousand pixel
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ blob's build location and those symbol names change; update the Makefile to
|
|||
match or the kernel fails to link.
|
||||
|
||||
**`STAGE2_SECTORS` now lives in exactly one place: the root `Makefile`.** It used
|
||||
to be written out by hand in five — `boot/bootasm.S`, `boot/stage2main.c`'s
|
||||
to be written out by hand in five — `boot/bios/bootasm.S`, `boot/bios/stage2main.c`'s
|
||||
`readseg()`, the `dd ... seek=` offset, and twice more inside `tools/posix/mkiso.sh`
|
||||
(its stage2 size assertion and `-boot-load-size`). This note used to warn you to
|
||||
keep three of them in step and did not know about the other two.
|
||||
|
|
@ -170,6 +170,6 @@ Makefile always wins.
|
|||
|
||||
Two things still fail the build rather than silently misbooting, and should stay
|
||||
that way: `tools/padstage2.pl` errors if stage2 overflows its budget instead of
|
||||
truncating it, and `boot/stage2main.c` static-asserts that stage2 cannot reach
|
||||
truncating it, and `boot/bios/stage2main.c` static-asserts that stage2 cannot reach
|
||||
the multiboot kernel-search buffer at `0x10000` — which puts the hard ceiling at
|
||||
65 sectors, since stage2 loads at `0x7E00`.
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ stops being extendable: it is 16-bit real mode, INT 10h VBE, and PIO ATA, none
|
|||
of which exist on a UEFI-only machine. The realistic shape is a *second*
|
||||
loader — an EFI application that gets the framebuffer from GOP, the memory map
|
||||
from `GetMemoryMap()`, loads the kernel off a FAT ESP, and enters at the same
|
||||
place `boot/stage2main.c` does — rather than a port of the existing one. Worth
|
||||
place `boot/bios/stage2main.c` does — rather than a port of the existing one. Worth
|
||||
noting that the splash work just done survives that transition: it is a mask, a
|
||||
palette and a layout, none of which care how the pixels were found. What does
|
||||
not survive is every assumption in `stage2main.c` about where things live in low
|
||||
|
|
@ -465,9 +465,9 @@ does not. Measured 2026-08-08: boots at 224M and above, triple faults at 192M
|
|||
and below. Nothing is actually being *used* — the requirement is entirely
|
||||
fictional.
|
||||
|
||||
**The fix is already half-built.** `boot/stage2.S` collects a full E820 memory
|
||||
**The fix is already half-built.** `boot/bios/stage2.S` collects a full E820 memory
|
||||
map in real mode and leaves it at `VBE_INFO_ADDR + 0x200` (count) and `+ 0x208`
|
||||
(24-byte entries); `boot/stage2main.c` already parses it to print detected RAM.
|
||||
(24-byte entries); `boot/bios/stage2main.c` already parses it to print detected RAM.
|
||||
**The kernel never reads it.** So: have `main()` take the top of the highest
|
||||
usable E820 region instead of the constant, clamp it to what the direct map
|
||||
covers, and keep `PHYSTOP` only as a fallback for the case where the firmware
|
||||
|
|
|
|||
Loading…
Reference in a new issue