2 PCI Rom supporting funtions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. 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 infor bits.
221 @param PciIoDevice Pci device instance.
223 @retval EFI_NOT_FOUND Pci device has not Option Rom.
224 @retval EFI_SUCCESS Pci device has Option Rom.
229 IN PCI_IO_DEVICE
*PciIoDevice
239 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
241 Bus
= PciIoDevice
->BusNumber
;
242 Device
= PciIoDevice
->DeviceNumber
;
243 Function
= PciIoDevice
->FunctionNumber
;
245 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
248 // Offset is 0x30 if is not ppb
254 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
256 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
264 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
= PciRootBridgeIoWrite (
280 if (EFI_ERROR (Status
)) {
281 return EFI_NOT_FOUND
;
287 Status
= PciRootBridgeIoRead (
295 if (EFI_ERROR (Status
)) {
296 return EFI_NOT_FOUND
;
299 // Bits [1, 10] are reserved
301 AllOnes
&= 0xFFFFF800;
302 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
303 return EFI_NOT_FOUND
;
306 PciIoDevice
->RomSize
= (UINT64
) ((~AllOnes
) + 1);
311 Check if the RomImage contains EFI Images.
313 @param RomImage The ROM address of Image for check.
314 @param RomSize Size of ROM for check.
316 @retval TRUE ROM contain EFI Image.
317 @retval FALSE ROM not contain EFI Image.
326 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
327 PCI_DATA_STRUCTURE
*RomPcir
;
331 RomHeader
= RomImage
;
333 while ((UINT8
*) RomHeader
< (UINT8
*) RomImage
+ RomSize
) {
334 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
338 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ 512);
344 RomPcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) RomHeader
+ RomHeader
->PcirOffset
);
346 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
350 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ RomPcir
->Length
* 512);
358 Load Option Rom image for specified PCI device.
360 @param PciDevice Pci device instance.
361 @param RomBase Base address of Option Rom.
363 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
364 @retval EFI_SUCESS Successfully loaded Option Rom.
369 IN PCI_IO_DEVICE
*PciDevice
,
378 EFI_STATUS RetStatus
;
381 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
382 PCI_DATA_STRUCTURE
*RomPcir
;
388 RomSize
= PciDevice
->RomSize
;
396 // Get the RomBarIndex
402 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
403 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
411 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
414 // Allocate memory for Rom header and PCIR
416 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
417 if (RomHeader
== NULL
) {
418 return EFI_OUT_OF_RESOURCES
;
421 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
422 if (RomPcir
== NULL
) {
423 FreePool (RomHeader
);
424 return EFI_OUT_OF_RESOURCES
;
427 RomBar
= (UINT32
) RomBase
;
432 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
434 RomBarOffset
= RomBar
;
435 RetStatus
= EFI_NOT_FOUND
;
439 PciDevice
->PciRootBridgeIo
->Mem
.Read (
440 PciDevice
->PciRootBridgeIo
,
443 sizeof (PCI_EXPANSION_ROM_HEADER
),
447 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
448 RomBarOffset
= RomBarOffset
+ 512;
452 RomImageSize
= RomImageSize
+ 512;
458 OffsetPcir
= RomHeader
->PcirOffset
;
459 PciDevice
->PciRootBridgeIo
->Mem
.Read (
460 PciDevice
->PciRootBridgeIo
,
462 RomBarOffset
+ OffsetPcir
,
463 sizeof (PCI_DATA_STRUCTURE
),
466 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
467 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
469 Indicator
= RomPcir
->Indicator
;
470 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
471 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
472 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
475 // Some Legacy Cards do not report the correct ImageLength so used the maximum
476 // of the legacy length and the PCIR Image Length
478 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
479 RomImageSize
= MAX(RomImageSize
, (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
* 512));
482 if (RomImageSize
> 0) {
483 RetStatus
= EFI_SUCCESS
;
484 Image
= AllocatePool ((UINT32
) RomImageSize
);
486 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
487 FreePool (RomHeader
);
489 return EFI_OUT_OF_RESOURCES
;
493 // Copy Rom image into memory
495 PciDevice
->PciRootBridgeIo
->Mem
.Read (
496 PciDevice
->PciRootBridgeIo
,
499 (UINT32
) RomImageSize
,
505 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
507 PciDevice
->PciIo
.RomSize
= RomImageSize
;
508 PciDevice
->PciIo
.RomImage
= RomInMemory
;
511 // For OpROM read from PCI device:
512 // Add the Rom Image to internal database for later PCI light enumeration
514 PciRomAddImageMapping (
516 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
517 PciDevice
->BusNumber
,
518 PciDevice
->DeviceNumber
,
519 PciDevice
->FunctionNumber
,
520 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
521 PciDevice
->PciIo
.RomSize
525 // Free allocated memory
527 FreePool (RomHeader
);
534 Enable/Disable Option Rom decode.
536 @param PciDevice Pci device instance.
537 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
538 base address for resource range. The legal range for this field is 0..5.
539 @param RomBar Base address of Option Rom.
540 @param Enable Flag for enable/disable decode.
545 IN PCI_IO_DEVICE
*PciDevice
,
546 IN UINT8 RomBarIndex
,
553 EFI_PCI_IO_PROTOCOL
*PciIo
;
555 PciIo
= &PciDevice
->PciIo
;
560 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
561 PciIoWrite (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
565 // set the Rom base address: now is hardcode
566 // enable its decoder
568 Value32
= RomBar
| 0x1;
571 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
578 // Programe all upstream bridge
580 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
583 // Setting the memory space bit in the function's command register
585 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
590 // disable command register decode to memory
592 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
595 // Destroy the programmed bar in all the upstream bridge.
597 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
600 // disable rom decode
602 Value32
= 0xFFFFFFFE;
605 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
615 Load and start the Option Rom image.
617 @param PciDevice Pci device instance.
619 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
620 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
625 IN PCI_IO_DEVICE
*PciDevice
632 EFI_HANDLE ImageHandle
;
634 EFI_STATUS RetStatus
;
636 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
637 PCI_DATA_STRUCTURE
*Pcir
;
638 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
639 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
646 // Get the Address of the Option Rom image
648 RomBar
= PciDevice
->PciIo
.RomImage
;
649 RomBarOffset
= (UINT8
*) RomBar
;
650 RetStatus
= EFI_NOT_FOUND
;
654 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
655 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
665 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
666 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
667 Indicator
= Pcir
->Indicator
;
670 // Create Pci Option Rom Image device path header
672 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
673 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
674 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
675 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
676 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
678 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
679 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
682 // load image and start image
686 Status
= EFI_SUCCESS
;
689 if (!EFI_ERROR (Status
)) {
690 Status
= gBS
->LoadImage (
692 gPciBusDriverBinding
.DriverBindingHandle
,
693 PciOptionRomImageDevicePath
,
701 // load image and start image
703 if (!EFI_ERROR (Status
)) {
704 Status
= gBS
->LoadImage (
706 gPciBusDriverBinding
.DriverBindingHandle
,
707 PciOptionRomImageDevicePath
,
714 FreePool (PciOptionRomImageDevicePath
);
716 if (!EFI_ERROR (Status
)) {
717 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
718 if (!EFI_ERROR (Status
)) {
719 AddDriver (PciDevice
, ImageHandle
);
720 PciRomAddImageMapping (
722 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
723 PciDevice
->BusNumber
,
724 PciDevice
->DeviceNumber
,
725 PciDevice
->FunctionNumber
,
726 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
727 PciDevice
->PciIo
.RomSize
729 RetStatus
= EFI_SUCCESS
;
733 RomBarOffset
+= ImageSize
;
735 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));