2 PCI Rom supporting funtions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2012, 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
= (UINT64
) ((~AllOnes
) + 1);
313 Load Option Rom image for specified PCI device.
315 @param PciDevice Pci device instance.
316 @param RomBase Base address of Option Rom.
318 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
319 @retval EFI_SUCESS Successfully loaded Option Rom.
324 IN PCI_IO_DEVICE
*PciDevice
,
333 EFI_STATUS RetStatus
;
336 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
337 PCI_DATA_STRUCTURE
*RomPcir
;
340 UINT32 LegacyImageLength
;
345 RomSize
= PciDevice
->RomSize
;
353 // Get the RomBarIndex
359 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
360 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
368 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
371 // Allocate memory for Rom header and PCIR
373 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
374 if (RomHeader
== NULL
) {
375 return EFI_OUT_OF_RESOURCES
;
378 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
379 if (RomPcir
== NULL
) {
380 FreePool (RomHeader
);
381 return EFI_OUT_OF_RESOURCES
;
384 RomBar
= (UINT32
) RomBase
;
389 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
391 RomBarOffset
= RomBar
;
392 RetStatus
= EFI_NOT_FOUND
;
394 LegacyImageLength
= 0;
398 PciDevice
->PciRootBridgeIo
->Mem
.Read (
399 PciDevice
->PciRootBridgeIo
,
402 sizeof (PCI_EXPANSION_ROM_HEADER
),
406 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
407 RomBarOffset
= RomBarOffset
+ 512;
411 RomImageSize
= RomImageSize
+ 512;
417 OffsetPcir
= RomHeader
->PcirOffset
;
419 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
420 // The PCI Data Structure must be DWORD aligned.
422 if (OffsetPcir
== 0 ||
423 (OffsetPcir
& 3) != 0 ||
424 RomImageSize
+ OffsetPcir
+ sizeof (PCI_DATA_STRUCTURE
) > RomSize
) {
427 PciDevice
->PciRootBridgeIo
->Mem
.Read (
428 PciDevice
->PciRootBridgeIo
,
430 RomBarOffset
+ OffsetPcir
,
431 sizeof (PCI_DATA_STRUCTURE
),
435 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
437 if (RomPcir
->Signature
!= PCI_DATA_STRUCTURE_SIGNATURE
) {
440 if (RomImageSize
+ RomPcir
->ImageLength
* 512 > RomSize
) {
443 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
444 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
445 LegacyImageLength
= ((UINT32
)((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
) * 512;
446 } else if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
449 Indicator
= RomPcir
->Indicator
;
450 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
451 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
452 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
455 // Some Legacy Cards do not report the correct ImageLength so used the maximum
456 // of the legacy length and the PCIR Image Length
458 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
459 RomImageSize
= MAX (RomImageSize
, LegacyImageLength
);
462 if (RomImageSize
> 0) {
463 RetStatus
= EFI_SUCCESS
;
464 Image
= AllocatePool ((UINT32
) RomImageSize
);
466 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
467 FreePool (RomHeader
);
469 return EFI_OUT_OF_RESOURCES
;
473 // Copy Rom image into memory
475 PciDevice
->PciRootBridgeIo
->Mem
.Read (
476 PciDevice
->PciRootBridgeIo
,
479 (UINT32
) RomImageSize
,
485 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
487 PciDevice
->HasEfiOpRom
= HasEfiOpRom
;
488 PciDevice
->EmbeddedRom
= TRUE
;
489 PciDevice
->PciIo
.RomSize
= RomImageSize
;
490 PciDevice
->PciIo
.RomImage
= RomInMemory
;
493 // For OpROM read from PCI device:
494 // Add the Rom Image to internal database for later PCI light enumeration
496 PciRomAddImageMapping (
498 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
499 PciDevice
->BusNumber
,
500 PciDevice
->DeviceNumber
,
501 PciDevice
->FunctionNumber
,
502 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
503 PciDevice
->PciIo
.RomSize
507 // Free allocated memory
509 FreePool (RomHeader
);
516 Enable/Disable Option Rom decode.
518 @param PciDevice Pci device instance.
519 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
520 base address for resource range. The legal range for this field is 0..5.
521 @param RomBar Base address of Option Rom.
522 @param Enable Flag for enable/disable decode.
527 IN PCI_IO_DEVICE
*PciDevice
,
528 IN UINT8 RomBarIndex
,
536 EFI_PCI_IO_PROTOCOL
*PciIo
;
538 PciIo
= &PciDevice
->PciIo
;
544 if (IS_PCI_BRIDGE(&PciDevice
->Pci
)) {
548 for (Offset
= 0x10; Offset
<= OffsetMax
; Offset
+= sizeof (UINT32
)) {
549 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
553 // set the Rom base address: now is hardcode
554 // enable its decoder
556 Value32
= RomBar
| 0x1;
559 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
566 // Programe all upstream bridge
568 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
571 // Setting the memory space bit in the function's command register
573 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
578 // disable command register decode to memory
580 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
583 // Destroy the programmed bar in all the upstream bridge.
585 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
588 // disable rom decode
590 Value32
= 0xFFFFFFFE;
593 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
603 Load and start the Option Rom image.
605 @param PciDevice Pci device instance.
607 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
608 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
613 IN PCI_IO_DEVICE
*PciDevice
620 EFI_HANDLE ImageHandle
;
622 EFI_STATUS RetStatus
;
623 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
624 PCI_DATA_STRUCTURE
*Pcir
;
625 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
626 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
633 // Get the Address of the Option Rom image
635 RomBar
= PciDevice
->PciIo
.RomImage
;
636 RomBarOffset
= (UINT8
*) RomBar
;
637 RetStatus
= EFI_NOT_FOUND
;
639 if (RomBar
== NULL
) {
642 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
)->Signature
== PCI_EXPANSION_ROM_HEADER_SIGNATURE
);
645 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
646 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
651 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
652 ASSERT (Pcir
->Signature
== PCI_DATA_STRUCTURE_SIGNATURE
);
653 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
654 Indicator
= Pcir
->Indicator
;
657 // Skip the image if it is not an EFI PCI Option ROM image
659 if (Pcir
->CodeType
!= PCI_CODE_TYPE_EFI_IMAGE
) {
664 // Skip the EFI PCI Option ROM image if its machine type is not supported
666 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader
->EfiMachineType
)) {
671 // Ignore the EFI PCI Option ROM image if it is an EFI application
673 if (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
678 // Create Pci Option Rom Image device path header
680 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
681 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
682 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
683 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
684 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
686 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
687 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
690 // load image and start image
696 Status
= gBS
->LoadImage (
698 gPciBusDriverBinding
.DriverBindingHandle
,
699 PciOptionRomImageDevicePath
,
705 FreePool (PciOptionRomImageDevicePath
);
707 if (!EFI_ERROR (Status
)) {
708 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
709 if (!EFI_ERROR (Status
)) {
710 AddDriver (PciDevice
, ImageHandle
);
711 PciRomAddImageMapping (
713 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
714 PciDevice
->BusNumber
,
715 PciDevice
->DeviceNumber
,
716 PciDevice
->FunctionNumber
,
717 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
718 PciDevice
->PciIo
.RomSize
720 RetStatus
= EFI_SUCCESS
;
725 RomBarOffset
+= ImageSize
;
727 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));