summaryrefslogtreecommitdiffstats
path: root/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
diff options
context:
space:
mode:
Diffstat (limited to 'CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c')
-rw-r--r--CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
new file mode 100644
index 0000000000..df0ae4e256
--- /dev/null
+++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
@@ -0,0 +1,557 @@
+/*++
+
+Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ PciOptionRomSupport.c
+
+Abstract:
+
+ PCI Bus Driver
+
+Revision History
+
+--*/
+
+#include "PciBus.h"
+
+
+EFI_STATUS
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+);
+
+EFI_STATUS
+GetOpRomInfo (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ 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 Status;
+ }
+
+ //
+ // read back
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &AllOnes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Bits [1, 10] are reserved
+ //
+ AllOnes &= 0xFFFFF800;
+ if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));
+ DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));
+
+ PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LoadOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT64 ReservedMemoryBase
+ )
+/*++
+
+Routine Description:
+
+ Load option rom image for specified PCI device
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ 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) {
+ gBS->FreePool (RomHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RomBar = (UINT32)ReservedMemoryBase;
+
+ //
+ // 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));
+
+ //
+ // 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) {
+ retStatus = EFI_SUCCESS;
+ Image = AllocatePool ((UINT32) RomImageSize);
+ if (Image == NULL) {
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+ gBS->FreePool (RomHeader);
+ gBS->FreePool (RomPcir);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy Rom image into memory
+ //
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBar,
+ (UINT32) RomImageSize,
+ Image
+ );
+ RomInMemory = Image;
+ }
+
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+
+ PciDevice->PciIo.RomSize = RomImageSize;
+ PciDevice->PciIo.RomImage = RomInMemory;
+
+ //
+ // Free allocated memory
+ //
+ gBS->FreePool (RomHeader);
+ gBS->FreePool (RomPcir);
+
+ return retStatus;
+}
+
+EFI_STATUS
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ UINT16 CommandValue;
+ UINT32 Value32;
+ UINT64 Address;
+ //EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = PciDevice->PciRootBridgeIo;
+ if (Enable) {
+ Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
+ //
+ // set the Rom base address: now is hardcode
+ //
+ PciRootBridgeIo->Pci.Write(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &RomBar);
+
+ //
+ // enable its decoder
+ //
+ Value32 = RomBar | 0x1;
+ PciRootBridgeIo->Pci.Write(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Value32);
+
+ //
+ //setting the memory space bit in the function's command register
+ //
+ Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);
+ PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &CommandValue);
+
+ CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003
+ PciRootBridgeIo->Pci.Write(
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &CommandValue);
+ } else {
+ //
+ // disable rom decode
+ //
+ Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
+ Value32 = 0xfffffffe;
+ PciRootBridgeIo->Pci.Write(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Value32);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+ProcessOpRomImage (
+ PCI_IO_DEVICE *PciDevice
+ )
+/*++
+
+Routine Description:
+
+ Process the oprom image.
+
+Arguments:
+ PciDevice A pointer to a pci device.
+
+Returns:
+
+ EFI Status.
+
+--*/
+{
+ UINT8 Indicator;
+ UINT32 ImageSize;
+ UINT16 ImageOffset;
+ VOID *RomBar;
+ UINT8 *RomBarOffset;
+ EFI_HANDLE ImageHandle;
+ EFI_STATUS Status;
+ EFI_STATUS retStatus;
+ BOOLEAN SkipImage;
+ UINT32 DestinationSize;
+ UINT32 ScratchSize;
+ UINT8 *Scratch;
+ VOID *ImageBuffer;
+ VOID *DecompressedImageBuffer;
+ UINT32 ImageLength;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+ EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ UINT32 InitializationSize;
+
+ Indicator = 0;
+
+ //
+ // Get the Address of the Rom image
+ //
+ RomBar = PciDevice->PciIo.RomImage;
+ RomBarOffset = (UINT8 *) RomBar;
+ retStatus = EFI_NOT_FOUND;
+
+ if (RomBarOffset == 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 = 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;
+
+ 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))) {
+
+ ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
+ InitializationSize = EfiRomHeader->InitializationSize * 512;
+
+ if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
+
+ ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);
+ ImageLength = InitializationSize - (UINT32)ImageOffset;
+ DecompressedImageBuffer = NULL;
+
+ //
+ // decompress here if needed
+ //
+ SkipImage = FALSE;
+ if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
+ SkipImage = TRUE;
+ }
+
+ if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
+ Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
+ if (EFI_ERROR (Status)) {
+ SkipImage = TRUE;
+ } else {
+ SkipImage = TRUE;
+ Status = Decompress->GetInfo (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ &DestinationSize,
+ &ScratchSize
+ );
+ if (!EFI_ERROR (Status)) {
+ DecompressedImageBuffer = NULL;
+ DecompressedImageBuffer = AllocatePool (DestinationSize);
+ if (DecompressedImageBuffer != NULL) {
+ Scratch = AllocatePool (ScratchSize);
+ if (Scratch != NULL) {
+ Status = Decompress->Decompress (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ DecompressedImageBuffer,
+ DestinationSize,
+ Scratch,
+ ScratchSize
+ );
+ if (!EFI_ERROR (Status)) {
+ ImageBuffer = DecompressedImageBuffer;
+ ImageLength = DestinationSize;
+ SkipImage = FALSE;
+ }
+
+ gBS->FreePool (Scratch);
+ }
+ }
+ }
+ }
+ }
+
+ if (!SkipImage) {
+ //
+ // load image and start image
+ //
+ Status = gBS->LoadImage (
+ FALSE,
+ gPciBusDriverBinding.DriverBindingHandle,
+ NULL,
+ ImageBuffer,
+ ImageLength,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ AddDriver (PciDevice, ImageHandle);
+ retStatus = EFI_SUCCESS;
+ }
+ }
+ }
+
+ RomBarOffset = RomBarOffset + ImageSize;
+ } else {
+ RomBarOffset = RomBarOffset + ImageSize;
+ }
+ } else {
+ RomBarOffset = RomBarOffset + ImageSize;
+ }
+
+ } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
+
+ return retStatus;
+
+}