/** @file
Implementation for a generic GOP driver.
Copyright (c) 2016, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "PciPlatformDxe.h"
#include
#include
//
// The driver should only start on one graphics controller.
// So a global flag is used to remember that the driver is already started.
//
EFI_HANDLE mDriverHandle = NULL;
EFI_STATUS
EFIAPI
PciPlatformNotify(
IN EFI_PCI_PLATFORM_PROTOCOL *This,
IN EFI_HANDLE HostBridge,
IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
IN EFI_PCI_EXECUTION_PHASE ExecPhase
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
PciPlatformPrepController(
IN EFI_PCI_PLATFORM_PROTOCOL *This,
IN EFI_HANDLE HostBridge,
IN EFI_HANDLE RootBridge,
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
IN EFI_PCI_EXECUTION_PHASE ExecPhase
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
PciGetPciRom (
IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
IN EFI_HANDLE PciHandle,
OUT VOID **RomImage,
OUT UINTN *RomSize
)
{
EFI_STATUS Status;
IN EFI_PCI_IO_PROTOCOL *PciIo;
UINTN PciSegment;
UINTN PciBus;
UINTN PciDevice;
UINTN PciFunction;
UINTN RomBarIndex;
UINT32 Buffer;
UINT32 AllOnes;
PCI_IO_DEVICE *PciIoDevice;
UINT8 Indicator;
UINT16 OffsetPcir;
UINT32 RomBarOffset;
UINT32 RomBar;
BOOLEAN FirstCheck;
PCI_EXPANSION_ROM_HEADER *RomHeader;
PCI_DATA_STRUCTURE *RomPcir;
UINT64 RomImageSize;
UINT32 LegacyImageLength;
UINT8 *RomInMemory;
UINT8 CodeType;
if (!RomImage || !RomSize) {
return EFI_INVALID_PARAMETER;
}
*RomImage = NULL;
*RomSize = 0;
Status = gBS->HandleProtocol (
PciHandle,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO, "%a: Failed to open gEfiPciIoProtocolGuid\n", __FUNCTION__));
return EFI_UNSUPPORTED;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
//
// Get the location of the PCI device
//
PciIo->GetLocation (
PciIo,
&PciSegment,
&PciBus,
&PciDevice,
&PciFunction
);
DEBUG ((EFI_D_INFO, "%a: Searching Option ROM on device:\n", __FUNCTION__));
DEBUG ((EFI_D_INFO, " PciSegment - %02x\n", PciSegment));
DEBUG ((EFI_D_INFO, " PciBus - %02x\n", PciBus));
DEBUG ((EFI_D_INFO, " PciDevice - %02x\n", PciDevice));
DEBUG ((EFI_D_INFO, " PciFunction - %02x\n", PciFunction));
//
// 0x30
//
RomBarIndex = PCI_EXPANSION_ROM_BASE;
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
//
// If is ppb, 0x38
//
RomBarIndex = PCI_BRIDGE_ROMBAR;
}
//
// Backup BAR
//
Status = PciIo->Pci.Read (
PciIo,
EfiPciWidthUint32,
RomBarIndex,
1,
&Buffer
);
if (EFI_ERROR (Status)) {
goto CloseAndReturn;
return Status;
}
//
// The bit0 is 0 to prevent the enabling of the Rom address decoder
//
AllOnes = 0xfffffffe;
Status = PciIo->Pci.Write (
PciIo,
EfiPciWidthUint32,
RomBarIndex,
1,
&AllOnes
);
if (EFI_ERROR (Status)) {
goto CloseAndReturn;
}
//
// Read back
//
Status = PciIo->Pci.Read(
PciIo,
EfiPciWidthUint32,
RomBarIndex,
1,
&AllOnes
);
if (EFI_ERROR (Status)) {
goto CloseAndReturn;
}
//
// Bits [1, 10] are reserved
//
AllOnes &= 0xFFFFF800;
if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
DEBUG ((EFI_D_INFO, "%a: No Option ROM found\n", __FUNCTION__));
return EFI_NOT_FOUND;
}
*RomSize = (~AllOnes) + 1;
DEBUG ((EFI_D_INFO, "%a: Option ROM with size %d\n", __FUNCTION__, *RomSize));
//
// Restore BAR and enable it
//
Buffer |= 1;
Status = PciIo->Pci.Write (
PciIo,
EfiPciWidthUint32,
RomBarIndex,
1,
&Buffer
);
if (EFI_ERROR (Status)) {
goto CloseAndReturn;
}
//
// Allocate memory for Rom header and PCIR
//
RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
if (RomHeader == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto CloseAndReturn;
}
RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
if (RomPcir == NULL) {
FreePool (RomHeader);
Status = EFI_OUT_OF_RESOURCES;
goto CloseAndReturn;
}
// FIXME: Use gEfiPciRootBridgeIoProtocolGuid
RomBar = (UINT32) Buffer &~1;
RomBarOffset = RomBar;
FirstCheck = TRUE;
LegacyImageLength = 0;
RomImageSize = 0;
do {
// FIXME: Use gEfiPciRootBridgeIoProtocolGuid
CopyMem(RomHeader, (VOID *)(UINTN)RomBarOffset, sizeof (PCI_EXPANSION_ROM_HEADER));
DEBUG ((EFI_D_INFO, "%a: RomHeader->Signature %x\n", __FUNCTION__, RomHeader->Signature));
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;
}
// FIXME: Use gEfiPciRootBridgeIoProtocolGuid
CopyMem(RomPcir, (VOID *)(UINTN)RomBarOffset + OffsetPcir, sizeof (PCI_DATA_STRUCTURE));
DEBUG ((EFI_D_INFO, "%a: RomPcir->Signature %x\n", __FUNCTION__, RomPcir->Signature));
//
// 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));
//
// Some Legacy Cards do not report the correct ImageLength so used the maximum
// of the legacy length and the PCIR Image Length
//
if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
RomImageSize = MAX (RomImageSize, LegacyImageLength);
}
if (RomImageSize > 0) {
// FIXME: Use gEfiPciRootBridgeIoProtocolGuid
RomInMemory = (VOID *)(UINTN)RomBar;
}
//
// Free allocated memory
//
FreePool (RomHeader);
FreePool (RomPcir);
if (RomImageSize > 0) {
*RomImage = RomInMemory;
*RomSize = RomImageSize;
DEBUG ((EFI_D_INFO, "%a: Found Option ROM at %p, length 0x%x\n", __FUNCTION__,
RomInMemory, RomImageSize));
Status = EFI_SUCCESS;
} else {
Status = EFI_NOT_FOUND;
}
CloseAndReturn:
//
// Close the I/O Abstraction(s) used to perform the supported test
//
gBS->CloseProtocol (
PciHandle,
&gEfiPciIoProtocolGuid,
PciIo,
PciHandle
);
return Status;
}
EFI_STATUS
EFIAPI
PciGetPlatformPolicy (
IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
OUT EFI_PCI_PLATFORM_POLICY *PciPolicy
)
{
if (PciPolicy == NULL)
return EFI_INVALID_PARAMETER;
*PciPolicy = 0;
return EFI_SUCCESS;
}
EFI_PCI_PLATFORM_PROTOCOL mPciPlatformProtocol = {
PciPlatformNotify,
PciPlatformPrepController,
PciGetPlatformPolicy,
PciGetPciRom,
};
/**
The Entry Point for Option ROM driver.
It installs DriverBinding.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
InstallPciPlatformProtocol (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = gBS->InstallProtocolInterface (
&mDriverHandle,
&gEfiPciPlatformProtocolGuid,
EFI_NATIVE_INTERFACE,
&mPciPlatformProtocol
);
return Status;
}