The FreeBSD boot process

Beware the FreeBSD Handbook! As of 2026, it is woefully out of date. It does not cover native EFI bootstrap, it gives examples using fdisk instead of the new gpart from FreeBSD 7 (sic!), and it has no clue that ZFS bootstrap (also "new" in FreeBSD 7) even exists.

You've come to this page because you've asked a question similar to the following:

What is the FreeBSD boot process ?

This is the Frequently Given Answer to such questions.

Up to the point that the FreeBSD loader is loaded, the FreeBSD bootstrap process differs between systems that use EFI machine firmware and systems that use IBM PC compatible machine firmware, subdividing the latter into discs with EFI's GUID disc partitioning scheme and those with the old MBR‐style partitioning scheme. There are three major flavours of loader, for running on top of different firmwares: /boot/loader, /boot/zfsloader, and /boot/loader.efi.

From that point onwards, the process is the same: FreeBSD's loader processes a load of Forth/LUA scripts, which present a menu, parse some loader.conf files, load the kernel and its loadable modules, and start the kernel. The FreeBSD kernel loads and runs the first application‐mode process.

How FreeBSD's loader.efi is loaded on systems that use EFI machine firmwares

The EFI bootstrap process is the subject of another Frequently Given Answer which describes it in detail.

On machines with EFI machine firmwares, the firmware is required to contain a boot manager, that loads and runs an EFI executable program, which is either a standalone utility program or an operating system boot loader program. In FreeBSD's case, this EFI executable is loader.efi.

EFI executables are 32‐bit PE-format executable programs that expect to run in protected mode, using the flat memory model and without paging enabled. The firmware itself places the processor in this mode before invoking any boot programs.

FreeBSD's loader.efi does the same things as the other flavours do, but employs EFI (boot‐time) services for performing keyboard, screen, and disc I/O.

Prior to FreeBSD 13, there used to be a boot1.efi that was interposed between the EFI firmware and loader.efi. This program is no longer relevant. Its raison d'être was that at least one installer program created very tiny EFI System Partitions, too small to hold loader.efi proper. This installer was later adjusted to default to larger ESP sizes. (It was making them not even as big as a FAT-formatted high capacity 90mm floppy disc.)

How FreeBSD's loader and zfsloader are loaded on systems that use pre-EFI machine firmwares

The bootstrap process on machines with old PC/AT and PC98 firmwares is the subject of another Frequently Given Answer which describes it in detail.

/boot/loader and /boot/zfsloader employ pre-EFI machine firmware services for keyboard, screen, and disc I/O.

On machines with such pre-EFI firmwares, the firmware first loads the MBR from the first disc that it finds, and runs it. The program to do this is under 512 bytes long and is written to the actual MBR with the gpart bootstrap command and its -b option.

There are three such programs, one of which targets discs partitioned with EFI's GUID partitioning scheme, and the other two of which target discs partitioned with the old MBR‐style partitioning scheme.

Unlike on EFI systems, IBM PC compatible firmwares execute MBRs as real mode programs using 16:16 addressing. The MBR programs do not switch into protected mode, and what they load in turn is also executed as real mode programs using 16:16 addressing. It is up to the chained‐to boot loaders to switch the processor into protected mode if that is required.

Bootstrapping without EFI firmwares but with EFI's GUID partitioning scheme

When the disc has been partitioned with EFI's GUID partitioning scheme, but there is no EFI firmware, the program that is in the MBR is /boot/pmbr. This is the conventional location on the FreeBSD filesystem from which it is copied to the actual boot record by gpart bootstrap -b.

This program loads the GUID partition table, and scans it for a "freebsd-boot" partition. If one such is found, the MBR program loads and runs the entire contents of the "freebsd-boot" partition.

This whole partition is a single program, loaded into real mode conventional memory and using 16:16 addressing. It, and the partition containing it, thus have to be 545KiB or smaller. It is written to the "freebsd-boot" partition by the gpart bootstrap command and its -p option.

It is one from a set of two such programs, here named by their conventional locations on FreeBSD from which they are copied to the actual "freebsd-boot" partitions by gpart bootstrap -p:

/boot/gptboot
This program understands FreeBSD's UFS filesystem format. It loads the GUID partition table, and scans it for "freebsd-ufs" partitions. It picks one of them to boot from according to bootme and bootonce flags in the partition table entries for those partitions, and loads and runs the /boot/loader program from that volume.
/boot/gptzfsboot
This program understands FreeBSD's ZFS filesystem format. It loads the GUID partition table, and scans it for "freebsd-zfs" partitions. It discovers the storage pools in these partitions, reads the bootfs property of the pool(s), and attempts to load and run the /boot/zfsloader program from the ZFS filesystem/volume/snapshot named by that property.

Both of these programs incorporate BTX, a program to switch to protected mode when running on top of real‐mode pre-EFI firmware.

Bootstrapping without EFI firmwares and with the MBR‐style partitioning scheme

When the disc has been partitioned with the old MBR‐style partitioning scheme, and there is no EFI firmware, the program that is in the MBR is one of two, again known by the conventional location on the FreeBSD filesystem from which they are copied to the actual boot record by gpart bootstrap -b:

