2 PCI Rom supporting funtions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2017, 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
;
56 UINT32 InitializationSize
;
58 EfiOpRomImageNode
= (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*) FilePath
;
59 if ((EfiOpRomImageNode
== NULL
) ||
60 (DevicePathType (FilePath
) != MEDIA_DEVICE_PATH
) ||
61 (DevicePathSubType (FilePath
) != MEDIA_RELATIVE_OFFSET_RANGE_DP
) ||
62 (DevicePathNodeLength (FilePath
) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
)) ||
63 (!IsDevicePathEnd (NextDevicePathNode (FilePath
))) ||
64 (EfiOpRomImageNode
->StartingOffset
> EfiOpRomImageNode
->EndingOffset
) ||
65 (EfiOpRomImageNode
->EndingOffset
>= PciIoDevice
->RomSize
) ||
68 return EFI_INVALID_PARAMETER
;
71 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) (
72 (UINT8
*) PciIoDevice
->PciIo
.RomImage
+ EfiOpRomImageNode
->StartingOffset
74 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
79 Pcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) EfiRomHeader
+ EfiRomHeader
->PcirOffset
);
80 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
82 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
83 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
) &&
84 ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
85 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) &&
86 (EfiRomHeader
->CompressionType
<= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
)
89 ImageSize
= Pcir
->ImageLength
* 512;
90 InitializationSize
= (UINT32
) EfiRomHeader
->InitializationSize
* 512;
91 if (InitializationSize
> ImageSize
|| EfiRomHeader
->EfiImageHeaderOffset
>= InitializationSize
) {
95 ImageBuffer
= (UINT8
*) EfiRomHeader
+ EfiRomHeader
->EfiImageHeaderOffset
;
96 ImageLength
= InitializationSize
- EfiRomHeader
->EfiImageHeaderOffset
;
98 if (EfiRomHeader
->CompressionType
!= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
100 // Uncompressed: Copy the EFI Image directly to user's buffer
102 if (Buffer
== NULL
|| *BufferSize
< ImageLength
) {
103 *BufferSize
= ImageLength
;
104 return EFI_BUFFER_TOO_SMALL
;
107 *BufferSize
= ImageLength
;
108 CopyMem (Buffer
, ImageBuffer
, ImageLength
);
113 // Compressed: Uncompress before copying
115 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**) &Decompress
);
116 if (EFI_ERROR (Status
)) {
117 return EFI_DEVICE_ERROR
;
119 Status
= Decompress
->GetInfo (
126 if (EFI_ERROR (Status
)) {
127 return EFI_DEVICE_ERROR
;
130 if (Buffer
== NULL
|| *BufferSize
< DestinationSize
) {
131 *BufferSize
= DestinationSize
;
132 return EFI_BUFFER_TOO_SMALL
;
135 *BufferSize
= DestinationSize
;
136 Scratch
= AllocatePool (ScratchSize
);
137 if (Scratch
== NULL
) {
138 return EFI_DEVICE_ERROR
;
141 Status
= Decompress
->Decompress (
152 if (EFI_ERROR (Status
)) {
153 return EFI_DEVICE_ERROR
;
159 return EFI_NOT_FOUND
;
163 Initialize a PCI LoadFile2 instance.
165 @param PciIoDevice PCI IO Device.
169 InitializePciLoadFile2 (
170 IN PCI_IO_DEVICE
*PciIoDevice
173 PciIoDevice
->LoadFile2
.LoadFile
= LoadFile2
;
177 Causes the driver to load a specified file.
179 @param This Indicates a pointer to the calling context.
180 @param FilePath The device specific path of the file to load.
181 @param BootPolicy Should always be FALSE.
182 @param BufferSize On input the size of Buffer in bytes. On output with a return
183 code of EFI_SUCCESS, the amount of data transferred to Buffer.
184 On output with a return code of EFI_BUFFER_TOO_SMALL,
185 the size of Buffer required to retrieve the requested file.
186 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
187 then no the size of the requested file is returned in BufferSize.
189 @retval EFI_SUCCESS The file was loaded.
190 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
191 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
193 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
194 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
195 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
196 BufferSize has been updated with the size needed to complete the request.
202 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
203 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
204 IN BOOLEAN BootPolicy
,
205 IN OUT UINTN
*BufferSize
,
206 IN VOID
*Buffer OPTIONAL
209 PCI_IO_DEVICE
*PciIoDevice
;
212 return EFI_UNSUPPORTED
;
214 PciIoDevice
= PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This
);
216 return LocalLoadFile2 (
225 Get Pci device's oprom information.
227 @param PciIoDevice Input Pci device instance.
228 Output Pci device instance with updated OptionRom size.
230 @retval EFI_NOT_FOUND Pci device has not Option Rom.
231 @retval EFI_SUCCESS Pci device has Option Rom.
236 IN OUT PCI_IO_DEVICE
*PciIoDevice
246 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
248 Bus
= PciIoDevice
->BusNumber
;
249 Device
= PciIoDevice
->DeviceNumber
;
250 Function
= PciIoDevice
->FunctionNumber
;
252 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
255 // Offset is 0x30 if is not ppb
261 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
263 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
267 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
270 // The bit0 is 0 to prevent the enabling of the Rom address decoder
272 AllOnes
= 0xfffffffe;
273 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
275 Status
= PciRootBridgeIo
->Pci
.Write (
282 if (EFI_ERROR (Status
)) {
283 return EFI_NOT_FOUND
;
289 Status
= PciRootBridgeIo
->Pci
.Read(
296 if (EFI_ERROR (Status
)) {
297 return EFI_NOT_FOUND
;
301 // Bits [1, 10] are reserved
303 AllOnes
&= 0xFFFFF800;
304 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
305 return EFI_NOT_FOUND
;
308 PciIoDevice
->RomSize
= (~AllOnes
) + 1;
313 Check if the RomImage contains EFI Images.
315 @param RomImage The ROM address of Image for check.
316 @param RomSize Size of ROM for check.
318 @retval TRUE ROM contain EFI Image.
319 @retval FALSE ROM not contain EFI Image.
328 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
329 PCI_DATA_STRUCTURE
*RomPcir
;
333 RomHeader
= RomImage
;
334 if (RomHeader
== NULL
) {
339 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
340 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ 512);
345 // The PCI Data Structure must be DWORD aligned.
347 if (RomHeader
->PcirOffset
== 0 ||
348 (RomHeader
->PcirOffset
& 3) != 0 ||
349 (UINT8
*) RomHeader
+ RomHeader
->PcirOffset
+ sizeof (PCI_DATA_STRUCTURE
) > (UINT8
*) RomImage
+ RomSize
) {
353 RomPcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) RomHeader
+ RomHeader
->PcirOffset
);
354 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
358 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
362 Indicator
= RomPcir
->Indicator
;
363 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ RomPcir
->ImageLength
* 512);
364 } while (((UINT8
*) RomHeader
< (UINT8
*) RomImage
+ RomSize
) && ((Indicator
& 0x80) == 0x00));
370 Load Option Rom image for specified PCI device.
372 @param PciDevice Pci device instance.
373 @param RomBase Base address of Option Rom.
375 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
376 @retval EFI_SUCESS Successfully loaded Option Rom.
381 IN PCI_IO_DEVICE
*PciDevice
,
390 EFI_STATUS RetStatus
;
393 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
394 PCI_DATA_STRUCTURE
*RomPcir
;
397 UINT32 LegacyImageLength
;
401 RomSize
= PciDevice
->RomSize
;
409 // Get the RomBarIndex
415 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
416 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
424 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
427 // Allocate memory for Rom header and PCIR
429 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
430 if (RomHeader
== NULL
) {
431 return EFI_OUT_OF_RESOURCES
;
434 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
435 if (RomPcir
== NULL
) {
436 FreePool (RomHeader
);
437 return EFI_OUT_OF_RESOURCES
;
440 RomBar
= (UINT32
) RomBase
;
445 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
447 RomBarOffset
= RomBar
;
448 RetStatus
= EFI_NOT_FOUND
;
450 LegacyImageLength
= 0;
453 PciDevice
->PciRootBridgeIo
->Mem
.Read (
454 PciDevice
->PciRootBridgeIo
,
457 sizeof (PCI_EXPANSION_ROM_HEADER
),
461 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
462 RomBarOffset
= RomBarOffset
+ 512;
466 RomImageSize
= RomImageSize
+ 512;
472 OffsetPcir
= RomHeader
->PcirOffset
;
474 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
475 // The PCI Data Structure must be DWORD aligned.
477 if (OffsetPcir
== 0 ||
478 (OffsetPcir
& 3) != 0 ||
479 RomImageSize
+ OffsetPcir
+ sizeof (PCI_DATA_STRUCTURE
) > RomSize
) {
482 PciDevice
->PciRootBridgeIo
->Mem
.Read (
483 PciDevice
->PciRootBridgeIo
,
485 RomBarOffset
+ OffsetPcir
,
486 sizeof (PCI_DATA_STRUCTURE
),
490 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
492 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
495 if (RomImageSize
+ RomPcir
->ImageLength
* 512 > RomSize
) {
498 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
499 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
500 LegacyImageLength
= ((UINT32
)((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
) * 512;
502 Indicator
= RomPcir
->Indicator
;
503 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
504 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
505 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
508 // Some Legacy Cards do not report the correct ImageLength so used the maximum
509 // of the legacy length and the PCIR Image Length
511 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
512 RomImageSize
= MAX (RomImageSize
, LegacyImageLength
);
515 if (RomImageSize
> 0) {
516 RetStatus
= EFI_SUCCESS
;
517 Image
= AllocatePool ((UINT32
) RomImageSize
);
519 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
520 FreePool (RomHeader
);
522 return EFI_OUT_OF_RESOURCES
;
526 // Copy Rom image into memory
528 PciDevice
->PciRootBridgeIo
->Mem
.Read (
529 PciDevice
->PciRootBridgeIo
,
532 (UINT32
) RomImageSize
,
538 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
540 PciDevice
->EmbeddedRom
= TRUE
;
541 PciDevice
->PciIo
.RomSize
= RomImageSize
;
542 PciDevice
->PciIo
.RomImage
= RomInMemory
;
545 // For OpROM read from PCI device:
546 // Add the Rom Image to internal database for later PCI light enumeration
548 PciRomAddImageMapping (
550 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
551 PciDevice
->BusNumber
,
552 PciDevice
->DeviceNumber
,
553 PciDevice
->FunctionNumber
,
554 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
555 PciDevice
->PciIo
.RomSize
559 // Free allocated memory
561 FreePool (RomHeader
);
568 Enable/Disable Option Rom decode.
570 @param PciDevice Pci device instance.
571 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
572 base address for resource range. The legal range for this field is 0..5.
573 @param RomBar Base address of Option Rom.
574 @param Enable Flag for enable/disable decode.
579 IN PCI_IO_DEVICE
*PciDevice
,
580 IN UINT8 RomBarIndex
,
588 EFI_PCI_IO_PROTOCOL
*PciIo
;
590 PciIo
= &PciDevice
->PciIo
;
596 if (IS_PCI_BRIDGE(&PciDevice
->Pci
)) {
600 for (Offset
= 0x10; Offset
<= OffsetMax
; Offset
+= sizeof (UINT32
)) {
601 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
605 // set the Rom base address: now is hardcode
606 // enable its decoder
608 Value32
= RomBar
| 0x1;
611 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
618 // Programe all upstream bridge
620 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
623 // Setting the memory space bit in the function's command register
625 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
630 // disable command register decode to memory
632 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
635 // Destroy the programmed bar in all the upstream bridge.
637 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
640 // disable rom decode
642 Value32
= 0xFFFFFFFE;
645 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
655 Load and start the Option Rom image.
657 @param PciDevice Pci device instance.
659 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
660 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
665 IN PCI_IO_DEVICE
*PciDevice
672 EFI_HANDLE ImageHandle
;
674 EFI_STATUS RetStatus
;
675 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
676 PCI_DATA_STRUCTURE
*Pcir
;
677 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
678 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
685 // Get the Address of the Option Rom image
687 RomBar
= PciDevice
->PciIo
.RomImage
;
688 RomBarOffset
= (UINT8
*) RomBar
;
689 RetStatus
= EFI_NOT_FOUND
;
691 if (RomBar
== NULL
) {
694 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
)->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
);
697 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
698 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
703 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
704 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
705 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
706 Indicator
= Pcir
->Indicator
;
709 // Skip the image if it is not an EFI PCI Option ROM image
711 if (Pcir
->CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
716 // Skip the EFI PCI Option ROM image if its machine type is not supported
718 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader
->EfiMachineType
)) {
723 // Ignore the EFI PCI Option ROM image if it is an EFI application
725 if (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
730 // Create Pci Option Rom Image device path header
732 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
733 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
734 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
735 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
736 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
738 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
739 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
742 // load image and start image
748 Status
= gBS
->LoadImage (
750 gPciBusDriverBinding
.DriverBindingHandle
,
751 PciOptionRomImageDevicePath
,
757 FreePool (PciOptionRomImageDevicePath
);
759 if (!EFI_ERROR (Status
)) {
760 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
761 if (!EFI_ERROR (Status
)) {
762 AddDriver (PciDevice
, ImageHandle
);
763 PciRomAddImageMapping (
765 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
766 PciDevice
->BusNumber
,
767 PciDevice
->DeviceNumber
,
768 PciDevice
->FunctionNumber
,
769 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
770 PciDevice
->PciIo
.RomSize
772 RetStatus
= EFI_SUCCESS
;
777 RomBarOffset
+= ImageSize
;
779 } while (((Indicator
& 0x80) == 0x00) && (((UINTN
) RomBarOffset
- (UINTN
) RomBar
) < PciDevice
->RomSize
));