With the Mac’s basic services running, boot.efi located and (where necessary) approved, the Mac then loads it and enters the EFI phase proper.
The purpose of the EFI phase and boot.efi is to augment the basic facilities provided by BootROM to the point where the macOS kernel can be loaded with its extensions, largely in terms of providing access to the Mac’s hardware through a device tree. When computers were much simpler, all that was needed was basic input and output, in the BIOS.
The model-specific boot.efi software (“OS X booter”) provides ongoing and additional support for boot services, including memory management, basic functions for timers and events, and for hardware access. It supports basic console protocols for input and output, and access to storage systems. Runtime services extend these to give access to variables stored in the NVRAM, and to GUIDs/UUIDs which are used for key variables in the EFI phase and later.
You can view the boot variables which are stored in NVRAM using the
nvram -x -p
command in Terminal. These vary by model and EFI firmware version, but common to most, if not all, are
- previous-system-uuid,
- efi-apple-recovery,
- efi-boot-device.
Within the boot GUID are some key EFI variables, including names of the kernel, kernel cache, and KEXT cache used in the boot process. These can be examined further by exploring the I/O Registry, for example using the tool ioreg
.
One of the key tasks of boot.efi is to built the device tree, IODeviceTree, which lists and relates all the devices in that Mac. This is passed to the kernel when it loads, and forms the basis for IOKit within macOS. This phase also looks for any saved hibernation state: if the Mac is to be restored to that state, Hibernation Resume will be initiated and will then override the rest of the boot process.
boot.efi also looks for startup key commands (which Apple has termed “snag keys”), such as Command-R to run in Recovery mode, Command-S and -V for Single User and Verbose modes, and Shift for Safe mode. By this stage, some models should have basic Bluetooth support, and may be able to detect startup keys from wireless keyboards. However, this is not generally reliable, and it is better to hold keys on a keyboard which is connected to one of the Mac’s USB ports, USB support being much more reliable at this stage.
The main property list containing parameters for boot.efi is still officially /Library/Preferences/SystemConfiguration/com.apple.Boot.plist, and this is even supported with its own man
page. However, more recent versions of macOS have used this file less and less, and on many Macs it is now almost empty. It is worth knowing that here, in the NVRAM variables, and anywhere else that is accessed by EFI components, path names use backslashes \ in place of normal slashes /, as that is the convention within EFI.
boot.efi has various other tasks to complete before it is ready to load the kernel itself. These include gathering together all the parameters which the kernel needs, such as any boot arguments, and passing the IODeviceTree.
Between the settings in the NVRAM and com.apple.Boot.plist, overridden by any startup keys being held, boot.efi knows where to locate the kernel to be loaded and run, and that is the next step in the boot process.
When Apple introduced Boot Camp, it made changes to boot.efi which supported booting from operating systems other than macOS. This essentially provides a suite of drivers which support Mac hardware in terms of a Windows hardware platform, which are engaged when the Mac is to be booted up in that operating system rather than macOS.
References
Apple’s Kernel Programming Guide, covers macOS up to about 10.7.
Apple’s IOKit Fundamentals, which should be supplemented with the more recent coverage in the IOKit framework documentation.