3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PciResourceSupport.h"
17 #include <IndustryStandard/Pci23.h>
20 // Module global for a template of the PCI option ROM Image Device Path Node
22 MEMMAP_DEVICE_PATH mPciOptionRomImageDevicePathNodeTemplate
= {
27 (UINT8
) (sizeof (MEMMAP_DEVICE_PATH
)),
28 (UINT8
) ((sizeof (MEMMAP_DEVICE_PATH
)) >> 8)
37 Get Pci device's oprom infor bits.
39 @retval EFI_NOT_FOUND Pci device has not oprom
40 @retval EFI_SUCCESS Pci device has oprom
44 IN PCI_IO_DEVICE
*PciIoDevice
54 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
56 Bus
= PciIoDevice
->BusNumber
;
57 Device
= PciIoDevice
->DeviceNumber
;
58 Function
= PciIoDevice
->FunctionNumber
;
60 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
63 // offset is 0x30 if is not ppb
69 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
71 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
79 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
82 // the bit0 is 0 to prevent the enabling of the Rom address decoder
85 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
87 Status
= PciRootBridgeIoWrite (
95 if (EFI_ERROR (Status
)) {
102 Status
= PciRootBridgeIoRead (
110 if (EFI_ERROR (Status
)) {
114 // Bits [1, 10] are reserved
116 AllOnes
&= 0xFFFFF800;
117 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
118 return EFI_NOT_FOUND
;
121 PciIoDevice
->RomSize
= (UINT64
) ((~AllOnes
) + 1);
126 Load option rom image for specified PCI device
128 @param PciDevice Pci device instance
129 @param RomBase Base address of oprom.
131 @retval EFI_OUT_OF_RESOURCES not enough memory to hold image
132 @retval EFI_SUCESS Success
136 IN PCI_IO_DEVICE
*PciDevice
,
145 EFI_STATUS retStatus
;
148 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
149 PCI_DATA_STRUCTURE
*RomPcir
;
155 RomSize
= PciDevice
->RomSize
;
163 // Get the RomBarIndex
169 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
170 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
178 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
181 // Allocate memory for Rom header and PCIR
183 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
184 if (RomHeader
== NULL
) {
185 return EFI_OUT_OF_RESOURCES
;
188 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
189 if (RomPcir
== NULL
) {
190 gBS
->FreePool (RomHeader
);
191 return EFI_OUT_OF_RESOURCES
;
194 RomBar
= (UINT32
) RomBase
;
199 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
201 RomBarOffset
= RomBar
;
202 retStatus
= EFI_NOT_FOUND
;
206 PciDevice
->PciRootBridgeIo
->Mem
.Read (
207 PciDevice
->PciRootBridgeIo
,
210 sizeof (PCI_EXPANSION_ROM_HEADER
),
214 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
215 RomBarOffset
= RomBarOffset
+ 512;
219 RomImageSize
= RomImageSize
+ 512;
225 OffsetPcir
= RomHeader
->PcirOffset
;
226 PciDevice
->PciRootBridgeIo
->Mem
.Read (
227 PciDevice
->PciRootBridgeIo
,
229 RomBarOffset
+ OffsetPcir
,
230 sizeof (PCI_DATA_STRUCTURE
),
233 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
234 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
236 Indicator
= RomPcir
->Indicator
;
237 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
238 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
239 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
242 // Some Legacy Cards do not report the correct ImageLength so used the maximum
243 // of the legacy length and the PCIR Image Length
245 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
246 RomImageSize
= MAX(RomImageSize
, (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
* 512));
249 if (RomImageSize
> 0) {
250 retStatus
= EFI_SUCCESS
;
251 Image
= AllocatePool ((UINT32
) RomImageSize
);
253 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
254 gBS
->FreePool (RomHeader
);
255 gBS
->FreePool (RomPcir
);
256 return EFI_OUT_OF_RESOURCES
;
260 // Copy Rom image into memory
262 PciDevice
->PciRootBridgeIo
->Mem
.Read (
263 PciDevice
->PciRootBridgeIo
,
266 (UINT32
) RomImageSize
,
272 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
274 PciDevice
->PciIo
.RomSize
= RomImageSize
;
275 PciDevice
->PciIo
.RomImage
= RomInMemory
;
278 // For OpROM read from PCI device:
279 // Add the Rom Image to internal database for later PCI light enumeration
281 PciRomAddImageMapping (
283 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
284 PciDevice
->BusNumber
,
285 PciDevice
->DeviceNumber
,
286 PciDevice
->FunctionNumber
,
287 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
288 PciDevice
->PciIo
.RomSize
292 // Free allocated memory
294 gBS
->FreePool (RomHeader
);
295 gBS
->FreePool (RomPcir
);
301 enable/disable oprom decode
303 @param PciDevice pci device instance
304 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
305 base address for resource range. The legal range for this field is 0..5.
306 @param RomBar Base address of rom
307 @param Enable Flag for enable/disable decode.
309 @retval EFI_SUCCESS Success
313 IN PCI_IO_DEVICE
*PciDevice
,
314 IN UINT8 RomBarIndex
,
321 EFI_PCI_IO_PROTOCOL
*PciIo
;
323 PciIo
= &PciDevice
->PciIo
;
328 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
329 PciIoWrite (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
333 // set the Rom base address: now is hardcode
334 // enable its decoder
336 Value32
= RomBar
| 0x1;
339 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
346 // Programe all upstream bridge
348 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
351 // Setting the memory space bit in the function's command register
353 PciEnableCommandRegister(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
358 // disable command register decode to memory
360 PciDisableCommandRegister(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
363 // Destroy the programmed bar in all the upstream bridge.
365 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
368 // disable rom decode
370 Value32
= 0xFFFFFFFE;
373 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
386 Process the oprom image.
388 @param PciDevice Pci device instance
392 PCI_IO_DEVICE
*PciDevice
400 EFI_HANDLE ImageHandle
;
402 EFI_STATUS retStatus
;
405 UINT32 DestinationSize
;
409 VOID
*DecompressedImageBuffer
;
411 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
412 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
413 PCI_DATA_STRUCTURE
*Pcir
;
414 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
419 // Get the Address of the Rom image
421 RomBar
= PciDevice
->PciIo
.RomImage
;
422 RomBarOffset
= (UINT8
*) RomBar
;
423 retStatus
= EFI_NOT_FOUND
;
427 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
428 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
429 RomBarOffset
= RomBarOffset
+ 512;
438 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
439 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
440 Indicator
= Pcir
->Indicator
;
442 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
443 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
)) {
445 if ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
446 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) {
448 ImageOffset
= EfiRomHeader
->EfiImageHeaderOffset
;
449 ImageSize
= (UINT32
) (EfiRomHeader
->InitializationSize
* 512);
451 ImageBuffer
= (VOID
*) (RomBarOffset
+ ImageOffset
);
452 ImageLength
= ImageSize
- (UINT32
)ImageOffset
;
453 DecompressedImageBuffer
= NULL
;
456 // decompress here if needed
459 if (EfiRomHeader
->CompressionType
> EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
463 if (EfiRomHeader
->CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
464 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**) &Decompress
);
465 if (EFI_ERROR (Status
)) {
469 Status
= Decompress
->GetInfo (
476 if (!EFI_ERROR (Status
)) {
477 DecompressedImageBuffer
= NULL
;
478 DecompressedImageBuffer
= AllocatePool (DestinationSize
);
479 if (DecompressedImageBuffer
!= NULL
) {
480 Scratch
= AllocatePool (ScratchSize
);
481 if (Scratch
!= NULL
) {
482 Status
= Decompress
->Decompress (
486 DecompressedImageBuffer
,
491 if (!EFI_ERROR (Status
)) {
492 ImageBuffer
= DecompressedImageBuffer
;
493 ImageLength
= DestinationSize
;
497 gBS
->FreePool (Scratch
);
506 // Build Memory Mapped device path node to record the image offset into the PCI Option ROM
508 mPciOptionRomImageDevicePathNodeTemplate
.StartingAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (RomBarOffset
- (UINT8
*) RomBar
);
509 mPciOptionRomImageDevicePathNodeTemplate
.EndingAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (RomBarOffset
+ ImageSize
- 1 - (UINT8
*) RomBar
);
510 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, (const EFI_DEVICE_PATH_PROTOCOL
*)&mPciOptionRomImageDevicePathNodeTemplate
);
511 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
514 // load image and start image
516 Status
= gBS
->LoadImage (
518 gPciBusDriverBinding
.DriverBindingHandle
,
519 PciOptionRomImageDevicePath
,
526 // Free the device path after it has been used by LoadImage
528 gBS
->FreePool (PciOptionRomImageDevicePath
);
530 if (!EFI_ERROR (Status
)) {
531 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
532 if (!EFI_ERROR (Status
)) {
533 AddDriver (PciDevice
, ImageHandle
);
534 PciRomAddImageMapping (
536 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
537 PciDevice
->BusNumber
,
538 PciDevice
->DeviceNumber
,
539 PciDevice
->FunctionNumber
,
540 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
541 PciDevice
->PciIo
.RomSize
543 retStatus
= EFI_SUCCESS
;
548 RomBarOffset
= RomBarOffset
+ ImageSize
;
550 RomBarOffset
= RomBarOffset
+ ImageSize
;
553 RomBarOffset
= RomBarOffset
+ ImageSize
;
556 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));