3 Copyright (c) 2006 - 2009, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PciResourceSupport.h"
17 #include <IndustryStandard/Pci23.h>
20 Load the EFI Image from Option ROM
22 @param PciIoDevice PCI IO Device
23 @param FilePath The file path of the EFI Image
24 @param BufferSize On input the size of Buffer in bytes. On output with a return
25 code of EFI_SUCCESS, the amount of data transferred to Buffer.
26 On output with a return code of EFI_BUFFER_TOO_SMALL,
27 the size of Buffer required to retrieve the requested file.
28 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
29 then no the size of the requested file is returned in BufferSize.
31 @retval EFI_SUCCESS The file was loaded.
32 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
33 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
34 BufferSize has been updated with the size needed to complete the request.
38 IN PCI_IO_DEVICE
*PciIoDevice
,
39 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
40 IN OUT UINTN
*BufferSize
,
41 IN VOID
*Buffer OPTIONAL
45 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*EfiOpRomImageNode
;
46 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
47 PCI_DATA_STRUCTURE
*Pcir
;
51 UINT32 DestinationSize
;
54 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
56 EfiOpRomImageNode
= (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
*) FilePath
;
57 if ((EfiOpRomImageNode
== NULL
) ||
58 (DevicePathType (FilePath
) != MEDIA_DEVICE_PATH
) ||
59 (DevicePathSubType (FilePath
) != MEDIA_RELATIVE_OFFSET_RANGE_DP
) ||
60 (DevicePathNodeLength (FilePath
) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
)) ||
61 (!IsDevicePathEnd (NextDevicePathNode (FilePath
))) ||
62 (EfiOpRomImageNode
->StartingOffset
> EfiOpRomImageNode
->EndingOffset
) ||
63 (EfiOpRomImageNode
->EndingOffset
>= PciIoDevice
->RomSize
) ||
66 return EFI_INVALID_PARAMETER
;
69 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) (
70 (UINT8
*) PciIoDevice
->PciIo
.RomImage
+ EfiOpRomImageNode
->StartingOffset
72 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
77 Pcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) EfiRomHeader
+ EfiRomHeader
->PcirOffset
);
80 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
81 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
) &&
82 ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
83 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) &&
84 (EfiRomHeader
->CompressionType
<= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
)
87 ImageSize
= (UINT32
) EfiRomHeader
->InitializationSize
* 512;
88 ImageBuffer
= (UINT8
*) EfiRomHeader
+ EfiRomHeader
->EfiImageHeaderOffset
;
89 ImageLength
= ImageSize
- EfiRomHeader
->EfiImageHeaderOffset
;
91 if (EfiRomHeader
->CompressionType
!= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
93 // Uncompressed: Copy the EFI Image directly to user's buffer
95 if (Buffer
== NULL
|| *BufferSize
< ImageLength
) {
96 *BufferSize
= ImageLength
;
97 return EFI_BUFFER_TOO_SMALL
;
100 *BufferSize
= ImageLength
;
101 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
;
112 Status
= Decompress
->GetInfo (
119 if (EFI_ERROR (Status
)) {
120 return EFI_DEVICE_ERROR
;
123 if (Buffer
== NULL
|| *BufferSize
< DestinationSize
) {
124 *BufferSize
= DestinationSize
;
125 return EFI_BUFFER_TOO_SMALL
;
128 *BufferSize
= DestinationSize
;
129 Scratch
= AllocatePool (ScratchSize
);
130 if (Scratch
== NULL
) {
131 return EFI_DEVICE_ERROR
;
134 Status
= Decompress
->Decompress (
145 if (EFI_ERROR (Status
)) {
146 return EFI_DEVICE_ERROR
;
152 return EFI_NOT_FOUND
;
156 Initialize a PCI LoadFile2 instance.
158 @param PciIoDevice PCI IO Device.
162 InitializePciLoadFile2 (
163 PCI_IO_DEVICE
*PciIoDevice
166 PciIoDevice
->LoadFile2
.LoadFile
= LoadFile2
;
170 Causes the driver to load a specified file.
172 @param This Indicates a pointer to the calling context.
173 @param FilePath The device specific path of the file to load.
174 @param BootPolicy Should always be FALSE.
175 @param BufferSize On input the size of Buffer in bytes. On output with a return
176 code of EFI_SUCCESS, the amount of data transferred to Buffer.
177 On output with a return code of EFI_BUFFER_TOO_SMALL,
178 the size of Buffer required to retrieve the requested file.
179 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
180 then no the size of the requested file is returned in BufferSize.
182 @retval EFI_SUCCESS The file was loaded.
183 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
184 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
185 BufferSize has been updated with the size needed to complete the request.
191 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
192 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
193 IN BOOLEAN BootPolicy
,
194 IN OUT UINTN
*BufferSize
,
195 IN VOID
*Buffer OPTIONAL
198 PCI_IO_DEVICE
*PciIoDevice
;
201 return EFI_UNSUPPORTED
;
203 PciIoDevice
= PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This
);
205 return LocalLoadFile2 (
215 // Module global for a template of the PCI option ROM Image Device Path Node
217 MEMMAP_DEVICE_PATH mPciOptionRomImageDevicePathNodeTemplate
= {
219 HARDWARE_DEVICE_PATH
,
222 (UINT8
) (sizeof (MEMMAP_DEVICE_PATH
)),
223 (UINT8
) ((sizeof (MEMMAP_DEVICE_PATH
)) >> 8)
232 Get Pci device's oprom infor bits.
234 @param PciIoDevice Pci device instance
236 @retval EFI_NOT_FOUND Pci device has not oprom
237 @retval EFI_SUCCESS Pci device has oprom
241 IN PCI_IO_DEVICE
*PciIoDevice
251 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
253 Bus
= PciIoDevice
->BusNumber
;
254 Device
= PciIoDevice
->DeviceNumber
;
255 Function
= PciIoDevice
->FunctionNumber
;
257 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
260 // offset is 0x30 if is not ppb
266 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
268 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
276 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
279 // the bit0 is 0 to prevent the enabling of the Rom address decoder
281 AllOnes
= 0xfffffffe;
282 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
284 Status
= PciRootBridgeIoWrite (
292 if (EFI_ERROR (Status
)) {
299 Status
= PciRootBridgeIoRead (
307 if (EFI_ERROR (Status
)) {
311 // Bits [1, 10] are reserved
313 AllOnes
&= 0xFFFFF800;
314 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
315 return EFI_NOT_FOUND
;
318 PciIoDevice
->RomSize
= (UINT64
) ((~AllOnes
) + 1);
324 Check if the RomImage contains EFI Images.
326 @param RomImage The ROM address of Image for check.
327 @param RomSize Size of ROM for check.
329 @retval TRUE ROM contain EFI Image.
330 @retval FALSE ROM not contain EFI Image.
339 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
340 PCI_DATA_STRUCTURE
*RomPcir
;
344 RomHeader
= RomImage
;
346 while ((UINT8
*) RomHeader
< (UINT8
*) RomImage
+ RomSize
) {
347 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
351 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ 512);
357 RomPcir
= (PCI_DATA_STRUCTURE
*) ((UINT8
*) RomHeader
+ RomHeader
->PcirOffset
);
359 if (RomPcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) {
363 RomHeader
= (PCI_EXPANSION_ROM_HEADER
*) ((UINT8
*) RomHeader
+ RomPcir
->Length
* 512);
371 Load option rom image for specified PCI device
373 @param PciDevice Pci device instance
374 @param RomBase Base address of oprom.
376 @retval EFI_OUT_OF_RESOURCES not enough memory to hold image
377 @retval EFI_SUCESS Success
381 IN PCI_IO_DEVICE
*PciDevice
,
390 EFI_STATUS RetStatus
;
393 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
394 PCI_DATA_STRUCTURE
*RomPcir
;
400 RomSize
= PciDevice
->RomSize
;
408 // Get the RomBarIndex
414 RomBarIndex
= PCI_EXPANSION_ROM_BASE
;
415 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
423 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
;
451 PciDevice
->PciRootBridgeIo
->Mem
.Read (
452 PciDevice
->PciRootBridgeIo
,
455 sizeof (PCI_EXPANSION_ROM_HEADER
),
459 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
460 RomBarOffset
= RomBarOffset
+ 512;
464 RomImageSize
= RomImageSize
+ 512;
470 OffsetPcir
= RomHeader
->PcirOffset
;
471 PciDevice
->PciRootBridgeIo
->Mem
.Read (
472 PciDevice
->PciRootBridgeIo
,
474 RomBarOffset
+ OffsetPcir
,
475 sizeof (PCI_DATA_STRUCTURE
),
478 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
479 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
481 Indicator
= RomPcir
->Indicator
;
482 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
483 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
484 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
487 // Some Legacy Cards do not report the correct ImageLength so used the maximum
488 // of the legacy length and the PCIR Image Length
490 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
491 RomImageSize
= MAX(RomImageSize
, (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
* 512));
494 if (RomImageSize
> 0) {
495 RetStatus
= EFI_SUCCESS
;
496 Image
= AllocatePool ((UINT32
) RomImageSize
);
498 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
499 FreePool (RomHeader
);
501 return EFI_OUT_OF_RESOURCES
;
505 // Copy Rom image into memory
507 PciDevice
->PciRootBridgeIo
->Mem
.Read (
508 PciDevice
->PciRootBridgeIo
,
511 (UINT32
) RomImageSize
,
517 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
519 PciDevice
->PciIo
.RomSize
= RomImageSize
;
520 PciDevice
->PciIo
.RomImage
= RomInMemory
;
523 // For OpROM read from PCI device:
524 // Add the Rom Image to internal database for later PCI light enumeration
526 PciRomAddImageMapping (
528 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
529 PciDevice
->BusNumber
,
530 PciDevice
->DeviceNumber
,
531 PciDevice
->FunctionNumber
,
532 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
533 PciDevice
->PciIo
.RomSize
537 // Free allocated memory
539 FreePool (RomHeader
);
546 enable/disable oprom decode
548 @param PciDevice pci device instance
549 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
550 base address for resource range. The legal range for this field is 0..5.
551 @param RomBar Base address of rom
552 @param Enable Flag for enable/disable decode.
554 @retval EFI_SUCCESS Success
558 IN PCI_IO_DEVICE
*PciDevice
,
559 IN UINT8 RomBarIndex
,
566 EFI_PCI_IO_PROTOCOL
*PciIo
;
568 PciIo
= &PciDevice
->PciIo
;
573 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
574 PciIoWrite (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
578 // set the Rom base address: now is hardcode
579 // enable its decoder
581 Value32
= RomBar
| 0x1;
584 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
591 // Programe all upstream bridge
593 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
596 // Setting the memory space bit in the function's command register
598 PCI_ENABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
603 // disable command register decode to memory
605 PCI_DISABLE_COMMAND_REGISTER(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
608 // Destroy the programmed bar in all the upstream bridge.
610 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
613 // disable rom decode
615 Value32
= 0xFFFFFFFE;
618 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
631 Process the oprom image.
633 @param PciDevice Pci device instance
637 PCI_IO_DEVICE
*PciDevice
644 EFI_HANDLE ImageHandle
;
646 EFI_STATUS RetStatus
;
648 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
649 PCI_DATA_STRUCTURE
*Pcir
;
650 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
652 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode
;
659 // Get the Address of the Rom image
661 RomBar
= PciDevice
->PciIo
.RomImage
;
662 RomBarOffset
= (UINT8
*) RomBar
;
663 RetStatus
= EFI_NOT_FOUND
;
667 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
668 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
678 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
679 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
680 Indicator
= Pcir
->Indicator
;
683 // Create Pci Option Rom Image device path header
685 EfiOpRomImageNode
.Header
.Type
= MEDIA_DEVICE_PATH
;
686 EfiOpRomImageNode
.Header
.SubType
= MEDIA_RELATIVE_OFFSET_RANGE_DP
;
687 SetDevicePathNodeLength (&EfiOpRomImageNode
.Header
, sizeof (EfiOpRomImageNode
));
688 EfiOpRomImageNode
.StartingOffset
= (UINTN
) RomBarOffset
- (UINTN
) RomBar
;
689 EfiOpRomImageNode
.EndingOffset
= (UINTN
) RomBarOffset
+ ImageSize
- 1 - (UINTN
) RomBar
;
691 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, &EfiOpRomImageNode
.Header
);
692 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
695 // load image and start image
700 Status
= EFI_SUCCESS
;
703 if (!EFI_ERROR (Status
)) {
704 Status
= gBS
->LoadImage (
706 gPciBusDriverBinding
.DriverBindingHandle
,
707 PciOptionRomImageDevicePath
,
715 // load image and start image
717 if (!EFI_ERROR (Status
)) {
718 Status
= gBS
->LoadImage (
720 gPciBusDriverBinding
.DriverBindingHandle
,
721 PciOptionRomImageDevicePath
,
728 FreePool (PciOptionRomImageDevicePath
);
730 if (!EFI_ERROR (Status
)) {
731 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
732 if (!EFI_ERROR (Status
)) {
733 AddDriver (PciDevice
, ImageHandle
);
734 PciRomAddImageMapping (
736 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
737 PciDevice
->BusNumber
,
738 PciDevice
->DeviceNumber
,
739 PciDevice
->FunctionNumber
,
740 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
741 PciDevice
->PciIo
.RomSize
743 RetStatus
= EFI_SUCCESS
;
747 RomBarOffset
+= ImageSize
;
749 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));