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
) ||
62 return EFI_INVALID_PARAMETER
;
65 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) (
66 (UINT8
*) PciIoDevice
->PciIo
.RomImage
+ EfiOpRomImageNode
->StartingOffset
68 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
);
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
= (~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
;
328 if (RomHeader
== NULL
) {
333 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
334 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ 512);
339 // The PCI Data Structure must be DWORD aligned.
341 if (RomHeader
->PcirOffset
== 0 ||
342 (RomHeader
->PcirOffset
& 3) != 0 ||
343 (UINT8
*) RomHeader
+ RomHeader
->PcirOffset
+ sizeof (PCI_DATA_STRUCTURE
) > (UINT8
*) RomImage
+ RomSize
) {
347 RomPcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) RomHeader
+ RomHeader
->PcirOffset
);
348 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
352 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
356 Indicator
= RomPcir
->Indicator
;
357 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ RomPcir
->ImageLength
* 512);
358 } while (((UINT8
*) RomHeader
< (UINT8
*) RomImage
+ RomSize
) && ((Indicator
& 0x80) == 0x00));
364 Load Option Rom image for specified PCI device.
366 @param PciDevice Pci device instance.
367 @param RomBase Base address of Option Rom.
369 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
370 @retval EFI_SUCESS Successfully loaded Option Rom.
375 IN PCI_IO_DEVICE
*PciDevice
,
384 EFI_STATUS RetStatus
;
387 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
388 PCI_DATA_STRUCTURE
*RomPcir
;
391 UINT32 LegacyImageLength
;
395 RomSize
= PciDevice
->RomSize
;
403 // Get the RomBarIndex
409 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
410 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
418 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
421 // Allocate memory for Rom header and PCIR
423 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
424 if (RomHeader
== NULL
) {
425 return EFI_OUT_OF_RESOURCES
;
428 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
429 if (RomPcir
== NULL
) {
430 FreePool (RomHeader
);
431 return EFI_OUT_OF_RESOURCES
;
434 RomBar
= (UINT32
) RomBase
;
439 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
441 RomBarOffset
= RomBar
;
442 RetStatus
= EFI_NOT_FOUND
;
444 LegacyImageLength
= 0;
447 PciDevice
->PciRootBridgeIo
->Mem
.Read (
448 PciDevice
->PciRootBridgeIo
,
451 sizeof (PCI_EXPANSION_ROM_HEADER
),
455 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
456 RomBarOffset
= RomBarOffset
+ 512;
460 RomImageSize
= RomImageSize
+ 512;
466 OffsetPcir
= RomHeader
->PcirOffset
;
468 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
469 // The PCI Data Structure must be DWORD aligned.
471 if (OffsetPcir
== 0 ||
472 (OffsetPcir
& 3) != 0 ||
473 RomImageSize
+ OffsetPcir
+ sizeof (PCI_DATA_STRUCTURE
) > RomSize
) {
476 PciDevice
->PciRootBridgeIo
->Mem
.Read (
477 PciDevice
->PciRootBridgeIo
,
479 RomBarOffset
+ OffsetPcir
,
480 sizeof (PCI_DATA_STRUCTURE
),
484 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
486 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
489 if (RomImageSize
+ RomPcir
->ImageLength
* 512 > RomSize
) {
492 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
493 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
494 LegacyImageLength
= ((UINT32
)((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
) * 512;
496 Indicator
= RomPcir
->Indicator
;
497 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
498 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
499 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
502 // Some Legacy Cards do not report the correct ImageLength so used the maximum
503 // of the legacy length and the PCIR Image Length
505 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
506 RomImageSize
= MAX (RomImageSize
, LegacyImageLength
);
509 if (RomImageSize
> 0) {
510 RetStatus
= EFI_SUCCESS
;
511 Image
= AllocatePool ((UINT32
) RomImageSize
);
513 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
514 FreePool (RomHeader
);
516 return EFI_OUT_OF_RESOURCES
;
520 // Copy Rom image into memory
522 PciDevice
->PciRootBridgeIo
->Mem
.Read (
523 PciDevice
->PciRootBridgeIo
,
526 (UINT32
) RomImageSize
,
532 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
534 PciDevice
->EmbeddedRom
= TRUE
;
535 PciDevice
->PciIo
.RomSize
= RomImageSize
;
536 PciDevice
->PciIo
.RomImage
= RomInMemory
;
539 // For OpROM read from PCI device:
540 // Add the Rom Image to internal database for later PCI light enumeration
542 PciRomAddImageMapping (
544 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
545 PciDevice
->BusNumber
,
546 PciDevice
->DeviceNumber
,
547 PciDevice
->FunctionNumber
,
548 PciDevice
->PciIo
.RomImage
,
549 PciDevice
->PciIo
.RomSize
553 // Free allocated memory
555 FreePool (RomHeader
);
562 Enable/Disable Option Rom decode.
564 @param PciDevice Pci device instance.
565 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
566 base address for resource range. The legal range for this field is 0..5.
567 @param RomBar Base address of Option Rom.
568 @param Enable Flag for enable/disable decode.
573 IN PCI_IO_DEVICE
*PciDevice
,
574 IN UINT8 RomBarIndex
,
580 EFI_PCI_IO_PROTOCOL
*PciIo
;
582 PciIo
= &PciDevice
->PciIo
;
586 // set the Rom base address: now is hardcode
587 // enable its decoder
589 Value32
= RomBar
| 0x1;
592 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
599 // Programe all upstream bridge
601 ProgramUpstreamBridgeForRom (PciDevice
, RomBar
, TRUE
);
604 // Setting the memory space bit in the function's command register
606 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
611 // disable command register decode to memory
613 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
616 // Destroy the programmed bar in all the upstream bridge.
618 ProgramUpstreamBridgeForRom (PciDevice
, RomBar
, FALSE
);
621 // disable rom decode
623 Value32
= 0xFFFFFFFE;
626 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
636 Load and start the Option Rom image.
638 @param PciDevice Pci device instance.
640 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
641 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
646 IN PCI_IO_DEVICE
*PciDevice
653 EFI_HANDLE ImageHandle
;
655 EFI_STATUS RetStatus
;
656 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
657 PCI_DATA_STRUCTURE
*Pcir
;
658 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
659 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
666 // Get the Address of the Option Rom image
668 RomBar
= PciDevice
->PciIo
.RomImage
;
669 RomBarOffset
= (UINT8
*) RomBar
;
670 RetStatus
= EFI_NOT_FOUND
;
672 if (RomBar
== NULL
) {
675 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
)->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
);
678 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
679 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
684 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
685 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
686 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
687 Indicator
= Pcir
->Indicator
;
690 // Skip the image if it is not an EFI PCI Option ROM image
692 if (Pcir
->CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
697 // Ignore the EFI PCI Option ROM image if it is an EFI application
699 if (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
704 // Create Pci Option Rom Image device path header
706 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
707 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
708 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
709 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
710 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
712 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
713 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
716 // load image and start image
722 Status
= gBS
->LoadImage (
724 gPciBusDriverBinding
.DriverBindingHandle
,
725 PciOptionRomImageDevicePath
,
730 if (EFI_ERROR (Status
)) {
732 // Record the Option ROM Image device path when LoadImage fails.
733 // PciOverride.GetDriver() will try to look for the Image Handle using the device path later.
735 AddDriver (PciDevice
, NULL
, PciOptionRomImageDevicePath
);
737 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
738 if (!EFI_ERROR (Status
)) {
740 // Record the Option ROM Image Handle
742 AddDriver (PciDevice
, ImageHandle
, NULL
);
743 PciRomAddImageMapping (
745 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
746 PciDevice
->BusNumber
,
747 PciDevice
->DeviceNumber
,
748 PciDevice
->FunctionNumber
,
749 PciDevice
->PciIo
.RomImage
,
750 PciDevice
->PciIo
.RomSize
752 RetStatus
= EFI_SUCCESS
;
755 FreePool (PciOptionRomImageDevicePath
);
758 RomBarOffset
+= ImageSize
;
760 } while (((Indicator
& 0x80) == 0x00) && (((UINTN
) RomBarOffset
- (UINTN
) RomBar
) < PciDevice
->RomSize
));