284 - Loading the Host Operating System | RFD | Oxide
Viewing public RFDs.Learn more
published<br>RFD 284<br>RFD 284 Loading the Host Operating System
This RFD can be accessed by the following groups:[public]
State<br>published
RFD<br>284
Authors<br>Dan Cross
Updated
Background<br>RFD 75 explores different options for booting, and we have<br>chosen a holistic approach.
RFDs 215 and 241 explain how holistic boot works for the Oxide<br>machine architecture. RFD 281 further describes the storage of<br>the host operating system in persistent media, image discovery,<br>and boot once the host OS kernel is loaded, and explains that<br>there is the practical matter of loading the host operating<br>system image into RAM and starting it running.
This document describes how the host OS image is loaded and<br>activated.
Determinations<br>The component that is responsible for loading and starting the<br>host operating system is the Pico Host Boot Loader, or phbl<br>(pronounced "foible").
phbl supports loading a compressed CPIO archive for the phase1<br>host OS image. ZLIB is currently the only supported compression<br>algorithm.
phbl Implementation<br>phbl is a simple program: it is loaded from SPI flash by the<br>PSP after DRAM training and is invoked from the reset vector of<br>the BSC (BootStrap Core, [amd64]). It does the bare minimum<br>required to bring the processor up into 64-bit mode, load the<br>illumos kernel, and call the kernel’s ELF entry point;<br>presumably a one-way journey. In many ways, it behaves like<br>single-threaded microcontroller code in this regard.
phbl passes a small amount of data to the kernel: the kernel<br>entry is called with the physical address of the CPIO archive<br>and the archive’s length as arguments. Further, it observes an<br>extremely simple protocol for transferring ownership of the<br>page tables that map the kernel image, and obeys a strict<br>convention for the granularity of mappings that the kernel may<br>rely on.
The major steps in system initialization that phbl completes<br>include:
Initializing the processor. Advancing the BSC through 16-bit<br>real mode, 32-bit protected mode, and into 64-bit long mode<br>with paging enabled
Mapping and initializing the console UART (purely for its own<br>output, for instance if an exception is encountered in early<br>boot).
Locating, reading, and decompressing the phase1 CPIO archive<br>containing the host kernel image, relevant kernel modules, and<br>other data. See RFD 281 for reference on the contents of the<br>archive.
Extracting the executable ELF image containing the host kernel<br>from the archive read in (3), and loading it into RAM by<br>copying the loadable segments from the binary image into<br>physical memory and mapping them at their linked addresses
Starting the host kernel by calling its ELF entry point
Virtual Memory Guarantees<br>phbl supports creating 1GiB, 2MiB and 4KiB virtual memory<br>mappings, and guarantees that a region of virtual memory will be<br>mapped with the largest pages possible, given alignment and size<br>constraints. So for instance, a 4GiB region aligned on a 1GiB<br>boundary will be mapped with 4 1GiB pages, while a 4GiB region<br>aligned to a 512MiB boundary will be mapped with 256 2MiB pages,<br>then 3 1GiB pages, and then another 256 2MiB pages.
The UART’s registers will be mapped uncached and write-through,<br>while mappings to known RAM regions will be mapped cached and<br>with the "writeback" memory type: that is, the PTE for the UART<br>will have both the PCD and PWT bits set, while these will be<br>cleared for mappings that point to RAM.
When mapping ELF segments for both the loader and host operating<br>system, protection bits for each segment will be respected: if a<br>segment is read-only, the 'R/W' bit in a corresponding PTE will<br>be clear. Similarly, non-executable segments will have the NX<br>bit set.
Modifications to System State<br>An explicit goal of phbl is to minimize changes to system<br>state post-reset, leaving the host in as close to a pristine<br>state as we can when the operating system takes over. Recalling<br>that phbl runs only on the BSC, specific changes are limited:
The interrupt-enable and direction indicator bits are cleared<br>in the %FLAGS register, disabling interrupts and forcing<br>repeated operations into ascending order. Note this is<br>architecturally guaranteed on reset, but is so critical we<br>repeat the operations explicitly from the reset vector.
Caching is enabled<br>The CD and NW bits in %cr0 are cleared
The default MTRR type is set to writeback
Protected mode (and then long mode) are enabled<br>A GDT is created with the following segments:<br>A NULL segment (required)
A 64-bit code segment (required for long mode)
A 32-bit code segment (required for 32-bit mode)
A 32-bit data segment (required for 32-bit mode)
The BSC’s GDTR is loaded with a reference to this GDT
The PE bit is set in %cr0 to enable protected mode
The segmentation registers are modified to reflect the<br>state of the processor as it transitions from 16-bit real<br>mode to 32-bit protected and then 64-bit long mode: data<br>and stack segments refer to a...