Boot
From power-on to kmain. Mostly about the bootloader for installed disks, since the ISO just uses GRUB.
From the ISO
The ISO is built with grub-mkrescue and a grub.cfg that does multiboot /boot/subverge.elf. GRUB loads the kernel at 1 MiB, fills in a Multiboot information block, and jumps to _start in 32-bit protected mode. That's the one piece of code in the whole system that wasn't written for Subverge, and it only ever runs on the ISO.
From an installed disk
Installed disks don't have GRUB. They have two stages of Subverge's own, written in nasm, in boot/.
The MBR
boot/mbr.asm is the 512-byte boot sector at LBA 0. The BIOS loads it at 0x7C00. It uses the int 13h extensions to read 16 sectors, LBA 1 to 16, to 0x7E00, and jumps there. If the read fails, it prints subverge: can't read stage 2 and halts.
Stage 2
boot/stage2.asm does the work GRUB would do, and starts with a header at byte 8:
| Offset | Field |
|---|---|
| 8 | SUBVERGE, the magic that marks an installed drive |
| 16 | the kernel's starting LBA |
| 20 | the kernel's length in sectors |
| 24 | the load address, 1 MiB |
| 28 | where bss ends |
| 32 | the entry point |
install fills in those fields from the running kernel when it writes stage 2 to the disk, so stage 2 itself never needs to know anything about the kernel. The kernel looks for that same SUBVERGE magic to find out which drive it's installed on.
Then stage 2:
- turns on the A20 line through port
0x92 - reads the kernel into low memory in chunks of 64 sectors with int 13h extensions, and prints
subverge: can't read the kernelif it can't - collects the memory map with E820 and the memory size
- builds a Multiboot information block, with its name as the loader name,
subverge stage2 - switches to protected mode, copies the kernel up to 1 MiB, clears bss
- jumps to the entry point with the Multiboot magic in
eaxand the info block inebx
The kernel can't tell which of the two loaders started it, so the rest of the kernel only ever has to handle one boot protocol.
_start
boot/boot.asm is the kernel's entry, and the first code the kernel runs either way. It has the Multiboot header, and then:
- sets up a 256 KiB boot stack
- builds the page tables: one PML4 entry, four PDPT entries, and 2048 page directory entries of 2 MiB each, which identity-maps the first 4 GiB
- turns on PAE in
cr4, long mode in the EFER MSR, and paging incr0 - loads a GDT with one 64-bit code segment and one data segment
- far-jumps into 64-bit code and calls
kmainwith the Multiboot magic and info pointer
See internals for what kmain does next.
Why not UEFI
Multiboot and BIOS were enough to boot in QEMU, and the whole system is built on VGA text mode, which UEFI machines often don't have. See hardware for what that means on real machines.
subverge