What is Mac OS X?© Amit Singh. All Rights Reserved. Written in December 2003
Booting Mac OS X
This page contains a brief description of the Mac's firmware (analogous to the PC BIOS in many respects), the bootloader, and the typical Mac OS X boot up sequence. There are significant differences between how older (68k, "Old World" PowerMacs) and newer (everything currently, but essentially "New World" machines with Open Firmware 3.x that load ROM from a file) boot. The discussion here applies to the newer systems.
Open Firmware (IEEE-1275 Standard for Boot Firmware: Core Requirements and Practices) is a non-proprietary, platform (CPU and system) independent boot firmware. Similar to a PC's BIOS, Open Firmware is stored in ROM and is the first stored program to be executed upon power-up.
An Open Firmware implementation is based on the Forth programming language, in particular, the FCode dialect (FCode is an ANS Forth compliant dialect that supports compilation of FCode source to bytecode). Apple and Sun are two prominent computer system makers that use implementations of Open Firmware in their systems (Sun's trademark is called OpenBoot). The Open Firmware Working Group's home page is hosted at various places, including Apple and Sun.
Thus, the firmware is implemented in Forth, and stored in the ROM as FCode bytecode. Device drivers that are required during system startup are also implemented similarly. Such drivers usually exist in the expansion ROM of expansion cards that are needed before the operating system has loaded.
You can enter Open Firmware by pressing the key combination
cmd-opt-O-F just as you power on a Macintosh. The
cmd key is the one with the Apple logo, and the
opt (option) key is the same as the
alt key. You should see a welcome message and some other verbiage, and should be dropped into a prompt like the following:
You can continue booting the machine by typing
mac-boot, or shut it down by typing
Even though this Forth "shell" supports reasonable (for a BIOS) command line editing (you can use
ctrl-a to go to the beginning of a line,
ctrl-e to go to the end,
ctrl-u to erase a line, the up-arrow key for history, etc.), you would find it more convenient (particularly if you are trying to write any code in the firmware) to access a Mac's Open Firmware from another (arbitrary) computer, over the network. Here is the command sequence to do this (everything is typed at the Open Firmware prompt, unless stated otherwise):
0 > dev /packages/telnet
If your Mac's Open Firmware includes the
telnet package, you would see:
0 > dev /packages/telnet ok
If you do get an
ok, you can run a TELNET server on it:
" enet:telnet,10.0.0.1" io
This would run a TELNET server on the machine with IP address
10.0.0.1 (you can and should choose any appropriate address). Thereafter, you can connect to Open Firmware on this machine using a TELNET client - say, from a Windows machine. See The Towers of Hanoi in Open Firmware for a programming example.
1. The following command prints the device tree:
0 > dev / ls
More [<space>,<cr>,q,a] ? _
2. The following command gives you information about installed RAM:
0 > dev /memory .properties ok
reg 00000000 10000000
dimm-types DDR SDRAM
The machine in the above command (a PowerBook G4 15, although that is not relevant) has two PC2700 DDR SDRAM chips installed. The two pairs of numbers against
reg are specify the starting address and size of the chips. Thus, the first RAM chip starts at address
0x0000000 and has a size
0x10000000 (which is 256 MB). The second chip starts at
0x1000000 (256 MB) and has a size 256 MB. The total RAM is thus 512 MB.
0 > " reg" delete-property ok
0 > 0 encode-int 10000000 encode-int encode+ " reg" property ok
# nvram boot-args="maxmem=128"
3. The following command sequence shows you various information on the machine's CPU(s):
0 > dev / ok
0 > dev /cpus ok
0 > ls
0 > dev PowerPC,G4@0 ok
0 > .properties
The rest of the output contains various cache sizes, the processor's graphics capabilities (Altivec, support for certain instructions, ...), and so on. You can think of this as analogous to
/proc/cpuinfo on Linux.
4. The following command lists files in the root directory of the disk (partition) referred to by the "alias"
0 > dir hd:\
Size/ GMT File/Dir
bytes date time Name
6148 12/25/ 3 4:25:25 .DS_Store
156 9/12/ 3 20:41:59 .hidden
589824 12/25/ 3 6:45: 6 .hotfiles.btree
5. The following command expands the alias
hd, and gives you the complete path of the device in the tree (type
devalias by itself to see a list of current aliases, along with what they refer to):
0 > devalias hd /pci@f4000000/ata-6@d/disk@0 ok
6. You can load a file (kernel) using the
load command, and boot it using the
boot command. As stated earlier,
shut-down are predefined to boot the machine normally, or shut it down, respectively. You can get and set variables (options) using the
setenv commands. These variables are stored in the non-volatile memory (NVRAM) of Open Firmware. For example, if you want your email address to be used as the "OEM banner", you should do the following:
0 > setenv oem-banner email@example.com
0 > setenv oem-banner? true
To sum up, Open Firmware is a powerful tool for controlling, debugging, and exploring the computer.
When an Open Firmware equipped Macintosh (all current Apple systems at the time of this writing) is powered on, hardware is diagnosed (by some POST code) and initialized. The first entity to control the CPU thereafter is the firmware. Open Firmware (which runs with interrupts disabled) builds a device tree, probes slots for devices, queries PCI devices and assigns them address space appropriately, and then looks for the default boot device (unless one was specified explicitly). The following "snag" keys let the user specify a boot device as the system is powered on:
C device referred to by the 'cd' alias, a CD-ROM drive
D device referred to by the 'hd' alias, a hard disk drive
N device referred to by the 'enet' alias, a network card
Z device referred to by the 'zip' alias, a ZIP drive
You can also specify the complete pathname of a device, or have the machine boot over the network using TFTP:
boot enet:<server IP>,<file>,<my IP>;<subnet>,;<gateway IP>
If Open Firmware fails to find a boot device, a blinking folder is displayed.
Open Firmware then loads a file of type
tbxi (ToolBox ROM Image, for historical reasons) from the system partition. Note that this would have been the file called "
Mac OS ROM" in the System Folder on Mac OS 9, while OS X loads
/System/Library/CoreServices/BootX, which is the bootloader as well. BootX is then executed and Control is then passed to it.
Note that Open Firmware can directly load ELF, XCOFF and "bootinfo" (any supported format with an XML header) binaries, but not Mach-O, the native executable format on Mac OS X. BootX can load Mach-O binaries.
/System/Library/CoreServices/BootX) is the default bootloader on Mac OS X.
BootX can load kernels from various filesystems: HFS+, HFS, UFS, ext2, and TFTP (network, abstracted to look like a filesystem). In addition to Mach-O, BootX can also load ELF kernels, although Mac OS X does not use this feature. To reiterate, BootX can load ELF kernels from an ext2 partition!
The sequence of events when BootX starts executing (after being handed control by Open Firmware) is described below:
- BootX first initializes the Open Firmware client interface (that it would use to talk to the firmware), and retrieves the firmware version.
It then creates a pseudo-device called
sl_words('sl' implies secondary loader) in the firmware, and defines various FORTH words in it (it is here that code for the spinning cursor is set up).
BootX looks up the
optionsdevice in the firmware, which contains various variables (that you can see and set using the
setenvcommands in Open Firmware).
0 > dev /options .properties
BootX looks up the
chosendevice, which contains handles for entities such as the boot input/output devices, memory, the MMU, the PMU, the CPU, the PIC, etc. For example, the following command at the Open Firmware prompt shows you the contents of
0 > dev /chosen ok
0 > .properties
BootX initializes handles to the MMU and memory using
- BootX initializes handles to the boot display and the keyboard (if present).
- BootX checks if the "security mode" is "none", or
BootX checks if the "verbose" (
cmd-v) or "single user" (
cmd-s) flags were specified, and sets the "output level" accordingly.
- BootX checks if the system is booting in "Safe Mode".
- BootX claims memory for various purposes.
- BootX finds all displays and sets them up. It does this by searching for nodes of type "display" in the device tree. The primary display is referred to by the
screenalias. For example, you can try this at the Open Firmware prompt:
0 > dev screen ok
0 > .properties
- While opening the display(s), BootX also sets the screen color to the familiar whitish gray.
- BootX looks up the boot device, boot arguments, etc., and determines where to get the kernel from (via a network device, from a block device, etc.), whence the path to the kernel file (
mach_kernel) is constructed. If booting from a block device (which is the usual case), the path to the kext cache (see
kextcache(8)) is calculated, along with the extensions directory (usually
- At this point, BootX draws the Apple logo splash screen, and starts the spinning cursor. If booting from a network device, a spinning globe is drawn instead.
- Depending on various conditions, BootX tries to retrieve and load the kernel cache file.
- The next step is to "decode" the kernel. If the kernel header indicates a compressed kernel, BootX tries to decompress it (typical LZSS compression is used, as you compress this kind of data once but expand it many times). Since the kernel binary can potentially be a "fat" binary (code for multiple architectures residing in the same binary), BootX checks if it indeed is (fat), and if so, "thins" it (figures out the PowerPC code).
- BootX attempts to decode the file (possibly "thinned") as a Mach-O binary. If this fails, BootX also tries to decode it as ELF.
- If the above fails, BootX gives up, draws the failed boot picture, and goes into an infinite loop.
- If BootX is successful so far, it saves filesystem cache hits, misses and evicts, sets up various boot arguments and values (such as whether this is a graphical or verbose boot, whether there are some flags to be passed to the kernel, the size of installed RAM), and also calls a recursive function to flatten the device tree.
- Finally, BootX "calls" the kernel, immediately before which it "quiesces" Open Firmware, an operation as a result of which any asynchronous tasks in the firmware, timers, or DMA get stopped, etc.
Mac OS X user level startup is neither pure BSD style, nor SYSV style, although the presence of
/etc/rc indicates a BSD heritage. In fact, various things are unsurprisingly similar to NEXTSTEP.
Mac OS X uses a boot-time optimization (effectively a smart readahead) called "BootCache" that monitors the pattern of incoming read requests to a block device (the boot disk), and sorts the pattern into a "playlist" (it also measures the cache hit rate and stores the request pattern into a "history list" for being adaptive in future).
The loadable (sorted) read pattern is stored in
/var/db/BootCache.playlist. Once this is loaded, the cache comes into effect.
Note that this feature requires at least 128 MB of physical RAM before it is enabled (automatically).