Hawker Chen, Development Manager
Tim Lewis, Chief BIOS Architect
Version: SecureCore Tiano (Release 1.4.0)
Legacy option ROMs have been around since the earliest days of the PC-AT architecture, allowing a add-in card to add functionality to which the system BIOS could not provide. Later, with the advent of the BIOS Boot Specification, add-in cards could provide seamless integration of boot devices for the system.
In addition to this, prior to UEFI, the option ROM was the only way of providing plug-in modules in a BIOS independent manner. The option ROM was built into the system BIOS firmware and then the BIOS would discover the option ROM and call its entry point. Hardware and software vendors began packaging their plug-ins for the system BIOS in this format, even if there was no hardware device associated with it.
This article describes a way to:
1. Integrate a legacy Option ROM into Phoenix’s Tiano-based products (SecureCore-Tiano and AwardCore-Tiano)
2. Find the option ROM from inside of a platform driver during the boo process, and
3. Shadow and call the option ROM’s entry point.
STEP 1: How to Integrate the Option Rom Image into the BIOS Image
This task creates one integrates a binary option ROM file into the BIOS image. Here are the steps:
1. Create an INF file which includes the option ROM image. For example:
BASE_NAME = OemOpRom // Name of component
FILE_GUID = 8FC3D37F-9AF1-4088-8372-A72EE51EAC18 // GUID of binary file.
COMPONENT_TYPE = BINARY // Format = binary
[sources.common]
OemOpRom.bin // File name of the Option Rom image
[nmake.common]
[includes.common]
$(EDK_SOURCE)\Foundation\Efi
2. Add this INF file to the DSC file in the build tip.’
[components]
$(PLATFORM_PATH)\...\OptionRom\OemOpRom.inf FV=FvMain
You can specify exactly which firmware volume the option ROM will be placed in using the FV statement on the same line.
STEP 2: How to Find the Option Rom Image
This task searches the BIOS image for the option ROM file. The option ROM file is located in one of the firmware volumes using a file name. In firmware volumes, files have a GUID for the file name. In this case, it is the GUID specified by FILE_GUID in the INF file.
Rather than making an assumption about which firmware volume the option ROM file is located in, this example searches all firmware volumes until it finds the file and then loads it.
//--+
// GetOemOpRom – Find the OEM option ROM and return the address and size
//
// Entry:
// RomImage – A pointer to the returned pointer to option ROM image.
// RomSize - A pointer to the returned integer size of the option ROM.
//
// Exit:
// EFI_SUCCESS - RomImage is valid
// EFI_NOT_FOUND - No RomImage
//
EFI_STATUS
GetOemOpRom (
OUT VOID **RomImage,
OUT UINTN *RomSize
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_FIRMWARE_VOLUME_PROTOCOL *FirmwareVolume;
UINT32 AuthenticationStatus;
VOID *LocalRomImage;
UINTN LocalRomSize;
//
// Get the list of all of the available firmware volumes
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status) || HandleCount == 0) {
return EFI_NOT_FOUND;
}
//
// Loop through all of the Firmware Volumes looking for the ROM image
//
for (Index = 0; Index < HandleCount; Index++) {
//
// Get the Firmware Volume Protocol
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeProtocolGuid,
&FirmwareVolume
);
if (EFI_ERROR (Status)) {
continue;
}
//
// Get the option ROM code from the same Firmware Volume as this driver
//
LocalRomImage = NULL;
LocalRomSize = 0;
Status = FirmwareVolume->ReadSection (
FirmwareVolume,
&mOpRomFileGuid, // The FILE_GUID of file
0,
&LocalRomImage,
&LocalRomSize,
&AuthenticationStatus
);
if (EFI_ERROR (Status)) {
continue;
}
*RomImage = LocalRomImage;
*RomSize = LocalRomSize;
gBS->FreePool (HandleBuffer);
return EFI_SUCCESS;
}
gBS->FreePool (HandleBuffer);
return EFI_NOT_FOUND;
}
STEP 3: How to Shadow the Option ROM into RAM
This task copies the option ROM image into shadow RAM and then calls the entry point of the image. The function InstallPciRom() is defined in the EFI_LEGACY_BIOS_PROTOCOL and handles most of the work. Here is the sample code for this:
EFI_LEGACY_BIOS_PROTOCOL *mLegacyBios;
VOID *OemRomImage = NULL;
UINTN OemRomSize = 0;
UINTN Flags = 0;
CHAR16 *TempStr = NULL;
VOID *RomShadowAddress = NULL;
UINT32 ShadowedRomSize = 0;
EFI_STATUS Status;
Status = GetOemOpRom(&OemRomImage, &OemRomSize);
if (!EFI_ERROR(Status)) {
Status = gBS->LocateProtocol (
&gEfiLegacyBiosProtocolGuid,
NULL,
&mLegacyBios
);
if (!EFI_ERROR(Status)) {
Status = mLegacyBios->InstallPciRom(
LegacyBios,
NULL,
&OemRomImage,
&Flags,
NULL,
NULL,
&RomShadowAddress,
&ShadowedRomSize
);
}
}
return Status;



You mention that "Hardware and software vendors began packaging their plug-ins for the system BIOS in this format, even if there was no hardware device associated with it."
I wonder how is the Expansion ROM initialization function is invoked it there's no hardware device associated with it.
Any ideas?
Posted by: David | May 13, 2009 at 01:19 AM