/*++ | |
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; | |
} |