git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@238 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			544 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			544 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. 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"
 | |
| #include "PciResourceSupport.h"
 | |
| 
 | |
| EFI_STATUS
 | |
| GetOpRomInfo (
 | |
|   IN PCI_IO_DEVICE    *PciIoDevice
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| // TODO:    PciIoDevice - add argument and description to function comment
 | |
| // TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| {
 | |
|   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 48 if is not ppb
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // 0x30
 | |
|   //
 | |
|   RomBarIndex = PCI_DEVICE_ROMBAR;
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   AllOnes &= 0xFFFFFFFC;
 | |
|   if ((AllOnes == 0) || (AllOnes == 0xFFFFFFFC)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| LoadOpRomImage (
 | |
|   IN PCI_IO_DEVICE   *PciDevice,
 | |
|   IN UINT64          RomBase
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|  
 | |
|     Load option rom image for specified PCI device
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
| Returns:
 | |
| 
 | |
| --*/
 | |
| // TODO:    PciDevice - add argument and description to function comment
 | |
| // TODO:    RomBase - add argument and description to function comment
 | |
| // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | |
| // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | |
| // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | |
| {
 | |
|   UINT8                     RomBarIndex;
 | |
|   UINT8                     Indicator;
 | |
|   UINT16                    OffsetPcir;
 | |
|   UINT32                    RomBarOffset;
 | |
|   UINT32                    RomBar;
 | |
|   UINT64                    Temp;
 | |
|   EFI_STATUS                retStatus;
 | |
|   BOOLEAN                   FirstCheck;
 | |
|   UINT8                     *Image;
 | |
|   PCI_EXPANSION_ROM_HEADER  *RomHeader;
 | |
|   PCI_DATA_STRUCTURE        *RomPcir;
 | |
|   UINT64                    RomSize;
 | |
|   UINT64                    RomImageSize;
 | |
|   UINT8                     *RomInMemory;
 | |
| 
 | |
|   RomSize       = PciDevice->RomSize;
 | |
| 
 | |
|   Indicator     = 0;
 | |
|   RomImageSize  = 0;
 | |
|   RomInMemory   = NULL;
 | |
|   Temp          = 0;
 | |
| 
 | |
|   //
 | |
|   // Get the RomBarIndex
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // 0x30
 | |
|   //
 | |
|   RomBarIndex = PCI_DEVICE_ROMBAR;
 | |
|   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) RomBase;
 | |
| 
 | |
|   //
 | |
|   // Enable RomBar
 | |
|   //
 | |
|   RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
 | |
| 
 | |
|   RomBarOffset  = RomBar;
 | |
|   retStatus     = EFI_NOT_FOUND;
 | |
|   FirstCheck    = TRUE;
 | |
| 
 | |
|   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;
 | |
|     PciDevice->PciRootBridgeIo->Mem.Read (
 | |
|                                       PciDevice->PciRootBridgeIo,
 | |
|                                       EfiPciWidthUint8,
 | |
|                                       RomBarOffset + OffsetPcir,
 | |
|                                       sizeof (PCI_DATA_STRUCTURE),
 | |
|                                       (UINT8 *) RomPcir
 | |
|                                       );
 | |
|     Indicator     = RomPcir->Indicator;
 | |
|     RomImageSize  = RomImageSize + RomPcir->ImageLength * 512;
 | |
|     RomBarOffset  = RomBarOffset + RomPcir->ImageLength * 512;
 | |
|   } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   PciRomAddImageMapping (
 | |
|     NULL,
 | |
|     PciDevice->PciRootBridgeIo->SegmentNumber,
 | |
|     PciDevice->BusNumber,
 | |
|     PciDevice->DeviceNumber,
 | |
|     PciDevice->FunctionNumber,
 | |
|     (UINT64) (UINTN) PciDevice->PciIo.RomImage,
 | |
|     PciDevice->PciIo.RomSize
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // 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:
 | |
| 
 | |
| --*/
 | |
| // TODO:    PciDevice - add argument and description to function comment
 | |
| // TODO:    RomBarIndex - add argument and description to function comment
 | |
| // TODO:    RomBar - add argument and description to function comment
 | |
| // TODO:    Enable - add argument and description to function comment
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| {
 | |
|   UINT32              Value32;
 | |
|   UINT32              Offset;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
| 
 | |
|   PciIo = &PciDevice->PciIo;
 | |
|   if (Enable) {
 | |
|     //
 | |
|     // Clear all bars
 | |
|     //
 | |
|     for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
 | |
|       PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // set the Rom base address: now is hardcode
 | |
|     // enable its decoder
 | |
|     //
 | |
|     Value32 = RomBar | 0x1;
 | |
|     PciIo->Pci.Write (
 | |
|                 PciIo,
 | |
|                 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
 | |
|                 RomBarIndex,
 | |
|                 1,
 | |
|                 &Value32
 | |
|                 );
 | |
| 
 | |
|     //
 | |
|     // Programe all upstream bridge
 | |
|     //
 | |
|     ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
 | |
| 
 | |
|     //
 | |
|     // Setting the memory space bit in the function's command register
 | |
|     //
 | |
|     PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
 | |
| 
 | |
|   } else {
 | |
|     
 | |
|     //
 | |
|     // disable command register decode to memory
 | |
|     //
 | |
|     PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
 | |
| 
 | |
|     //
 | |
|     // Destroy the programmed bar in all the upstream bridge.
 | |
|     //
 | |
|     ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
 | |
| 
 | |
|     //
 | |
|     // disable rom decode
 | |
|     //
 | |
|     Value32 = 0xFFFFFFFE;
 | |
|     PciIo->Pci.Write (
 | |
|                 PciIo,
 | |
|                 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
 | |
|                 RomBarIndex,
 | |
|                 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                       FirstCheck;
 | |
|   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;
 | |
| 
 | |
|   Indicator = 0;
 | |
| 
 | |
|   //
 | |
|   // Get the Address of the Rom image
 | |
|   //
 | |
|   RomBar        = PciDevice->PciIo.RomImage;
 | |
|   RomBarOffset  = (UINT8 *) RomBar;
 | |
|   retStatus     = EFI_NOT_FOUND;
 | |
|   FirstCheck    = TRUE;
 | |
| 
 | |
|   do {
 | |
|     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
 | |
|     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
 | |
|       RomBarOffset = RomBarOffset + 512;
 | |
|       if (FirstCheck) {
 | |
|         break;
 | |
|       } else {
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     FirstCheck  = FALSE;
 | |
|     Pcir        = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
 | |
|     ImageSize   = (UINT32) (Pcir->ImageLength * 512);
 | |
|     Indicator   = Pcir->Indicator;
 | |
| 
 | |
|     if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && 
 | |
|         (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {
 | |
| 
 | |
|       if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)  ||
 | |
|           (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
 | |
| 
 | |
|         ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
 | |
|         ImageSize               = (UINT32) (EfiRomHeader->InitializationSize * 512);
 | |
| 
 | |
|         ImageBuffer             = (VOID *) (RomBarOffset + ImageOffset);
 | |
|         ImageLength             = ImageSize - (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,
 | |
|                           PciDevice->Handle,
 | |
|                           ImageBuffer,
 | |
|                           ImageLength,
 | |
|                           &ImageHandle
 | |
|                           );
 | |
|           if (!EFI_ERROR (Status)) {
 | |
|             Status = gBS->StartImage (ImageHandle, NULL, NULL);
 | |
|             if (!EFI_ERROR (Status)) {
 | |
|               AddDriver (PciDevice, ImageHandle);
 | |
|               PciRomAddImageMapping (
 | |
|                 ImageHandle,
 | |
|                 PciDevice->PciRootBridgeIo->SegmentNumber,
 | |
|                 PciDevice->BusNumber,
 | |
|                 PciDevice->DeviceNumber,
 | |
|                 PciDevice->FunctionNumber,
 | |
|                 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
 | |
|                 PciDevice->PciIo.RomSize
 | |
|                 );
 | |
|               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;
 | |
| 
 | |
| }
 |