diff options
Diffstat (limited to 'CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c')
-rw-r--r-- | CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c | 557 |
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; + +} |