2 PCI Rom supporting funtions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 Load the EFI Image from Option ROM
14 @param PciIoDevice PCI IO device instance.
15 @param FilePath The file path of the EFI Image
16 @param BufferSize On input the size of Buffer in bytes. On output with a return
17 code of EFI_SUCCESS, the amount of data transferred to Buffer.
18 On output with a return code of EFI_BUFFER_TOO_SMALL,
19 the size of Buffer required to retrieve the requested file.
20 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
21 then no the size of the requested file is returned in BufferSize.
23 @retval EFI_SUCCESS The file was loaded.
24 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
26 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
27 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
28 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
29 BufferSize has been updated with the size needed to complete the request.
33 IN PCI_IO_DEVICE
*PciIoDevice
,
34 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
35 IN OUT UINTN
*BufferSize
,
36 IN VOID
*Buffer OPTIONAL
40 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*EfiOpRomImageNode
;
41 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
42 PCI_DATA_STRUCTURE
*Pcir
;
46 UINT32 DestinationSize
;
49 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
50 UINT32 InitializationSize
;
52 EfiOpRomImageNode
= (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*)FilePath
;
53 if ((EfiOpRomImageNode
== NULL
) ||
54 (DevicePathType (FilePath
) != MEDIA_DEVICE_PATH
) ||
55 (DevicePathSubType (FilePath
) != MEDIA_RELATIVE_OFFSET_RANGE_DP
) ||
56 (DevicePathNodeLength (FilePath
) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
)) ||
57 (!IsDevicePathEnd (NextDevicePathNode (FilePath
))) ||
58 (EfiOpRomImageNode
->StartingOffset
> EfiOpRomImageNode
->EndingOffset
) ||
59 (EfiOpRomImageNode
->EndingOffset
>= PciIoDevice
->RomSize
) ||
63 return EFI_INVALID_PARAMETER
;
66 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*)(
67 (UINT8
*)PciIoDevice
->PciIo
.RomImage
+ EfiOpRomImageNode
->StartingOffset
69 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
73 Pcir
= (PCI_DATA_STRUCTURE
*)((UINT8
*)EfiRomHeader
+ EfiRomHeader
->PcirOffset
);
74 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
76 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
77 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
) &&
78 ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
79 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) &&
80 (EfiRomHeader
->CompressionType
<= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
)
83 ImageSize
= Pcir
->ImageLength
* 512;
84 InitializationSize
= (UINT32
)EfiRomHeader
->InitializationSize
* 512;
85 if ((InitializationSize
> ImageSize
) || (EfiRomHeader
->EfiImageHeaderOffset
>= InitializationSize
)) {
89 ImageBuffer
= (UINT8
*)EfiRomHeader
+ EfiRomHeader
->EfiImageHeaderOffset
;
90 ImageLength
= InitializationSize
- 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
);
106 // Compressed: Uncompress before copying
108 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
109 if (EFI_ERROR (Status
)) {
110 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
;
154 return EFI_NOT_FOUND
;
158 Initialize a PCI LoadFile2 instance.
160 @param PciIoDevice PCI IO Device.
164 InitializePciLoadFile2 (
165 IN PCI_IO_DEVICE
*PciIoDevice
168 PciIoDevice
->LoadFile2
.LoadFile
= LoadFile2
;
172 Causes the driver to load a specified file.
174 @param This Indicates a pointer to the calling context.
175 @param FilePath The device specific path of the file to load.
176 @param BootPolicy Should always be FALSE.
177 @param BufferSize On input the size of Buffer in bytes. On output with a return
178 code of EFI_SUCCESS, the amount of data transferred to Buffer.
179 On output with a return code of EFI_BUFFER_TOO_SMALL,
180 the size of Buffer required to retrieve the requested file.
181 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
182 then no the size of the requested file is returned in BufferSize.
184 @retval EFI_SUCCESS The file was loaded.
185 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
186 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
188 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
189 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
190 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
191 BufferSize has been updated with the size needed to complete the request.
197 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
198 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
199 IN BOOLEAN BootPolicy
,
200 IN OUT UINTN
*BufferSize
,
201 IN VOID
*Buffer OPTIONAL
204 PCI_IO_DEVICE
*PciIoDevice
;
207 return EFI_UNSUPPORTED
;
210 PciIoDevice
= PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This
);
212 return LocalLoadFile2 (
221 Get Pci device's oprom information.
223 @param PciIoDevice Input Pci device instance.
224 Output Pci device instance with updated OptionRom size.
226 @retval EFI_NOT_FOUND Pci device has not Option Rom.
227 @retval EFI_SUCCESS Pci device has Option Rom.
232 IN OUT PCI_IO_DEVICE
*PciIoDevice
242 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
244 Bus
= PciIoDevice
->BusNumber
;
245 Device
= PciIoDevice
->DeviceNumber
;
246 Function
= PciIoDevice
->FunctionNumber
;
248 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
251 // Offset is 0x30 if is not ppb
257 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
259 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
263 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
267 // The bit0 is 0 to prevent the enabling of the Rom address decoder
269 AllOnes
= 0xfffffffe;
270 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
272 Status
= PciRootBridgeIo
->Pci
.Write (
279 if (EFI_ERROR (Status
)) {
280 return EFI_NOT_FOUND
;
286 Status
= PciRootBridgeIo
->Pci
.Read (
293 if (EFI_ERROR (Status
)) {
294 return EFI_NOT_FOUND
;
298 // Bits [1, 10] are reserved
300 AllOnes
&= 0xFFFFF800;
301 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
302 return EFI_NOT_FOUND
;
305 PciIoDevice
->RomSize
= (~AllOnes
) + 1;
310 Check if the RomImage contains EFI Images.
312 @param RomImage The ROM address of Image for check.
313 @param RomSize Size of ROM for check.
315 @retval TRUE ROM contain EFI Image.
316 @retval FALSE ROM not contain EFI Image.
325 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
326 PCI_DATA_STRUCTURE
*RomPcir
;
330 RomHeader
= RomImage
;
331 if (RomHeader
== NULL
) {
336 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
337 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*)((UINT8
*)RomHeader
+ 512);
342 // The PCI Data Structure must be DWORD aligned.
344 if ((RomHeader
->PcirOffset
== 0) ||
345 ((RomHeader
->PcirOffset
& 3) != 0) ||
346 ((UINT8
*)RomHeader
+ RomHeader
->PcirOffset
+ sizeof (PCI_DATA_STRUCTURE
) > (UINT8
*)RomImage
+ RomSize
))
351 RomPcir
= (PCI_DATA_STRUCTURE
*)((UINT8
*)RomHeader
+ RomHeader
->PcirOffset
);
352 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
356 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
360 Indicator
= RomPcir
->Indicator
;
361 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*)((UINT8
*)RomHeader
+ RomPcir
->ImageLength
* 512);
362 } while (((UINT8
*)RomHeader
< (UINT8
*)RomImage
+ RomSize
) && ((Indicator
& 0x80) == 0x00));
368 Load Option Rom image for specified PCI device.
370 @param PciDevice Pci device instance.
371 @param RomBase Base address of Option Rom.
373 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
374 @retval EFI_SUCESS Successfully loaded Option Rom.
379 IN PCI_IO_DEVICE
*PciDevice
,
388 EFI_STATUS RetStatus
;
391 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
392 PCI_DATA_STRUCTURE
*RomPcir
;
395 UINT32 LegacyImageLength
;
399 RomSize
= PciDevice
->RomSize
;
407 // Get the RomBarIndex
413 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
414 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
422 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
426 // Allocate memory for Rom header and PCIR
428 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
429 if (RomHeader
== NULL
) {
430 return EFI_OUT_OF_RESOURCES
;
433 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
434 if (RomPcir
== NULL
) {
435 FreePool (RomHeader
);
436 return EFI_OUT_OF_RESOURCES
;
439 RomBar
= (UINT32
)RomBase
;
444 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
446 RomBarOffset
= RomBar
;
447 RetStatus
= EFI_NOT_FOUND
;
449 LegacyImageLength
= 0;
452 PciDevice
->PciRootBridgeIo
->Mem
.Read (
453 PciDevice
->PciRootBridgeIo
,
456 sizeof (PCI_EXPANSION_ROM_HEADER
),
460 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
461 RomBarOffset
= RomBarOffset
+ 512;
465 RomImageSize
= RomImageSize
+ 512;
471 OffsetPcir
= RomHeader
->PcirOffset
;
473 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
474 // The PCI Data Structure must be DWORD aligned.
476 if ((OffsetPcir
== 0) ||
477 ((OffsetPcir
& 3) != 0) ||
478 (RomImageSize
+ OffsetPcir
+ sizeof (PCI_DATA_STRUCTURE
) > RomSize
))
483 PciDevice
->PciRootBridgeIo
->Mem
.Read (
484 PciDevice
->PciRootBridgeIo
,
486 RomBarOffset
+ OffsetPcir
,
487 sizeof (PCI_DATA_STRUCTURE
),
491 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
493 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
497 if (RomImageSize
+ RomPcir
->ImageLength
* 512 > RomSize
) {
501 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
502 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
503 LegacyImageLength
= ((UINT32
)((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
) * 512;
506 Indicator
= RomPcir
->Indicator
;
507 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
508 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
509 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
512 // Some Legacy Cards do not report the correct ImageLength so used the maximum
513 // of the legacy length and the PCIR Image Length
515 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
516 RomImageSize
= MAX (RomImageSize
, LegacyImageLength
);
519 if (RomImageSize
> 0) {
520 RetStatus
= EFI_SUCCESS
;
521 Image
= AllocatePool ((UINT32
)RomImageSize
);
523 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
524 FreePool (RomHeader
);
526 return EFI_OUT_OF_RESOURCES
;
530 // Copy Rom image into memory
532 PciDevice
->PciRootBridgeIo
->Mem
.Read (
533 PciDevice
->PciRootBridgeIo
,
536 (UINT32
)RomImageSize
/sizeof (UINT32
),
542 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
544 PciDevice
->EmbeddedRom
= TRUE
;
545 PciDevice
->PciIo
.RomSize
= RomImageSize
;
546 PciDevice
->PciIo
.RomImage
= RomInMemory
;
549 // For OpROM read from PCI device:
550 // Add the Rom Image to internal database for later PCI light enumeration
552 PciRomAddImageMapping (
554 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
555 PciDevice
->BusNumber
,
556 PciDevice
->DeviceNumber
,
557 PciDevice
->FunctionNumber
,
558 PciDevice
->PciIo
.RomImage
,
559 PciDevice
->PciIo
.RomSize
563 // Free allocated memory
565 FreePool (RomHeader
);
572 Enable/Disable Option Rom decode.
574 @param PciDevice Pci device instance.
575 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
576 base address for resource range. The legal range for this field is 0..5.
577 @param RomBar Base address of Option Rom.
578 @param Enable Flag for enable/disable decode.
583 IN PCI_IO_DEVICE
*PciDevice
,
584 IN UINT8 RomBarIndex
,
590 EFI_PCI_IO_PROTOCOL
*PciIo
;
592 PciIo
= &PciDevice
->PciIo
;
595 // set the Rom base address: now is hardcode
596 // enable its decoder
598 Value32
= RomBar
| 0x1;
601 (EFI_PCI_IO_PROTOCOL_WIDTH
)EfiPciWidthUint32
,
608 // Programe all upstream bridge
610 ProgramUpstreamBridgeForRom (PciDevice
, RomBar
, TRUE
);
613 // Setting the memory space bit in the function's command register
615 PCI_ENABLE_COMMAND_REGISTER (PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
618 // disable command register decode to memory
620 PCI_DISABLE_COMMAND_REGISTER (PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
623 // Destroy the programmed bar in all the upstream bridge.
625 ProgramUpstreamBridgeForRom (PciDevice
, RomBar
, FALSE
);
628 // disable rom decode
630 Value32
= 0xFFFFFFFE;
633 (EFI_PCI_IO_PROTOCOL_WIDTH
)EfiPciWidthUint32
,
642 Load and start the Option Rom image.
644 @param PciDevice Pci device instance.
646 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
647 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
652 IN PCI_IO_DEVICE
*PciDevice
659 EFI_HANDLE ImageHandle
;
661 EFI_STATUS RetStatus
;
662 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
663 PCI_DATA_STRUCTURE
*Pcir
;
664 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
665 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
672 // Get the Address of the Option Rom image
674 RomBar
= PciDevice
->PciIo
.RomImage
;
675 RomBarOffset
= (UINT8
*)RomBar
;
676 RetStatus
= EFI_NOT_FOUND
;
678 if (RomBar
== NULL
) {
682 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER
*)RomBarOffset
)->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
);
685 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*)RomBarOffset
;
686 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
691 Pcir
= (PCI_DATA_STRUCTURE
*)(RomBarOffset
+ EfiRomHeader
->PcirOffset
);
692 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
693 ImageSize
= (UINT32
)(Pcir
->ImageLength
* 512);
694 Indicator
= Pcir
->Indicator
;
697 // Skip the image if it is not an EFI PCI Option ROM image
699 if (Pcir
->CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
704 // Ignore the EFI PCI Option ROM image if it is an EFI application
706 if (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
711 // Create Pci Option Rom Image device path header
713 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
714 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
715 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
716 EfiOpRomImageNode
.StartingOffset
= (UINTN
)RomBarOffset
- (UINTN
)RomBar
;
717 EfiOpRomImageNode
.EndingOffset
= (UINTN
)RomBarOffset
+ ImageSize
- 1 - (UINTN
)RomBar
;
719 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
720 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
723 // load image and start image
729 Status
= gBS
->LoadImage (
731 gPciBusDriverBinding
.DriverBindingHandle
,
732 PciOptionRomImageDevicePath
,
737 if (EFI_ERROR (Status
)) {
739 // Record the Option ROM Image device path when LoadImage fails.
740 // PciOverride.GetDriver() will try to look for the Image Handle using the device path later.
742 AddDriver (PciDevice
, NULL
, PciOptionRomImageDevicePath
);
744 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
745 if (!EFI_ERROR (Status
)) {
747 // Record the Option ROM Image Handle
749 AddDriver (PciDevice
, ImageHandle
, NULL
);
750 PciRomAddImageMapping (
752 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
753 PciDevice
->BusNumber
,
754 PciDevice
->DeviceNumber
,
755 PciDevice
->FunctionNumber
,
756 PciDevice
->PciIo
.RomImage
,
757 PciDevice
->PciIo
.RomSize
759 RetStatus
= EFI_SUCCESS
;
763 FreePool (PciOptionRomImageDevicePath
);
766 RomBarOffset
+= ImageSize
;
767 } while (((Indicator
& 0x80) == 0x00) && (((UINTN
)RomBarOffset
- (UINTN
)RomBar
) < PciDevice
->RomSize
));