2 PCI Rom supporting funtions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Load the EFI Image from Option ROM
20 @param PciIoDevice PCI IO device instance.
21 @param FilePath The file path of the EFI Image
22 @param BufferSize On input the size of Buffer in bytes. On output with a return
23 code of EFI_SUCCESS, the amount of data transferred to Buffer.
24 On output with a return code of EFI_BUFFER_TOO_SMALL,
25 the size of Buffer required to retrieve the requested file.
26 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
27 then no the size of the requested file is returned in BufferSize.
29 @retval EFI_SUCCESS The file was loaded.
30 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
32 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
33 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
34 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
35 BufferSize has been updated with the size needed to complete the request.
39 IN PCI_IO_DEVICE
*PciIoDevice
,
40 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
41 IN OUT UINTN
*BufferSize
,
42 IN VOID
*Buffer OPTIONAL
46 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*EfiOpRomImageNode
;
47 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
48 PCI_DATA_STRUCTURE
*Pcir
;
52 UINT32 DestinationSize
;
55 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
57 EfiOpRomImageNode
= (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*) FilePath
;
58 if ((EfiOpRomImageNode
== NULL
) ||
59 (DevicePathType (FilePath
) != MEDIA_DEVICE_PATH
) ||
60 (DevicePathSubType (FilePath
) != MEDIA_RELATIVE_OFFSET_RANGE_DP
) ||
61 (DevicePathNodeLength (FilePath
) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
)) ||
62 (!IsDevicePathEnd (NextDevicePathNode (FilePath
))) ||
63 (EfiOpRomImageNode
->StartingOffset
> EfiOpRomImageNode
->EndingOffset
) ||
64 (EfiOpRomImageNode
->EndingOffset
>= PciIoDevice
->RomSize
) ||
67 return EFI_INVALID_PARAMETER
;
70 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) (
71 (UINT8
*) PciIoDevice
->PciIo
.RomImage
+ EfiOpRomImageNode
->StartingOffset
73 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
78 Pcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) EfiRomHeader
+ EfiRomHeader
->PcirOffset
);
81 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
82 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
) &&
83 ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
84 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) &&
85 (EfiRomHeader
->CompressionType
<= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
)
88 ImageSize
= (UINT32
) EfiRomHeader
->InitializationSize
* 512;
89 ImageBuffer
= (UINT8
*) EfiRomHeader
+ EfiRomHeader
->EfiImageHeaderOffset
;
90 ImageLength
= ImageSize
- EfiRomHeader
->EfiImageHeaderOffset
;
92 if (EfiRomHeader
->CompressionType
!= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
94 // Uncompressed: Copy the EFI Image directly to user's buffer
96 if (Buffer
== NULL
|| *BufferSize
< ImageLength
) {
97 *BufferSize
= ImageLength
;
98 return EFI_BUFFER_TOO_SMALL
;
101 *BufferSize
= ImageLength
;
102 CopyMem (Buffer
, ImageBuffer
, ImageLength
);
107 // Compressed: Uncompress before copying
109 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**) &Decompress
);
110 if (EFI_ERROR (Status
)) {
111 return EFI_DEVICE_ERROR
;
113 Status
= Decompress
->GetInfo (
120 if (EFI_ERROR (Status
)) {
121 return EFI_DEVICE_ERROR
;
124 if (Buffer
== NULL
|| *BufferSize
< DestinationSize
) {
125 *BufferSize
= DestinationSize
;
126 return EFI_BUFFER_TOO_SMALL
;
129 *BufferSize
= DestinationSize
;
130 Scratch
= AllocatePool (ScratchSize
);
131 if (Scratch
== NULL
) {
132 return EFI_DEVICE_ERROR
;
135 Status
= Decompress
->Decompress (
146 if (EFI_ERROR (Status
)) {
147 return EFI_DEVICE_ERROR
;
153 return EFI_NOT_FOUND
;
157 Initialize a PCI LoadFile2 instance.
159 @param PciIoDevice PCI IO Device.
163 InitializePciLoadFile2 (
164 IN PCI_IO_DEVICE
*PciIoDevice
167 PciIoDevice
->LoadFile2
.LoadFile
= LoadFile2
;
171 Causes the driver to load a specified file.
173 @param This Indicates a pointer to the calling context.
174 @param FilePath The device specific path of the file to load.
175 @param BootPolicy Should always be FALSE.
176 @param BufferSize On input the size of Buffer in bytes. On output with a return
177 code of EFI_SUCCESS, the amount of data transferred to Buffer.
178 On output with a return code of EFI_BUFFER_TOO_SMALL,
179 the size of Buffer required to retrieve the requested file.
180 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
181 then no the size of the requested file is returned in BufferSize.
183 @retval EFI_SUCCESS The file was loaded.
184 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
185 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
187 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
188 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
189 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
190 BufferSize has been updated with the size needed to complete the request.
196 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
197 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
198 IN BOOLEAN BootPolicy
,
199 IN OUT UINTN
*BufferSize
,
200 IN VOID
*Buffer OPTIONAL
203 PCI_IO_DEVICE
*PciIoDevice
;
206 return EFI_UNSUPPORTED
;
208 PciIoDevice
= PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This
);
210 return LocalLoadFile2 (
219 Get Pci device's oprom information.
221 @param PciIoDevice Input Pci device instance.
222 Output Pci device instance with updated OptionRom size.
224 @retval EFI_NOT_FOUND Pci device has not Option Rom.
225 @retval EFI_SUCCESS Pci device has Option Rom.
230 IN OUT PCI_IO_DEVICE
*PciIoDevice
240 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
242 Bus
= PciIoDevice
->BusNumber
;
243 Device
= PciIoDevice
->DeviceNumber
;
244 Function
= PciIoDevice
->FunctionNumber
;
246 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
249 // Offset is 0x30 if is not ppb
255 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
257 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
261 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
264 // The bit0 is 0 to prevent the enabling of the Rom address decoder
266 AllOnes
= 0xfffffffe;
267 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
269 Status
= PciRootBridgeIo
->Pci
.Write (
276 if (EFI_ERROR (Status
)) {
277 return EFI_NOT_FOUND
;
283 Status
= PciRootBridgeIo
->Pci
.Read(
290 if (EFI_ERROR (Status
)) {
291 return EFI_NOT_FOUND
;
295 // Bits [1, 10] are reserved
297 AllOnes
&= 0xFFFFF800;
298 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
299 return EFI_NOT_FOUND
;
302 PciIoDevice
->RomSize
= (UINT64
) ((~AllOnes
) + 1);
307 Check if the RomImage contains EFI Images.
309 @param RomImage The ROM address of Image for check.
310 @param RomSize Size of ROM for check.
312 @retval TRUE ROM contain EFI Image.
313 @retval FALSE ROM not contain EFI Image.
322 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
323 PCI_DATA_STRUCTURE
*RomPcir
;
327 RomHeader
= RomImage
;
329 while ((UINT8
*) RomHeader
< (UINT8
*) RomImage
+ RomSize
) {
330 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
334 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ 512);
340 RomPcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) RomHeader
+ RomHeader
->PcirOffset
);
342 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
346 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ RomPcir
->Length
* 512);
354 Load Option Rom image for specified PCI device.
356 @param PciDevice Pci device instance.
357 @param RomBase Base address of Option Rom.
359 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
360 @retval EFI_SUCESS Successfully loaded Option Rom.
365 IN PCI_IO_DEVICE
*PciDevice
,
374 EFI_STATUS RetStatus
;
377 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
378 PCI_DATA_STRUCTURE
*RomPcir
;
384 RomSize
= PciDevice
->RomSize
;
392 // Get the RomBarIndex
398 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
399 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
407 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
410 // Allocate memory for Rom header and PCIR
412 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
413 if (RomHeader
== NULL
) {
414 return EFI_OUT_OF_RESOURCES
;
417 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
418 if (RomPcir
== NULL
) {
419 FreePool (RomHeader
);
420 return EFI_OUT_OF_RESOURCES
;
423 RomBar
= (UINT32
) RomBase
;
428 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
430 RomBarOffset
= RomBar
;
431 RetStatus
= EFI_NOT_FOUND
;
435 PciDevice
->PciRootBridgeIo
->Mem
.Read (
436 PciDevice
->PciRootBridgeIo
,
439 sizeof (PCI_EXPANSION_ROM_HEADER
),
443 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
444 RomBarOffset
= RomBarOffset
+ 512;
448 RomImageSize
= RomImageSize
+ 512;
454 OffsetPcir
= RomHeader
->PcirOffset
;
455 PciDevice
->PciRootBridgeIo
->Mem
.Read (
456 PciDevice
->PciRootBridgeIo
,
458 RomBarOffset
+ OffsetPcir
,
459 sizeof (PCI_DATA_STRUCTURE
),
462 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
463 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
465 Indicator
= RomPcir
->Indicator
;
466 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
467 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
468 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
471 // Some Legacy Cards do not report the correct ImageLength so used the maximum
472 // of the legacy length and the PCIR Image Length
474 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
475 RomImageSize
= MAX(RomImageSize
, (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
* 512));
478 if (RomImageSize
> 0) {
479 RetStatus
= EFI_SUCCESS
;
480 Image
= AllocatePool ((UINT32
) RomImageSize
);
482 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
483 FreePool (RomHeader
);
485 return EFI_OUT_OF_RESOURCES
;
489 // Copy Rom image into memory
491 PciDevice
->PciRootBridgeIo
->Mem
.Read (
492 PciDevice
->PciRootBridgeIo
,
495 (UINT32
) RomImageSize
,
501 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
503 PciDevice
->EmbeddedRom
= TRUE
;
504 PciDevice
->PciIo
.RomSize
= RomImageSize
;
505 PciDevice
->PciIo
.RomImage
= RomInMemory
;
508 // For OpROM read from PCI device:
509 // Add the Rom Image to internal database for later PCI light enumeration
511 PciRomAddImageMapping (
513 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
514 PciDevice
->BusNumber
,
515 PciDevice
->DeviceNumber
,
516 PciDevice
->FunctionNumber
,
517 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
518 PciDevice
->PciIo
.RomSize
522 // Free allocated memory
524 FreePool (RomHeader
);
531 Enable/Disable Option Rom decode.
533 @param PciDevice Pci device instance.
534 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
535 base address for resource range. The legal range for this field is 0..5.
536 @param RomBar Base address of Option Rom.
537 @param Enable Flag for enable/disable decode.
542 IN PCI_IO_DEVICE
*PciDevice
,
543 IN UINT8 RomBarIndex
,
551 EFI_PCI_IO_PROTOCOL
*PciIo
;
553 PciIo
= &PciDevice
->PciIo
;
559 if (IS_PCI_BRIDGE(&PciDevice
->Pci
)) {
563 for (Offset
= 0x10; Offset
<= OffsetMax
; Offset
+= sizeof (UINT32
)) {
564 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
568 // set the Rom base address: now is hardcode
569 // enable its decoder
571 Value32
= RomBar
| 0x1;
574 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
581 // Programe all upstream bridge
583 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
586 // Setting the memory space bit in the function's command register
588 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
593 // disable command register decode to memory
595 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
598 // Destroy the programmed bar in all the upstream bridge.
600 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
603 // disable rom decode
605 Value32
= 0xFFFFFFFE;
608 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
618 Load and start the Option Rom image.
620 @param PciDevice Pci device instance.
622 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
623 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
628 IN PCI_IO_DEVICE
*PciDevice
635 EFI_HANDLE ImageHandle
;
637 EFI_STATUS RetStatus
;
639 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
640 PCI_DATA_STRUCTURE
*Pcir
;
641 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
642 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
649 // Get the Address of the Option Rom image
651 RomBar
= PciDevice
->PciIo
.RomImage
;
652 RomBarOffset
= (UINT8
*) RomBar
;
653 RetStatus
= EFI_NOT_FOUND
;
657 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
658 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
668 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
669 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
670 Indicator
= Pcir
->Indicator
;
673 // Skip the image if it is not an EFI PCI Option ROM image
675 if (Pcir
->CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
680 // Skip the EFI PCI Option ROM image if its machine type is not supported
682 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader
->EfiMachineType
)) {
687 // Ignore the EFI PCI Option ROM image if it is an EFI application
689 if (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
694 // Create Pci Option Rom Image device path header
696 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
697 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
698 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
699 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
700 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
702 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
703 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
706 // load image and start image
712 Status
= gBS
->LoadImage (
714 gPciBusDriverBinding
.DriverBindingHandle
,
715 PciOptionRomImageDevicePath
,
721 FreePool (PciOptionRomImageDevicePath
);
723 if (!EFI_ERROR (Status
)) {
724 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
725 if (!EFI_ERROR (Status
)) {
726 AddDriver (PciDevice
, ImageHandle
);
727 PciRomAddImageMapping (
729 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
730 PciDevice
->BusNumber
,
731 PciDevice
->DeviceNumber
,
732 PciDevice
->FunctionNumber
,
733 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
734 PciDevice
->PciIo
.RomSize
736 RetStatus
= EFI_SUCCESS
;
741 RomBarOffset
+= ImageSize
;
743 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));