Working with Protocols
Any EFI code can operate with protocols during boot time. However, after ExitBootServices() is called, the handle database is no longer available. Several EFI boot time services work with EFI protocols.
Multiple Protocol Instances
A handle may have many protocols attached to it. However, it may have only one protocol of each type. In other words, a handle may not have more than one instance of the exact same protocol. Otherwise, it would make requests for a particular protocol on a handle nondeterministic.
However, drivers may create multiple instances of a particular protocol and attach each instance to a different handle. The PCI I/O Protocol fits this scenario, where the PCI bus driver installs a PCI I/O Protocol instance for each PCI device. Each instance of the PCI I/O Protocol is configured with data values that are unique to that PCI device, including the location and size of the EFI Option ROM (OpROM) image.
Also, each driver can install customized versions of the same protocol as long as they do not use the same handle. For example, each EFI driver installs the Component Name Protocol on its driver image handle, yet when the EFI_COMPONENT_NAME_PROTOCOL.GetDriverName() function is called, each handle returns the unique name of the driver that owns that image handle. The EFI_COMPONENT_NAME_PROTOCOL.GetDriverName() function on the USB bus driver handle returns "USB bus driver" for the English language, but on the PXE driver handle it returns "PXE base code driver."
A protocol may be nothing more than a GUID. In such cases, the GUID is called a tag GUID. Such protocols can serve useful purposes such as marking a device handle as special in some way or allowing other EFI images to easily find the device handle by querying the system for the device handles with that protocol GUID attached. The EDK uses the HOT_PLUG_DEVICE_GUID in this way to mark device handles that represent devices from a hot-plug bus such as USB.
All EFI images contain a PE/COFF header that defines the format of the executable code as required by the Microsoft Portable Executable and Common Object File Format Specification (Microsoft 1997). The target for this code can be an IA-32 processor, an Itanium processor, or a processor agnostic, generic EFI Byte Code. The header defines the processor type and the image type. Presently there are three processor types and the following three image types defined:
- EFI applications. Images that have their memory and state reclaimed upon exit.
- EFI Boot Service drivers. Images that have their memory and state preserved throughout the pre-operating system flow. Their memory is reclaimed upon invocation of ExitBootServices() by the OS loader.
- EFI Runtime drivers. Images whose memory and state persist throughout the evolution of the machine. These images coexist with and can be invoked by an EFI-aware operating system.
The value of the EFI Image format is that various parties can create binary executables that interoperate. For example, the operating system loader for Microsoft Windows and Linux for an EFI-aware OS build is simple an EFI application. In addition, third parties can create EFI drivers to abstract their particular hardware, such as a networking interface host bus adapter (HBA) or other device. EFI images are loaded and relocated into memory with the Boot Service gBS->LoadImage(). Several supported storage locations for EFI images are available, including the following:
- Expansion ROMs on a PCI card.
- System ROM or system flash.
- A media device such as a hard disk, floppy, CD-ROM, or DVD.
- A LAN boot server.
In general, EFI images are not compiled and linked at a specific address. Instead, the EFI image contains relocation fix-ups so the EFI image can be placed anywhere in system memory. The Boot Service gBS->LoadImage() does the following:
- Allocates memory for the image being loaded.
- Automatically applies the relocation fix-ups to the image.
- Creates a new image handle in the handle database, which installs an instance of the EFI_LOADED_IMAGE_PROTOCOL.
This instance of the EFI_LOADED_IMAGE_PROTOCOL contains information about the EFI image that was loaded. Because this information is published in the handle database, it is available to all EFI components.
After an EFI image is loaded with gBS->LoadImage(), it can be started with a call to gBS->StartImage(). The header for an EFI image contains the address of the entry point that is called by gBS->StartImage(). The entry point always receives the following two parameters:
- The image handle of the EFI image being started.
- A pointer to the EFI System Table.
These two items allow the EFI image to do the following:
- Access all of the EFI services that are available in the platform.
- Retrieve information about where the EFI image was loaded from and where in memory the image was placed.
The operations that the EFI image performs in its entry point vary depending on the type of EFI image. Table 1 shows the various EFI image types and the relationships between the different levels of images.