The FreeBSD Boot Process r0.2 ---------------------------------------------------------------------- Michael Smith Overview "Bootstrapping" refers to the process which takes the system from an initial state and makes it ready for use. The name is derived from the expression "to lift oneself by ones' own bootstraps", which refers to the fact that the boot software has to do everything by itself. This document describes the process of bootstrapping FreeBSD 3.1 on the i386 platform. There are similarities but also significant differences between this process and that used in earlier releases. Future releases will expand on this process to add extra functionality. Discussion here is limited to booting from local disk, as there is no supported diskless boot mechanism for the 3.1 release. BIOS When booting from a floppy or fixed disk, the boot process begins with the system BIOS reading the first sector from the boot disk. This sector is loaded into low memory at 0x7c00, and the BIOS then passes execution to the code that is presumed to live there. The CDROM boot process is similar, but slightly more complex. The BIOS uses a region placed at the beginning of the CDROM by the disk's manufacturer to emulate a read-only floppy or hard disk drive. Apart from this emulation, the boot process is otherwise identical. Boot0 and the MBR Hard disks may be "sliced" or "unsliced". Unsliced disks don't have a boot0 stage, nor a real MBR. Sliced disks, however, are compatible with other operating systems (eg. Linux, Windows, etc.), and they thus must contain a compatible Master Boot Record. The Master Boot Record contains the slice table, which can be used to divide the disk into separate regions for use by different operating systems. FreeBSD normally only requires one slice. Note: Other operating systems call slices "partitions". FreeBSD uses this term to refer to the regions contained within a slice. Traditionally, the code in the MBR immediately reads the first sector of the slice marked 'active' into memory, and passes control to it in the same fashion that the BIOS did. For systems with more than one operating system installed, it is convenient to be able to select a slice to boot from without having to change the 'active' marking. This is accomplished using a tool known as a "boot manager". In the past, FreeBSD used the BootEasy boot manager. FreeBSD 3.1 now uses a replacement for BootEasy known simply as boot0. Boot0 presents a short menu listing the slice types on the current disk, and waits for the user to select one. After a timeout, it will automatically proceed to load from the default (usually the slice selected last time). If there are other disks in the system, it will list those on the menu as well. Boot1/2 At the base of every FreeBSD slice, and every unsliced disk, is an 8k region set aside for bootstrap code. If the disk/slice is being booted, the first sector (512 bytes) of this block will be read and executed. This region is known as boot1, and its purpose is to locate and read the remaining 7.5k, known as boot2. Together, boot1 and boot2 contain the core functionality required to read FreeBSD filesystems, and interact with the system console. Their normal task is to locate the next stage of the boot process, the loader, from within the 'a' partition of the disk or FreeBSD slice that has been booted. In addition, boot1/2 are capable of booting both a.out and ELF kernels directly, as well as a non-default loader, in order to effect emergency repairs. Boot1/2 are documented in the boot(8) manpage. The Loader As its name suggests, the goal of the loader is to load the FreeBSD kernel and related components. By default it will pause for 10 seconds, load the file /kernel as a FreeBSD kernel and start it. There are, however, many additional features provided by the loader. Some are designed to work around difficulties presented by the PC environment, while others add functionality to the boot process which enables the administrator to customise their environment. Advanced use of the loader To allow for customised boot behaviour, the loader contains a command interpreter and commandline interface. At startup, commands are read from /boot/loader.rc. By default, once the processing of loader.rc is completed, the automatic boot process resumes. This can be overridden as described below under the 'autoboot_delay' variable. The command interpreter understands the following commands: autoboot [ []] Displays or a default prompt, and counts down seconds before attempting to boot. If is not specified, the default value is 10. boot [- ...] [] Start the loaded kernel. If arguments are specified, they are added to the arguments for the kernel. If is specified, and a kernel has not already been loaded, it will be booted instead of the default kernel. echo [-n] [] Emits , with no trailing newline if -n is specified. This is most useful in conjunction with scripts and the '@' line prefix. Variables are substituted by prefixing them with $, eg. echo Current device is $currdev will print the current device. help [topic [subtopic]] ? The help command displays help on commands and their usage. In command help, a term enclosed with <...> indicates a value as described by the term. A term enclosed with [...] is optional, and may not be required by all forms of the command. Some commands may not be availalble. Use the '?' command to list most available commands. include The entire contents of are read into memory before executing commands, so it is safe to source a file from removable media. load [-t ] Loads the module contained in into memory. If no other modules are loaded, must be a kernel or the command will fail. If -t is specified, the module is loaded as raw data of , for later use by the kernel or other modules. may be any string. Common types include: userconfig_script The file contains commands for the kernel's UserConfig interface, eg. to assign PnP resources. ls [-l] [] Displays a listing of files in the directory , or the root directory of the current device if is not specified. The -l argument displays file sizes as well; the process of obtaining file sizes on some media may be very slow. lsdev [-v] List all of the devices from which it may be possible to load modules. If -v is specified, print more details. lsmod [-v] List loaded modules. If [-v] is specified, print more details. pnpscan [-v] Scan for Plug-and-Play devices. This command is normally automatically run as part of the boot process, in order to dynamically load modules required for system operation. (Note: automatic loading of modules is not implemented as of this writing.) If the -v argument is specified, details on the devices found will be printed. read [-t ] [-p ] [] The read command reads a line of input from the terminal. If the -t argument is specified, it will return nothing if no input has been received after seconds. (Any keypress will cancel the timeout). If -p is specified, is printed before reading input. No newline is emitted after the prompt. If a variable name is supplied, the variable is set to the value read, less any terminating newline. reboot Causes the system to immediately reboot. set set = The set command is used to set variables. show [] Displays the value of , or all variables if not specified. Multiple paths can be separated with a semicolon. unload This command removes any kernel and all loaded modules from memory. unset If allowed, the named variable's value is discarded and the variable is removed. Variables The loader provides support for variables in a fashion similar to environment variables. They may be set and displayed with the 'set' and 'show' commands, as well as substituted in other commands by prefixing the variable name with $. Integer variables have a numeric value, string variables may contain any character string, while boolean variables are true if set and false if unset. autoboot_delay (integer) Sets the default delay for the autoboot command to its value in seconds. If set to 0 in while loader.rc is being processed, the implicit autoboot at the completion of loader.rc will be disabled. boot_askname (boolean) If set, instructs the kernel to prompt the user for the name of the root device when the kernel is booted. (Requires support in the kernel.) boot_ddb (boolean) If set, instructs the kernel to start in the DDB debugger, rather than proceeding to initialise when booted. boot_gdb (boolean) If set, selects gdb-remote mode for the kernel debugger by default. boot_single (boolean) If set, prevents the kernel from initiating a multi-user startup, single-user mode will be entered when the kernel has finished device probes. boot_userconfig (boolean) Requests that the kernel's interactive device configuration program be run when the kernel is booted. boot_verbose (boolean) Setting this variable causes extra debugging information to be printed by the kernel during the boot phase. bootfile (string) The default search path for bootable kernels is /kernel;/kernel.old. It may be overridden by setting this variable to a semicolon-separated list of paths, which will be searched for in turn. console (string) Sets the current console. If a value is omitted, a list of valid consoles will be displayed. Typically the 'vidconsole' (primary video card) and 'comconsole' (first serial port) consoles will be available. currdev (string) Selects the default device. Syntax for devices is odd. module_path (string) Sets the list of directories which will be searched in for modules named in a load command or implicitly required by a dependancy. prompt (string) The command prompt is displayed when the loader is waiting for input. Variable substitution is performed on the prompt when it is displayed. The default prompt can be set with: set prompt=\$currdev> root_disk_unit (integer) If the code which detects the disk unit number for the root disk is confused, eg. by a mix of SCSI and IDE disks, or IDE disks with gaps in the sequence (eg. no primary slave), the unit number can be forced by setting this variable. Common values would be 0 (for the first SCSI disk in a system with one or more IDE disks) or 2 (for a system with FreeBSD on the secondary master IDE disk and no primary slave disk). Parser Commands are parsed when they are read from a file or the commandline. The parsing process performs a number of straightforward substitutions which make writing scripts easier. - Variable substitution is available; use ${name} to have the value of the variable 'name' inserted. - Items containing spaces may be quoted, eg. set variable="some text" - A comprehensive set of escapes are available: \\ backslash \" quote \$ dollar symbol \b backspace \f formfeed \r carriage return \n newline \s space \v vertical tab \z ignored \OOO octal character value \x00 hexadecical character value BootForth The loader also contains a Forth interpreter, derived from the popular Ficl implementation. Programming in Forth is beyond the scope of this document, however Ficl implements a nearly complete ANS forth, with access to full loader functionality. Work on BootForth is ongoing; expect a BootForth tutorial in the future. Kernel Once the kernel and any required modules are loaded, control is transferred to the kernel, which proceeds to size memory, probe for devices, and mount the root filesystem in the traditional fashion. Tunable Values Various kernel tunable parameters can be overriden by specifying new values in the loader's environment. kern.ipc.nmbclusters (integer) Set the number of mbuf clusters to be allocated. The value cannot be set below the default determined when the kernel was compiled. kern.vm.kmem.size (integer) Sets the size of kernel memory (bytes). This overrides completely the value determined when the kernel was compiled. Installing/Repairing the Bootstrap Code [This section under construction]