Introduction to Open Firmware
Introduction
The IEEE standard 1275-1994 entitled Standard for Boot (Initialization, Configuration) Firmware Core Requirements and Practices addresses two areas of concern regarding the boot process:
The very first section in this chapter described the basic rationale for including a device ROM in the design of a device—it provides a device driver that allows the OS boot program to use the device during the OS boot process. That raises the question of what language to write the device driver in. This is one of the two major areas addressed by the OpenBoot standard. It is the one that the PCI spec is concerned with. After the OS is booted into memory, the BIOS passes control to it. If it's a Plug-and-Play capable OS, it would be nice if the BIOS passed a pointer to the OS that identified a data structure defining all of the devices that the OS has at its disposal. The OS could then traverse this data structure, determine the current state of all devices, and manage them for the remainder of the power-up session. In order for this to work, the exact format of this data structure must be standardized and understood by both the BIOS that builds it and the OS that subsequently takes ownership of it. This is the other major area addressed by the OpenBoot standard.
These two areas are discussed in more detail in the two sections that follow. It should be noted that this is only intended as an introduction to this standard. There's a lot more to it than is covered here: the standard is approximately 300 pages in length, 8.5" x 11" in size. A detailed discussion of Open Firmware is outside the scope of this book.
Universal Device Driver Format
Historically, most of the PC-compatible machines marketed in the past have been based on Intel x86 processors. When writing ROM code for an add-in subsystem on a card, it was a simple decision that the device driver image to be stored in the ROM would be an x86 machine language code image.
A number of system vendors have created systems incorporating PCI and based on processors other than the x86 processor family. These machines would take a substantial performance hit when executing expansion ROM code that isn't written in the processor's native machine language (i.e., x86 code is "foreign" to PowerPC and other types of non-Intel compatible processors). They would be forced to emulate the x86 code, an inherently inefficient solution.
Rather than writing an add-in device's ROM code in machine language native to a particular processor, the subsystem designer can write the ROM code in Fcode (tokenized Forth code) based on the Open Firmware specification, IEEE 1275-1994. In other words, the device driver is written in the high-order language Forth.
The Open Firmware components would consist of the following:
The system BIOS contains the Fcode interpreter and possibly an individual Fcode device driver associated with each of the embedded subsystems that the system Open Firmware is already cognizant of. Each add-in subsystem would hopefully contain an Open Firmware Fcode image.
The Open Firmware language is based on the Forth programming language. The ROM code would be written in Forth source code. The source code is then supplied as input to a "tokenizer" program. The tokenizer processes the source code into a series of compressed commands, known as Fcode. As an example, an entire line of source code might be reduced to a single byte that represents the Forth command, only in a much more compact form.
The system BIOS that "discovered" the ROM (as described earlier in this chapter), incorporates an interpreter that converts the Fcode byte stream read from the ROM into machine language instructions specific to the system's processor.
The programmer only has to write this one universal version of the driver and any machine with an Fcode interpreter built into the system BIOS can then utilize this driver with the device during the boot process (allowing the device to be selected as the Input, Output, or IPL boot device). Obviously, executing a driver written in interpretive code would yield less than optimum performance. However, once the OS is booted into memory it then loads native code drivers for the three boot devices to replace the Fcode drivers. Performance of the devices is then optimized.
The PCI spec refers the reader to another document, PCI Bus Binding to IEEE 1275-1994, for implementation of Open Firmware in a PCI-based machine. This document is available using anonymous FTP to the machine playground.sun.com with the file name /pub/p1275/bindings/postscript/PCI.ps.
Passing Resource List To Plug-and-Play OS
BIOS Calls Bus Enumerators For Different Bus Environments
A machine architecture can contain many different device environments. Examples would be PCI, CardBus, Plug-and-Play ISA, etc. The methods that must be used to access the configuration registers associated with each of these different device types are very different from each other. In addition, the layout and format of their configuration registers are quite different as well.
The BIOS includes a separate, bus-specific program for each of these environments. This program is frequently referred to as a Bus Enumerator. The Bus Enumerator knows:
how to access the configuration registers within devices of its specific type (e.g., PCI, PCI-X, PCI Express). how to "discover" devices within its environment. For example, in a PCI, PCI-X, or PCI Express environment, the programmer reads the Vendor ID from a function's Vendor ID register. Any value other than FFFFh represents a valid ID, while FFFFh indicates that no function resides at the currently-addressed location. how to probe the device's configuration registers to discover the device's resource requirements. how to allocate selected resources to the device.
The system BIOS must call the Bus Enumerators for each of the bus environments supported in the platform. When a specific Enumerator is called, it discovers all of the devices within its target environment, discovers the resources each requires, and allocates non-conflicting resources to each. It does not, however, enable the devices. The Enumerator builds a data structure in memory that lists all devices of its type that were found. It then passes a pointer to the start of that data structure back to the system BIOS.
When the system BIOS has called each of the Bus Enumerators for the different environments, it now has a list of pointers to the various, bus-specific data structures that list all of the devices that it has to work with.
BIOS Selects Boot Devices and Finds Drivers For Them
The system BIOS would then scan the data structures to locate an Input device, an Output device, and an IPL device to use in booting the OS into memory. In order to use each of these devices during the boot process, it would also require a device driver for each of them. The drivers would either be embedded within the BIOS itself or within device ROMs discovered with each of the devices.
For each of the three boot devices, the BIOS would then:
call the initialization code within the device driver. The initialization code would then complete the preparation of the device for use. The BIOS would then set the appropriate bits in its configuration Command register (e.g., Bus Master Enable, etc.) to enable the device and bring it on-line.
BIOS Boots Plug-and-Play OS and Passes Pointer To It
The system BIOS then uses the three devices to boot the OS into memory and passes control to the OS. It also passes the OS a pointer that points to the head of the list of data structures that identify all of the devices that the OS has to work with.
OS Locates and Loads Drivers and Calls Init Code In Each
Note that Init code refers to the Initialization code portion of the driver. The OS then locates the disk-based drivers for each device and loads them into memory one-by-one. As it loads each driver, it then calls its initialization code entry point and the driver completes the device-specific setup of the device and brings the device on-line. The machine is now up and running and the OS manages the system devices from this point forward.
 |