/boot/mbr
This program inspects the partition table for a partition marked "startable", and loads and runs that partition's VBR.
/boot/boot0
This program allows the operator to interactively choose which partition's VBR to load and to run. (A slight wrinkle is that there are several flavours of this program, such as /boot/boot0sio which uses the serial port for operator interaction instead of the screen and keyboard. For the purposes of this explanation, they can all be considered one program.)

The next stage depends from what the "startable" partition found by /boot/mbr or the partition selected by the operator with /boot/boot0 actually is. Neither program actually cares beyond trying to print a human‐readable name for the unreliable partition type in the partition table. The pre-EFI convention is that MBR programs only load a single sector as the VBR boot program. If there is more to a boot program than fits into a single sector, it is responsible for loading the rest of itself into memory.

There are three basic categories:

a FreeBSD UFS partition

A program known by the name /boot/boot lives in such UFS partitions, in their VBR and subsequent few sectors, which are spare space in the UFS filesystem format. This loads and runs the /boot/loader program from the same UFS partition.

The /boot/boot program actually comprises a /boot/boot1 program that is the primary VBR program, concatenated with a /boot/boot2 program that contains the rest of the code.

a FreeBSD ZFS partition

A program known by the name /boot/zfsboot lives in such ZFS partitions. This loads and runs the /boot/loader program from the same ZFS partition.

As with UFS partitions, the program is split into a part that is stored in the VBR and a part that is stored elsewhere, with the former responsible for loading the latter. Unlike with UFS partitions, the reserved area for the second part of the program does not immediately follow the VBR. Instead, ZFS reserves an area 1MiB after the ZFS partition start.

a BSD "disklabel", subdividing a single MBR-format partition into several slices

The program known by the name /boot/boot lives in a "disklabel" partition, written there by the bsdlabel command and its -B option. This looks for a UFS partition in the "disklabel" slice table, and loads and runs the /boot/loader program from that slice.

Both of these programs incorporate (as part of their non-VBR portions) BTX, a program to switch to protected mode when running on top of real‐mode pre-EFI firmware and run another program (in this case the main portion of the program).

How FreeBSD is bootstrapped by its boot loader

/boot/loader, /boot/zfsloader, /boot/loader.efi are all roughly the same program. The former two run in protected mode on top of BTX, BTX providing a shim layer for accessing real‐mode firmware services; the latter runs in protected mode directly on top of EFI firmware.

In older FreeBSD they contained an embedded Forth interpreter; in newer FreeBSD it is a LUA interpreter. These interpreters load and run several scripts, from files named /boot/loader.rc and /boot/menu.rc, and indirectly from /boot/*.4th or /boot/*.lua files.

Unlike all of the files in the preceding section, which are templates whose contents are copied to their actual locations in boot records by the gpart and bsdlabel commands, these script files, and the loader program image files, are actually read from the /boot directory of the chosen boot volume. Because this boot volume can be a ZFS filesystem/volume or a UFS volume, various flavours of loader have to understand these filesystem formats in order to open and read these files. This nicety is handled by a "libstand" library that is linked into loader.

These scripts do things like print the "Beastie" logo, and the opening menu; and load and parse the /boot/loader.conf and /boot/loader.conf.local files. (The loader program does not in fact directly understand its own configuration file format. The configuration file is parsed by code written in Forth/LUA.)

The Forth version of the menu allows the operator to drop out of the scripts to an interactive session at a Forth "ok" prompt. The commands "menu" and "boot" that one can seemingly run at that prompt are in fact Forth words.

The upshot of the scripting and anything done interactively is to set up a list of "environment variables" (combined from menu choices, loader.conf files, and device.hints files), load the kernel and any loadable modules from /boot/kernel/ (or optionally another search path), and transfer control to the kernel entrypoint with a small set of additional flags. The "environment variables" list passed to the kernel by the loader becomes the list of "kernel environment variables" that can be manipulated with the kenv utility or with sysctl. The flags and environment variables pass along loader menu choices, such as the console device set‐up (vide freebsd-console(4)).

How FreeBSD runs the first application‐mode process

The FreeBSD kernel employs a fairly conventional old Unix design of a process 0 running a load of threads in purely kernel mode, and forking process 1 as the first application‐mode process.

One of the "kernel environment variables" is the init_path (kernel) environment variable, which is a colon‐separated list of executable program image files that are exec()ed one by one by process 1 after it has been forked, until one of them succeeds or the list is exhausted.

The first user process is given an argument vector that is constructed from the additional bitflags that were passed to the kernel by loader. Specifically, the first user process gets an -s option for "single‐user mode" (i.e. emergency mode) being selected by loader's menu. (The FreeBSD kernel is actually fairly impoverished when it comes to telling the first application‐mode process what to do. There are no flags for rescue mode.)


© Copyright 2026 Jonathan de Boyne Pollard. "Moral" rights asserted.
Permission is hereby granted to copy and to distribute this web page in its original, unmodified form as long as its last modification datestamp is preserved.