1# Zircon kernel to userspace bootstrapping (`userboot`) 2 3Zircon has a microkernel style of design. A complexity for microkernel 4designs is how to bootstrap the initial userspace processes. Often this 5is accomplished by having the kernel implement minimal versions of 6filesystem reading and program loading just for the purpose of 7bootstrapping, even when those kernel facilities are never used after boot 8time. Zircon takes a different approach. 9 10[TOC] 11 12## Boot loader and kernel startup 13 14A boot loader loads the kernel into memory and transfers control to the 15kernel's startup code. The details of the boot loader protocols are not 16described here. The boot loaders used with Zircon load both the kernel 17image and a data blob in Zircon Boot Image format. 18The [ZBI format](../system/public/zircon/boot/image.h) is a 19simple container format that embeds items passed by the boot loader, 20including hardware-specific information, 21the [kernel "command line"](kernel_cmdline.md) giving boot options, and RAM 22disk images (which are usually compressed). The kernel extracts some 23essential information for its own use in the early stages of booting. 24 25## BOOTFS 26 27One of the items embedded in the Zircon Boot Image is an initial RAM disk 28filesystem image. The image is usually compressed using the **LZ4** 29format. Once decompressed, the image is in **BOOTFS** format. This is a 30trivial read-only filesystem format that simply lists file names, and for 31each file the offset and size within the BOOTFS image (both values must be 32page-aligned both fields and are limited to 32 bits). 33 34The primary BOOTFS image contains everything that the userspace system 35needs to run: executables, shared libraries, and data files. These include 36the implementations of device drivers and more advanced filesystems that 37make it possible to read more code and data from storage or network 38devices. 39 40After the system has bootstrapped itself, the files in the primary 41BOOTFS become the read-only filesystem tree rooted at `/boot` (and served by 42bootsvc). 43 44## Kernel loads userboot 45 46The kernel does not include any code for decompressing LZ4 format, nor 47any code for interpreting the BOOTFS format. Instead, all of this work 48is done by the first userspace process, called `userboot`. 49 50`userboot` is a normal userspace process. It can only make the standard 51system calls through the [vDSO](vdso.md) like any other process would, and 52is subject to the full [vDSO enforcement](vdso.md#Enforcement) regime. 53What's special about `userboot` is the way it gets loaded. 54 55`userboot` is built as an ELF dynamic shared object, using the 56same [RODSO layout](vdso.md#Read_Only-Dynamic-Shared-Object-Layout) as 57the vDSO. Like the vDSO, the `userboot` ELF image is embedded in the 58kernel at compile time. Its simple layout means that loading it does 59not require the kernel to interpret ELF headers at boot time. The 60kernel only needs to know three things: the size of the read-only 61segment, the size of the executable segment, and the address of the 62`userboot` entry point. At compile time, these values are extracted 63from the `userboot` ELF image and used as constants in the kernel code. 64 65Like any other process, `userboot` must start with the vDSO already 66mapped into its address space so it can make system calls. The kernel 67maps both `userboot` and the vDSO into the first user process, and then 68starts it running at the `userboot` entry point. 69 70## Kernel sends `processargs` message 71 72In normal [program loading](program_loading.md), 73a [*bootstrap message*](program_loading.md#the-processargs-protocol) is 74sent to each new process. The process's first thread receives 75a [channel](objects/channel.md) handle in a register. It can then read 76data and handles sent by its creator. 77 78The kernel uses the exact same protocol to start `userboot`. The kernel 79command line is split into words that become the environment strings in the 80bootstrap message. All the handles that `userboot` itself will need, and 81that the rest of the system will need to access kernel facilities, are 82included in this message. Following the normal format, *handle info 83entries* describe the purpose of each handle. These include 84the [`PA_VMO_VDSO` handle](vdso.md#pa_vmo_vdso-handle). 85 86## userboot finds system calls in the vDSO 87 88The [standard convention](vdso.md#process_start_argument) for informing 89a new process of its vDSO mapping requires the process to interpret the 90vDSO's ELF headers and symbol table to locate system call entry points. 91To avoid this complexity, `userboot` finds the entry points in the vDSO 92in a different way. 93 94When the kernel maps `userboot` into the first user process, it chooses 95a random location in memory, just as normal program loading does. 96However, when it maps the vDSO in it doesn't choose another random 97location as is normal. Instead, it places the vDSO image immediately 98after the `userboot` image in memory. This way, the vDSO code is always 99at fixed offsets from the `userboot` code. 100 101At compile time, the symbol table entries for all the system call entry 102points are extracted from the vDSO ELF image. These are then massaged 103into linker script symbol definitions that use each symbol's fixed 104offset into the vDSO image to define that symbol at that fixed offset 105from the linker-provided `_end` symbol. In this way, the `userboot` 106code can make direct calls to each vDSO entry point in the exact 107location it will appear in memory after the `userboot` image itself. 108 109## userboot decompresses BOOTFS 110 111The first thing `userboot` does is to read the bootstrap message sent by 112the kernel. Among the handles it gets from the kernel is one with 113*handle info entry* `PA_HND(PA_VMO_BOOTDATA, 0)`. This is 114a [VMO](objects/vm_object.md) containing the ZBI from the 115boot loader. `userboot` reads the ZBI headers from this VMO 116looking for the first item with type `ZBI_TYPE_STORAGE_BOOTFS`. That 117contains the [BOOTFS](#BOOTFS) image. The item's ZBI header 118indicates if it's compressed, which it usually is. `userboot` maps in 119this portion of the VMO. `userboot` contains LZ4 format support code, 120which it uses to decompress the item into a fresh VMO. 121 122## userboot loads the first "real" user process from BOOTFS 123 124Next, `userboot` examines the environment strings it received from the 125kernel, which represent the kernel command line. If there is a string 126`userboot=`*file* then *file* will be loaded as the first real user 127process. If no such option is present, the default *file* is `bin/bootsvc`. 128The files are found in the BOOTFS image. 129 130To load the file, `userboot` implements a full-featured ELF program loader. 131Usually the file being loaded is a dynamically-linked executable with a 132`PT_INTERP` program header. In this case, `userboot` looks for the file 133named in `PT_INTERP` and loads that instead. 134 135Then `userboot` loads the vDSO at a random address. It starts the new 136process with the standard conventions, passing it a channel handle and the 137vDSO base address. On that channel, `userboot` sends the 138standard [`processargs`](program_loading.md#the-processargs-protocol) 139messages. It passes on all the important handles it received from the 140kernel (replacing specific handles such as the process-self and thread-self 141handles with those for the new process rather than for `userboot` itself). 142 143## userboot loader service 144 145Following the standard program loading protocol, when `userboot` loads a 146program via `PT_INTERP`, it sends an additional `processargs` message 147before the main message, intended for the use of the dynamic linker. This 148message includes a `PA_LDSVC_LOADER` handle for a channel on which `userboot` 149provides a minimal implementation of the 150standard [loader service](program_loading.md#the-loader-service). 151 152`userboot` has only a single thread, which remains in a loop handling 153loader service requests until the channel is closed. When it receives a 154`LOADER_SVC_OP_LOAD_OBJECT` request, it looks up the object name prefixed 155by `lib/` as a file in BOOTFS and returns a VMO of its contents. Thus, the 156first "real" user process can be (and usually is) a dynamically linked 157executable needing various shared libraries. The dynamic linker, the 158executable, and the shared libraries are all loaded from the same BOOTFS 159pages that will later appear as files in `/boot`. 160 161An executable that will be loaded by `userboot` (i.e. [`bootsvc`](bootsvc.md)) should 162normally close its loader service channel once it's completed startup. 163That lets `userboot` know that it's no longer needed. 164 165## userboot rides off into the sunset 166 167When the loader service channel is closed (or if the executable had no 168`PT_INTERP` and so no loader service was required, then as soon as the 169process has been started), `userboot` no longer has anything to do. 170 171If [the `userboot.shutdown` option was given on the kernel command line](kernel_cmdline.md#userboot_shutdown), 172then `userboot` waits for the process it started to exit, and then shuts 173down the system (as if by the `dm shutdown` command). This can be useful 174to run a single test program and then shut down the machine (or emulator). 175For example, the command line `userboot=bin/core-tests userboot.shutdown` 176runs the Zircon core tests and then shuts down. 177 178Otherwise, `userboot` does not wait for the process to exit. `userboot` 179exits immediately, leaving the first "real" user process in charge of 180bringing up and taking down the rest of the system. 181