虽然UEFI 出来十几年了,但是legacy 的阴影一直笼罩着我们。今天我们来看看Legacy里面的一个老朋友OpRom。以前很多PCI 设备上面都外挂一颗Rom,用来实现一些特定的功能,比如网络启动,硬盘保护,远程管理等等。后面比较常见的就只有网卡和显卡这两种设备还在用OpRom,独立的板卡有自己的板载Rom IC,板载的为了节约成本,就把OpRom包到BIOS里面。此外,OpRom也可以独立存在并执行。
我们今天打算介绍一下下面几个主题:
- 在BIOS里面包一个OpRom。
- 在启动过程中找到这个OpRom。
- 在内存里面查看这个OpRom的内容。
如何在BIOS里面包一个OpRom?如下,在OvmfPkgX64.fdf里面[FV.DXEFV]段加入下面的代码即可。
FILE FREEFORM = 1845d593-26a0-4805-a014-2e294fef14ee {
SECTION RAW = OvmfPkg/LegacyRom/rtegrom.lom
SECTION UI = "RealtekPXE"
}
如何找到这个OpRom?如下,遍历firmware volumes根据GUID找到这个OpRom的位置。
STATIC
EFI_STATUS
EFIAPI
CHHGetOpRom (
OUT VOID **RomImage,
OUT UINTN *RomSize
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume;
UINT32 AuthenticationStatus;
VOID *LocalRomImage;
UINTN LocalRomSize;
EFI_GUID gRealtekPXEOpRomGUID = { 0x1845d593, 0x26a0, 0x4805, { 0xA0, 0x14, 0x2E, 0x29, 0x4F, 0xEF, 0x14, 0xEE } }; //GUID in OvmfPkgX64.fdf 1845d593-26a0-4805-a014-2e294fef14ee
// Get the list of available firmware volumes
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status) || HandleCount == 0) {
return EFI_NOT_FOUND;
}
//
// Loop through the Firmware Volumes looking for the Easton 815 Video ROM image
//
for (Index = 0; Index < HandleCount; Index++) {
//
// Get the Firmware Volume Protocol
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &FirmwareVolume
);
if (EFI_ERROR (Status)) {
continue;
}
//
// Get the 16-bit BIOS code from the same Firmware Volume as this driver
//
LocalRomImage = NULL;
LocalRomSize = 0;
Status = FirmwareVolume->ReadSection (
FirmwareVolume,
&gRealtekPXEOpRomGUID,
EFI_SECTION_RAW,
0,
&LocalRomImage,
&LocalRomSize,
&AuthenticationStatus
);
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((EFI_D_INFO, "Charles RomImage = 0x%X ;RomSize = 0x%X ;\n",LocalRomImage,LocalRomSize));
*RomImage = LocalRomImage;
*RomSize = LocalRomSize;
FreePool (HandleBuffer);
return EFI_SUCCESS;
}
FreePool (HandleBuffer);
return EFI_NOT_FOUND;
}
上面代码丢出来的Debug信息如下,
Charles RomImage = 0x7548018 ;RomSize = 0x11800 ;
如何在内存里面查看这个OpRom的内容?根据上面丢出来的OpRom的地址,在内存对应位置查看,可以看到OpRom signature "55AA":
如何执行这个OpRom?