/** @file | |
PCI Rom supporting funtions implementation for PCI Bus module. | |
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "PciBus.h" | |
/** | |
Load the EFI Image from Option ROM | |
@param PciIoDevice PCI IO device instance. | |
@param FilePath The file path of the EFI Image | |
@param BufferSize On input the size of Buffer in bytes. On output with a return | |
code of EFI_SUCCESS, the amount of data transferred to Buffer. | |
On output with a return code of EFI_BUFFER_TOO_SMALL, | |
the size of Buffer required to retrieve the requested file. | |
@param Buffer The memory buffer to transfer the file to. If Buffer is NULL, | |
then no the size of the requested file is returned in BufferSize. | |
@retval EFI_SUCCESS The file was loaded. | |
@retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or | |
BufferSize is NULL. | |
@retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device. | |
@retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image. | |
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. | |
BufferSize has been updated with the size needed to complete the request. | |
**/ | |
EFI_STATUS | |
LocalLoadFile2 ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN EFI_DEVICE_PATH_PROTOCOL *FilePath, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode; | |
EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; | |
PCI_DATA_STRUCTURE *Pcir; | |
UINT32 ImageSize; | |
UINT8 *ImageBuffer; | |
UINT32 ImageLength; | |
UINT32 DestinationSize; | |
UINT32 ScratchSize; | |
VOID *Scratch; | |
EFI_DECOMPRESS_PROTOCOL *Decompress; | |
UINT32 InitializationSize; | |
EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *)FilePath; | |
if ((EfiOpRomImageNode == NULL) || | |
(DevicePathType (FilePath) != MEDIA_DEVICE_PATH) || | |
(DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) || | |
(DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) || | |
(!IsDevicePathEnd (NextDevicePathNode (FilePath))) || | |
(EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) || | |
(EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) || | |
(BufferSize == NULL) | |
) | |
{ | |
return EFI_INVALID_PARAMETER; | |
} | |
EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *)( | |
(UINT8 *)PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset | |
); | |
if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { | |
return EFI_NOT_FOUND; | |
} | |
Pcir = (PCI_DATA_STRUCTURE *)((UINT8 *)EfiRomHeader + EfiRomHeader->PcirOffset); | |
ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); | |
if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && | |
(EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && | |
((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || | |
(EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) && | |
(EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) | |
) | |
{ | |
ImageSize = Pcir->ImageLength * 512; | |
InitializationSize = (UINT32)EfiRomHeader->InitializationSize * 512; | |
if ((InitializationSize > ImageSize) || (EfiRomHeader->EfiImageHeaderOffset >= InitializationSize)) { | |
return EFI_NOT_FOUND; | |
} | |
ImageBuffer = (UINT8 *)EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset; | |
ImageLength = InitializationSize - EfiRomHeader->EfiImageHeaderOffset; | |
if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { | |
// | |
// Uncompressed: Copy the EFI Image directly to user's buffer | |
// | |
if ((Buffer == NULL) || (*BufferSize < ImageLength)) { | |
*BufferSize = ImageLength; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
*BufferSize = ImageLength; | |
CopyMem (Buffer, ImageBuffer, ImageLength); | |
return EFI_SUCCESS; | |
} else { | |
// | |
// Compressed: Uncompress before copying | |
// | |
Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
Status = Decompress->GetInfo ( | |
Decompress, | |
ImageBuffer, | |
ImageLength, | |
&DestinationSize, | |
&ScratchSize | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
if ((Buffer == NULL) || (*BufferSize < DestinationSize)) { | |
*BufferSize = DestinationSize; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
*BufferSize = DestinationSize; | |
Scratch = AllocatePool (ScratchSize); | |
if (Scratch == NULL) { | |
return EFI_DEVICE_ERROR; | |
} | |
Status = Decompress->Decompress ( | |
Decompress, | |
ImageBuffer, | |
ImageLength, | |
Buffer, | |
DestinationSize, | |
Scratch, | |
ScratchSize | |
); | |
FreePool (Scratch); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Initialize a PCI LoadFile2 instance. | |
@param PciIoDevice PCI IO Device. | |
**/ | |
VOID | |
InitializePciLoadFile2 ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
PciIoDevice->LoadFile2.LoadFile = LoadFile2; | |
} | |
/** | |
Causes the driver to load a specified file. | |
@param This Indicates a pointer to the calling context. | |
@param FilePath The device specific path of the file to load. | |
@param BootPolicy Should always be FALSE. | |
@param BufferSize On input the size of Buffer in bytes. On output with a return | |
code of EFI_SUCCESS, the amount of data transferred to Buffer. | |
On output with a return code of EFI_BUFFER_TOO_SMALL, | |
the size of Buffer required to retrieve the requested file. | |
@param Buffer The memory buffer to transfer the file to. If Buffer is NULL, | |
then no the size of the requested file is returned in BufferSize. | |
@retval EFI_SUCCESS The file was loaded. | |
@retval EFI_UNSUPPORTED BootPolicy is TRUE. | |
@retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or | |
BufferSize is NULL. | |
@retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device. | |
@retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image. | |
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. | |
BufferSize has been updated with the size needed to complete the request. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
LoadFile2 ( | |
IN EFI_LOAD_FILE2_PROTOCOL *This, | |
IN EFI_DEVICE_PATH_PROTOCOL *FilePath, | |
IN BOOLEAN BootPolicy, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer OPTIONAL | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
if (BootPolicy) { | |
return EFI_UNSUPPORTED; | |
} | |
PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This); | |
return LocalLoadFile2 ( | |
PciIoDevice, | |
FilePath, | |
BufferSize, | |
Buffer | |
); | |
} | |
/** | |
Get Pci device's oprom information. | |
@param PciIoDevice Input Pci device instance. | |
Output Pci device instance with updated OptionRom size. | |
@retval EFI_NOT_FOUND Pci device has not Option Rom. | |
@retval EFI_SUCCESS Pci device has Option Rom. | |
**/ | |
EFI_STATUS | |
GetOpRomInfo ( | |
IN OUT PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
UINT8 RomBarIndex; | |
UINT32 AllOnes; | |
UINT64 Address; | |
EFI_STATUS Status; | |
UINT8 Bus; | |
UINT8 Device; | |
UINT8 Function; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
Bus = PciIoDevice->BusNumber; | |
Device = PciIoDevice->DeviceNumber; | |
Function = PciIoDevice->FunctionNumber; | |
PciRootBridgeIo = PciIoDevice->PciRootBridgeIo; | |
// | |
// Offset is 0x30 if is not ppb | |
// | |
// | |
// 0x30 | |
// | |
RomBarIndex = PCI_EXPANSION_ROM_BASE; | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
// | |
// If is ppb, 0x38 | |
// | |
RomBarIndex = PCI_BRIDGE_ROMBAR; | |
} | |
// | |
// The bit0 is 0 to prevent the enabling of the Rom address decoder | |
// | |
AllOnes = 0xfffffffe; | |
Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex); | |
Status = PciRootBridgeIo->Pci.Write ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
1, | |
&AllOnes | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Read back | |
// | |
Status = PciRootBridgeIo->Pci.Read ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
1, | |
&AllOnes | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Bits [1, 10] are reserved | |
// | |
AllOnes &= 0xFFFFF800; | |
if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) { | |
return EFI_NOT_FOUND; | |
} | |
PciIoDevice->RomSize = (~AllOnes) + 1; | |
return EFI_SUCCESS; | |
} | |
/** | |
Check if the RomImage contains EFI Images. | |
@param RomImage The ROM address of Image for check. | |
@param RomSize Size of ROM for check. | |
@retval TRUE ROM contain EFI Image. | |
@retval FALSE ROM not contain EFI Image. | |
**/ | |
BOOLEAN | |
ContainEfiImage ( | |
IN VOID *RomImage, | |
IN UINT64 RomSize | |
) | |
{ | |
PCI_EXPANSION_ROM_HEADER *RomHeader; | |
PCI_DATA_STRUCTURE *RomPcir; | |
UINT8 Indicator; | |
Indicator = 0; | |
RomHeader = RomImage; | |
if (RomHeader == NULL) { | |
return FALSE; | |
} | |
do { | |
if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { | |
RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + 512); | |
continue; | |
} | |
// | |
// The PCI Data Structure must be DWORD aligned. | |
// | |
if ((RomHeader->PcirOffset == 0) || | |
((RomHeader->PcirOffset & 3) != 0) || | |
((UINT8 *)RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *)RomImage + RomSize)) | |
{ | |
break; | |
} | |
RomPcir = (PCI_DATA_STRUCTURE *)((UINT8 *)RomHeader + RomHeader->PcirOffset); | |
if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { | |
break; | |
} | |
if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) { | |
return TRUE; | |
} | |
Indicator = RomPcir->Indicator; | |
RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + RomPcir->ImageLength * 512); | |
} while (((UINT8 *)RomHeader < (UINT8 *)RomImage + RomSize) && ((Indicator & 0x80) == 0x00)); | |
return FALSE; | |
} | |
/** | |
Load Option Rom image for specified PCI device. | |
@param PciDevice Pci device instance. | |
@param RomBase Base address of Option Rom. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to hold image. | |
@retval EFI_SUCESS Successfully loaded Option Rom. | |
**/ | |
EFI_STATUS | |
LoadOpRomImage ( | |
IN PCI_IO_DEVICE *PciDevice, | |
IN UINT64 RomBase | |
) | |
{ | |
UINT8 RomBarIndex; | |
UINT8 Indicator; | |
UINT16 OffsetPcir; | |
UINT32 RomBarOffset; | |
UINT32 RomBar; | |
EFI_STATUS RetStatus; | |
BOOLEAN FirstCheck; | |
UINT8 *Image; | |
PCI_EXPANSION_ROM_HEADER *RomHeader; | |
PCI_DATA_STRUCTURE *RomPcir; | |
UINT64 RomSize; | |
UINT64 RomImageSize; | |
UINT32 LegacyImageLength; | |
UINT8 *RomInMemory; | |
UINT8 CodeType; | |
RomSize = PciDevice->RomSize; | |
Indicator = 0; | |
RomImageSize = 0; | |
RomInMemory = NULL; | |
CodeType = 0xFF; | |
// | |
// Get the RomBarIndex | |
// | |
// | |
// 0x30 | |
// | |
RomBarIndex = PCI_EXPANSION_ROM_BASE; | |
if (IS_PCI_BRIDGE (&(PciDevice->Pci))) { | |
// | |
// if is ppb | |
// | |
// | |
// 0x38 | |
// | |
RomBarIndex = PCI_BRIDGE_ROMBAR; | |
} | |
// | |
// Allocate memory for Rom header and PCIR | |
// | |
RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER)); | |
if (RomHeader == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE)); | |
if (RomPcir == NULL) { | |
FreePool (RomHeader); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
RomBar = (UINT32)RomBase; | |
// | |
// Enable RomBar | |
// | |
RomDecode (PciDevice, RomBarIndex, RomBar, TRUE); | |
RomBarOffset = RomBar; | |
RetStatus = EFI_NOT_FOUND; | |
FirstCheck = TRUE; | |
LegacyImageLength = 0; | |
do { | |
PciDevice->PciRootBridgeIo->Mem.Read ( | |
PciDevice->PciRootBridgeIo, | |
EfiPciWidthUint8, | |
RomBarOffset, | |
sizeof (PCI_EXPANSION_ROM_HEADER), | |
(UINT8 *)RomHeader | |
); | |
if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { | |
RomBarOffset = RomBarOffset + 512; | |
if (FirstCheck) { | |
break; | |
} else { | |
RomImageSize = RomImageSize + 512; | |
continue; | |
} | |
} | |
FirstCheck = FALSE; | |
OffsetPcir = RomHeader->PcirOffset; | |
// | |
// If the pointer to the PCI Data Structure is invalid, no further images can be located. | |
// The PCI Data Structure must be DWORD aligned. | |
// | |
if ((OffsetPcir == 0) || | |
((OffsetPcir & 3) != 0) || | |
(RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize)) | |
{ | |
break; | |
} | |
PciDevice->PciRootBridgeIo->Mem.Read ( | |
PciDevice->PciRootBridgeIo, | |
EfiPciWidthUint8, | |
RomBarOffset + OffsetPcir, | |
sizeof (PCI_DATA_STRUCTURE), | |
(UINT8 *)RomPcir | |
); | |
// | |
// If a valid signature is not present in the PCI Data Structure, no further images can be located. | |
// | |
if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { | |
break; | |
} | |
if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) { | |
break; | |
} | |
if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { | |
CodeType = PCI_CODE_TYPE_PCAT_IMAGE; | |
LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512; | |
} | |
Indicator = RomPcir->Indicator; | |
RomImageSize = RomImageSize + RomPcir->ImageLength * 512; | |
RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512; | |
} while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize) && (RomImageSize > 0)); | |
// | |
// Some Legacy Cards do not report the correct ImageLength so used the maximum | |
// of the legacy length and the PCIR Image Length | |
// | |
if ((RomImageSize > 0) && (CodeType == PCI_CODE_TYPE_PCAT_IMAGE)) { | |
RomImageSize = MAX (RomImageSize, LegacyImageLength); | |
} | |
if (RomImageSize > 0) { | |
RetStatus = EFI_SUCCESS; | |
Image = AllocatePool ((UINT32)RomImageSize); | |
if (Image == NULL) { | |
RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); | |
FreePool (RomHeader); | |
FreePool (RomPcir); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Copy Rom image into memory | |
// | |
PciDevice->PciRootBridgeIo->Mem.Read ( | |
PciDevice->PciRootBridgeIo, | |
EfiPciWidthUint32, | |
RomBar, | |
(UINT32)RomImageSize/sizeof (UINT32), | |
Image | |
); | |
RomInMemory = Image; | |
} | |
RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); | |
PciDevice->EmbeddedRom = TRUE; | |
PciDevice->PciIo.RomSize = RomImageSize; | |
PciDevice->PciIo.RomImage = RomInMemory; | |
// | |
// For OpROM read from PCI device: | |
// Add the Rom Image to internal database for later PCI light enumeration | |
// | |
PciRomAddImageMapping ( | |
NULL, | |
PciDevice->PciRootBridgeIo->SegmentNumber, | |
PciDevice->BusNumber, | |
PciDevice->DeviceNumber, | |
PciDevice->FunctionNumber, | |
PciDevice->PciIo.RomImage, | |
PciDevice->PciIo.RomSize | |
); | |
// | |
// Free allocated memory | |
// | |
FreePool (RomHeader); | |
FreePool (RomPcir); | |
return RetStatus; | |
} | |
/** | |
Enable/Disable Option Rom decode. | |
@param PciDevice Pci device instance. | |
@param RomBarIndex The BAR index of the standard PCI Configuration header to use as the | |
base address for resource range. The legal range for this field is 0..5. | |
@param RomBar Base address of Option Rom. | |
@param Enable Flag for enable/disable decode. | |
**/ | |
VOID | |
RomDecode ( | |
IN PCI_IO_DEVICE *PciDevice, | |
IN UINT8 RomBarIndex, | |
IN UINT32 RomBar, | |
IN BOOLEAN Enable | |
) | |
{ | |
UINT32 Value32; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
PciIo = &PciDevice->PciIo; | |
if (Enable) { | |
// | |
// set the Rom base address: now is hardcode | |
// enable its decoder | |
// | |
Value32 = RomBar | 0x1; | |
PciIo->Pci.Write ( | |
PciIo, | |
(EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint32, | |
RomBarIndex, | |
1, | |
&Value32 | |
); | |
// | |
// Programe all upstream bridge | |
// | |
ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE); | |
// | |
// Setting the memory space bit in the function's command register | |
// | |
PCI_ENABLE_COMMAND_REGISTER (PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); | |
} else { | |
// | |
// disable command register decode to memory | |
// | |
PCI_DISABLE_COMMAND_REGISTER (PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); | |
// | |
// Destroy the programmed bar in all the upstream bridge. | |
// | |
ProgramUpstreamBridgeForRom (PciDevice, RomBar, FALSE); | |
// | |
// disable rom decode | |
// | |
Value32 = 0xFFFFFFFE; | |
PciIo->Pci.Write ( | |
PciIo, | |
(EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint32, | |
RomBarIndex, | |
1, | |
&Value32 | |
); | |
} | |
} | |
/** | |
Load and start the Option Rom image. | |
@param PciDevice Pci device instance. | |
@retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image. | |
@retval EFI_NOT_FOUND Failed to process PCI Option Rom image. | |
**/ | |
EFI_STATUS | |
ProcessOpRomImage ( | |
IN PCI_IO_DEVICE *PciDevice | |
) | |
{ | |
UINT8 Indicator; | |
UINT32 ImageSize; | |
VOID *RomBar; | |
UINT8 *RomBarOffset; | |
EFI_HANDLE ImageHandle; | |
EFI_STATUS Status; | |
EFI_STATUS RetStatus; | |
EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; | |
PCI_DATA_STRUCTURE *Pcir; | |
EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath; | |
MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode; | |
VOID *Buffer; | |
UINTN BufferSize; | |
Indicator = 0; | |
// | |
// Get the Address of the Option Rom image | |
// | |
RomBar = PciDevice->PciIo.RomImage; | |
RomBarOffset = (UINT8 *)RomBar; | |
RetStatus = EFI_NOT_FOUND; | |
if (RomBar == NULL) { | |
return RetStatus; | |
} | |
ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *)RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE); | |
do { | |
EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *)RomBarOffset; | |
if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { | |
RomBarOffset += 512; | |
continue; | |
} | |
Pcir = (PCI_DATA_STRUCTURE *)(RomBarOffset + EfiRomHeader->PcirOffset); | |
ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); | |
ImageSize = (UINT32)(Pcir->ImageLength * 512); | |
Indicator = Pcir->Indicator; | |
// | |
// Skip the image if it is not an EFI PCI Option ROM image | |
// | |
if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) { | |
goto NextImage; | |
} | |
// | |
// Ignore the EFI PCI Option ROM image if it is an EFI application | |
// | |
if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { | |
goto NextImage; | |
} | |
// | |
// Create Pci Option Rom Image device path header | |
// | |
EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH; | |
EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP; | |
SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode)); | |
EfiOpRomImageNode.StartingOffset = (UINTN)RomBarOffset - (UINTN)RomBar; | |
EfiOpRomImageNode.EndingOffset = (UINTN)RomBarOffset + ImageSize - 1 - (UINTN)RomBar; | |
PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header); | |
ASSERT (PciOptionRomImageDevicePath != NULL); | |
// | |
// load image and start image | |
// | |
BufferSize = 0; | |
Buffer = NULL; | |
ImageHandle = NULL; | |
Status = gBS->LoadImage ( | |
FALSE, | |
gPciBusDriverBinding.DriverBindingHandle, | |
PciOptionRomImageDevicePath, | |
Buffer, | |
BufferSize, | |
&ImageHandle | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Record the Option ROM Image device path when LoadImage fails. | |
// PciOverride.GetDriver() will try to look for the Image Handle using the device path later. | |
// | |
AddDriver (PciDevice, NULL, PciOptionRomImageDevicePath); | |
} else { | |
Status = gBS->StartImage (ImageHandle, NULL, NULL); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Record the Option ROM Image Handle | |
// | |
AddDriver (PciDevice, ImageHandle, NULL); | |
PciRomAddImageMapping ( | |
ImageHandle, | |
PciDevice->PciRootBridgeIo->SegmentNumber, | |
PciDevice->BusNumber, | |
PciDevice->DeviceNumber, | |
PciDevice->FunctionNumber, | |
PciDevice->PciIo.RomImage, | |
PciDevice->PciIo.RomSize | |
); | |
RetStatus = EFI_SUCCESS; | |
} | |
} | |
FreePool (PciOptionRomImageDevicePath); | |
NextImage: | |
RomBarOffset += ImageSize; | |
} while (((Indicator & 0x80) == 0x00) && (((UINTN)RomBarOffset - (UINTN)RomBar) < PciDevice->RomSize)); | |
return RetStatus; | |
} |