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.

The firmware is not part of Mac OS X, but it plays an important role in the operation of the machine, and is useful in debugging. Hence, we discuss it here.

Open Firmware

Background

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.

Interaction

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:

ok 0 >

You can continue booting the machine by typing mac-boot, or shut it down by typing shut-down.

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

Note that upon success, Open Firmware prints the string "ok" on the same line as you press <return>. In the examples on this page, if you see ok, remember that it is printed by Open Firmware and you are not supposed to type it in (it's not a valid Open Firmware word anyway).

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.

Note that current (at least G4 and above) Apple computers come with Ethernet ports that are auto-sensing and self-configuring, so you do not need a cross-over cable to connect it directly to another computer (no hub is required, etc.).

Examples

1. The following command prints the device tree:

0 > dev / ls ff880d90: /cpus ff881068: /PowerPC,750@0 ff881488: /l2-cache ff882148: /chosen ff882388: /memory@0 ff882650: /openprom ff882828: /client-services ... More [<space>,<cr>,q,a] ? _

2. The following command gives you information about installed RAM:

0 > dev /memory .properties ok name memory device_type memory reg 00000000 10000000 10000000 10000000 slot-names 00000003 SODIMM0/J25LOWER SODIMM1/J25UPPER ... dimm-types DDR SDRAM DDR SDRAM dimm-speeds PC2700U-25330 PC2700U-25330 ...

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.

If you need to reduce the installed RAM size (as seen by Mac OS X) for any reason, without actually having to remove a RAM stick (or you want to simulate an arbitrary size that's less than the total installed RAM), you can actually delete the reg entry using the delete-property command, and specify your own reg. Referring to the previous example of the 512 MB PowerBook, the following command essentially disables the second RAM stick (note that this change is not written to NVRAM - it is transient - once you reboot, the other chip will be detected and used as before):

0 > " reg" delete-property ok 0 > 0 encode-int 10000000 encode-int encode+ " reg" property ok

It must be kept in mind though that the reg properties can change from machine to machine, or more likely with architectural changes (for example, the format changed with the PowerMac G5). A less adventurous and more appropriate way to limit visible RAM is to use the maxmem boot argument, such as at the shell prompt:

# 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 ff886d58: /PowerPC,G4@0 ff8871f8: /l2-cache ok 0 > dev PowerPC,G4@0 ok 0 > .properties name cpu reg 00000000 cpu-version 80020101 state running clock-frequency 4a817c7b bus-frequency 09ef21aa ...

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" hd

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, mac-boot and shut-down are predefined to boot the machine normally, or shut it down, respectively. You can get and set variables (options) using the printenv and 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 you@your.email.address 0 > setenv oem-banner? true

You do not actually need to drop into Open Firmware to set the NVRAM variables. You can access (get and set) these from within Mac OS X via the nvram command line utility.

To sum up, Open Firmware is a powerful tool for controlling, debugging, and exploring the computer.

Operation

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

It is worth noting that pressing T while your Mac powers on would boot it into what's called the FireWire Target Disk Mode. Essentially, your Mac becomes a fancy external FireWire disk 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.

Bootloader

BootX (/System/Library/CoreServices/BootX) is the default bootloader on Mac OS X.

BootX is also the name of an open source bootloader (different from Apple's BootX) that allows dual-booting Mac OS and Linux on "Old World" machines.

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 "Old World" Macs had various issues with the implementation of Open Firmware, which in turn caused many booting problems for Apple engineers, and even more problems for the PowerPC Linux port. Now, Apple had access to the firmware's source. They solved most of the problems either via NVRAM patches, or by integrating required changes into BootX itself (in the instances where the changes could not be implemented as patches). As BootX matured, Apple added support for ext2 and ELF with the goal of making the platform more amenable to PowerPC Linux.

The sequence of events when BootX starts executing (after being handed control by Open Firmware) is described below:

0 > dev /options .properties name options little-endian? false real-mode? false auto-boot? true diag-switch? false ... boot-command mac-boot ...

0 > dev /chosen ok 0 > .properties name chosen stdin ffbc6e40 stdout ffbc6600 memory ffbdd600 mmu ... ...

0 > dev screen ok 0 > .properties name ATY,Bee_A compatible ATY,Bee width 00000400 height 00000300 linebytes 00000400 depth 00000008 display-type 4c434400 device_type display character-set ISO859-1 ...

Mac OS X uses a few kinds of "kext" (kernel extension) caches to speed up loading of kexts. Kernel caches are kept in the directory /System/Library/Caches/com.apple.kernelcaches. The cache files are named kernelcache.XXXXXXXX, where the suffix is a 32-bit adler checksum (the same algorithm as used by Gzip).

System Startup

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.

The next section, XNU: The Kernel, describes some of the things the kernel does as it comes up. Mac OS X System Startup continues with a description of (mostly) user-level startup.

BootCache

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).

/System/Library/Extensions/BootCache.kext is the location of the kernel extension implementing the cache while Contents/Resources/BootCacheControl within that directory is the user-level control utility (it lets you load the playlist, among other things). The effectiveness of BootCache can be gauged from the following: in a recent update to "Panther", a reference to BootCacheControl was broken. BootCache is started (via the control utility) in /etc/rc, and a prefetch tag is inserted (unless the system is booting in safe mode). /etc/rc looks for BootCacheControl in the "kext" directory, as well as in /usr/sbin, and finds it in the former (it doesn't exist in the latter). However, another program (possibly loginwindow.app) accesses /usr/sbin/BootCacheControl directly, and does not find it. For what it's worth, making BootCacheControl available in /usr/sbin, say via a symlink, reduces the boot time (measured from clicking on the "Restart" confirmation button to the point where absolutely everything has shown up on the system menu) from 135 seconds to 60 seconds on one of my machines!

<<< Architecture of Mac OS X main XNU: The Kernel >>>