diff --git a/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.c b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.c new file mode 100644 index 0000000000..52f54ddb82 --- /dev/null +++ b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.c @@ -0,0 +1,436 @@ +/** @file + This driver will probe for the Option Rom and provide a pointer to + the activated BAR if found. + +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; + +/** + The notification from the PCI bus enumerator to the platform that it is + about to enter a certain phase during the enumeration process. + + @param[in] This The pointer to the EFI_PCI_PLATFORM_PROTOCOL instance. + @param[in] HostBridge The handle of the host bridge controller. + @param[in] Phase The phase of the PCI bus enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipset driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +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_SUCCESS; +} + + +/** + The notification from the PCI bus enumerator to the platform for each PCI + controller at several predefined points during PCI controller initialization. + + @param[in] This The pointer to the EFI_PCI_PLATFORM_PROTOCOL instance. + @param[in] HostBridge The associated PCI host bridge handle. + @param[in] RootBridge The associated PCI root bridge handle. + @param[in] PciAddress The address of the PCI device on the PCI bus. + @param[in] Phase The phase of the PCI controller enumeration. + @param[in] ExecPhase Defines the execution phase of the PCI chipset driver. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +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_SUCCESS; +} + +/** + Gets the PCI device's option ROM. + + @param[in] This The pointer to the EFI_PCI_PLATFORM_PROTOCOL instance. + @param[in] PciHandle The handle of the PCI device. + @param[out] RomImage If the call succeeds, the pointer to the pointer to the option ROM image. + Otherwise, this field is undefined. The memory for RomImage is allocated + by EFI_PCI_PLATFORM_PROTOCOL.GetPciRom() using the EFI Boot Service AllocatePool(). + It is the caller's responsibility to free the memory using the EFI Boot Service + FreePool(), when the caller is done with the option ROM. + @param[out] RomSize If the call succeeds, a pointer to the size of the option ROM size. Otherwise, + this field is undefined. + + @retval EFI_SUCCESS The option ROM was available for this device and loaded into memory. + @retval EFI_NOT_FOUND No option ROM was available for this device. + @retval EFI_OUT_OF_RESOURCES No memory was available to load the option ROM. + @retval EFI_DEVICE_ERROR An error occurred in obtaining the option ROM. + +**/ +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 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)) { + return EFI_UNSUPPORTED; + } + + DEBUG_CODE ( + { + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + + // + // Get the location of the PCI device + // + Status = PciIo->GetLocation ( + PciIo, + &PciSegment, + &PciBus, + &PciDevice, + &PciFunction + ); + + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: Searching Option ROM on PCI @ [%02x|%02x|%02x] ..", + __FUNCTION__, + PciBus, + PciDevice, + PciFunction)); + } + } + ); + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); + + // + // Offset is 0x30 if is not ppb + // + 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)) { + DEBUG ((DEBUG_INFO, "error accessing PCI device\n")); + 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)) { + DEBUG ((DEBUG_INFO, "error accessing PCI device\n")); + goto CloseAndReturn; + } + + // + // Read back + // + Status = PciIo->Pci.Read( + PciIo, + EfiPciWidthUint32, + RomBarIndex, + 1, + &AllOnes + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "error accessing PCI device\n")); + goto CloseAndReturn; + } + + // + // Bits [1, 10] are reserved + // + AllOnes &= 0xFFFFF800; + if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) { + DEBUG ((DEBUG_INFO, "nothing found\n")); + Status = EFI_NOT_FOUND; + goto CloseAndReturn; + } + + *RomSize = (~AllOnes) + 1; + + DEBUG ((DEBUG_INFO, "found one of size %d\n", *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 ((DEBUG_INFO, "%a: RomHeader->Signature 0x%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 ((DEBUG_INFO, "%a: RomPcir->Signature 0x%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 ((DEBUG_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; +} + +/** + Retrieves the platform policy regarding enumeration. + + The GetPlatformPolicy() function retrieves the platform policy regarding PCI + enumeration. The PCI bus driver and the PCI Host Bridge Resource Allocation Protocol + driver can call this member function to retrieve the policy. + + @param[in] This The pointer to the EFI_PCI_PLATFORM_PROTOCOL instance. + @param[out] PciPolicy The platform policy with respect to VGA and ISA aliasing. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER PciPolicy is NULL. + +**/ +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; +} diff --git a/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.h b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.h new file mode 100644 index 0000000000..c40518c703 --- /dev/null +++ b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.h @@ -0,0 +1,19 @@ +/** @file + Header file for a PCI platform driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _PCI_PLATFORM_DXE_H_ +#define _PCI_PLATFORM_DXE_H_ +#include + +#include +#include +#include +#include +#include + +#endif diff --git a/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.inf b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.inf new file mode 100644 index 0000000000..96cedad5af --- /dev/null +++ b/UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.inf @@ -0,0 +1,46 @@ +## @file +# This driver produces gEfiPciPlatform protocol to load PCI Option ROMs +# +# Copyright (c) 2020, 9elements Agency GmbH +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PciPlatformDxe + FILE_GUID = 86D58F7B-6E7C-401F-BDD4-E32E6D582AAD + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InstallPciPlatformProtocol + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + PciPlatformDxe.h + PciPlatformDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DxeServicesTableLib + DebugLib + MemoryAllocationLib + BaseMemoryLib + DevicePathLib + UefiLib + HobLib + +[Protocols] + gEfiPciPlatformProtocolGuid ## PRODUCES + gEfiPciIoProtocolGuid ## COMSUMES diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 52423653dd..8a88865d3f 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -568,6 +568,7 @@ MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf !endif UefiPayloadPkg/GraphicsOutputDxe/GraphicsOutputDxe.inf + UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.inf # # Random Number Generator diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayloadPkg.fdf index 62112d0f77..5b3e0e6159 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -168,6 +168,8 @@ INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf !endif INF UefiPayloadPkg/GraphicsOutputDxe/GraphicsOutputDxe.inf +INF UefiPayloadPkg/PciPlatformDxe/PciPlatformDxe.inf + # # SCSI/ATA/IDE/DISK Support #