3 Copyright (c) 2006 - 2007, 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 // Module global for a template of the PCI option ROM Image Device Path Node
22 MEMMAP_DEVICE_PATH mPciOptionRomImageDevicePathNodeTemplate
= {
26 sizeof (MEMMAP_DEVICE_PATH
)
35 IN PCI_IO_DEVICE
*PciIoDevice
46 // TODO: PciIoDevice - add argument and description to function comment
47 // TODO: EFI_NOT_FOUND - add return value to function comment
48 // TODO: EFI_SUCCESS - add return value to function comment
57 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
59 Bus
= PciIoDevice
->BusNumber
;
60 Device
= PciIoDevice
->DeviceNumber
;
61 Function
= PciIoDevice
->FunctionNumber
;
63 PciRootBridgeIo
= PciIoDevice
->PciRootBridgeIo
;
66 // offset is 0x30 if is not ppb
72 RomBarIndex
= PCI_DEVICE_ROMBAR
;
74 if (IS_PCI_BRIDGE (&PciIoDevice
->Pci
)) {
82 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
85 // the bit0 is 0 to prevent the enabling of the Rom address decoder
88 Address
= EFI_PCI_ADDRESS (Bus
, Device
, Function
, RomBarIndex
);
90 Status
= PciRootBridgeIoWrite (
98 if (EFI_ERROR (Status
)) {
105 Status
= PciRootBridgeIoRead (
113 if (EFI_ERROR (Status
)) {
117 // Bits [1, 10] are reserved
119 AllOnes
&= 0xFFFFF800;
120 if ((AllOnes
== 0) || (AllOnes
== 0xFFFFF800)) {
121 return EFI_NOT_FOUND
;
124 PciIoDevice
->RomSize
= (UINT64
) ((~AllOnes
) + 1);
130 IN PCI_IO_DEVICE
*PciDevice
,
137 Load option rom image for specified PCI device
144 // TODO: PciDevice - add argument and description to function comment
145 // TODO: RomBase - add argument and description to function comment
146 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
147 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
148 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
155 EFI_STATUS retStatus
;
158 PCI_EXPANSION_ROM_HEADER
*RomHeader
;
159 PCI_DATA_STRUCTURE
*RomPcir
;
165 RomSize
= PciDevice
->RomSize
;
173 // Get the RomBarIndex
179 RomBarIndex
= PCI_DEVICE_ROMBAR
;
180 if (IS_PCI_BRIDGE (&(PciDevice
->Pci
))) {
188 RomBarIndex
= PCI_BRIDGE_ROMBAR
;
191 // Allocate memory for Rom header and PCIR
193 RomHeader
= AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER
));
194 if (RomHeader
== NULL
) {
195 return EFI_OUT_OF_RESOURCES
;
198 RomPcir
= AllocatePool (sizeof (PCI_DATA_STRUCTURE
));
199 if (RomPcir
== NULL
) {
200 gBS
->FreePool (RomHeader
);
201 return EFI_OUT_OF_RESOURCES
;
204 RomBar
= (UINT32
) RomBase
;
209 RomDecode (PciDevice
, RomBarIndex
, RomBar
, TRUE
);
211 RomBarOffset
= RomBar
;
212 retStatus
= EFI_NOT_FOUND
;
216 PciDevice
->PciRootBridgeIo
->Mem
.Read (
217 PciDevice
->PciRootBridgeIo
,
220 sizeof (PCI_EXPANSION_ROM_HEADER
),
224 if (RomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
225 RomBarOffset
= RomBarOffset
+ 512;
229 RomImageSize
= RomImageSize
+ 512;
235 OffsetPcir
= RomHeader
->PcirOffset
;
236 PciDevice
->PciRootBridgeIo
->Mem
.Read (
237 PciDevice
->PciRootBridgeIo
,
239 RomBarOffset
+ OffsetPcir
,
240 sizeof (PCI_DATA_STRUCTURE
),
243 if (RomPcir
->CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
244 CodeType
= PCI_CODE_TYPE_PCAT_IMAGE
;
246 Indicator
= RomPcir
->Indicator
;
247 RomImageSize
= RomImageSize
+ RomPcir
->ImageLength
* 512;
248 RomBarOffset
= RomBarOffset
+ RomPcir
->ImageLength
* 512;
249 } while (((Indicator
& 0x80) == 0x00) && ((RomBarOffset
- RomBar
) < RomSize
));
252 // Some Legacy Cards do not report the correct ImageLength so used the maximum
253 // of the legacy length and the PCIR Image Length
255 if (CodeType
== PCI_CODE_TYPE_PCAT_IMAGE
) {
256 RomImageSize
= MAX(RomImageSize
, (((EFI_LEGACY_EXPANSION_ROM_HEADER
*)RomHeader
)->Size512
* 512));
259 if (RomImageSize
> 0) {
260 retStatus
= EFI_SUCCESS
;
261 Image
= AllocatePool ((UINT32
) RomImageSize
);
263 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
264 gBS
->FreePool (RomHeader
);
265 gBS
->FreePool (RomPcir
);
266 return EFI_OUT_OF_RESOURCES
;
270 // Copy Rom image into memory
272 PciDevice
->PciRootBridgeIo
->Mem
.Read (
273 PciDevice
->PciRootBridgeIo
,
276 (UINT32
) RomImageSize
,
282 RomDecode (PciDevice
, RomBarIndex
, RomBar
, FALSE
);
284 PciDevice
->PciIo
.RomSize
= RomImageSize
;
285 PciDevice
->PciIo
.RomImage
= RomInMemory
;
288 // For OpROM read from PCI device:
289 // Add the Rom Image to internal database for later PCI light enumeration
291 PciRomAddImageMapping (
293 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
294 PciDevice
->BusNumber
,
295 PciDevice
->DeviceNumber
,
296 PciDevice
->FunctionNumber
,
297 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
298 PciDevice
->PciIo
.RomSize
302 // Free allocated memory
304 gBS
->FreePool (RomHeader
);
305 gBS
->FreePool (RomPcir
);
312 IN PCI_IO_DEVICE
*PciDevice
,
313 IN UINT8 RomBarIndex
,
326 // TODO: PciDevice - add argument and description to function comment
327 // TODO: RomBarIndex - add argument and description to function comment
328 // TODO: RomBar - add argument and description to function comment
329 // TODO: Enable - add argument and description to function comment
330 // TODO: EFI_SUCCESS - add return value to function comment
334 EFI_PCI_IO_PROTOCOL
*PciIo
;
336 PciIo
= &PciDevice
->PciIo
;
341 for (Offset
= 0x10; Offset
<= 0x24; Offset
+= sizeof (UINT32
)) {
342 PciIoWrite (PciIo
, EfiPciIoWidthUint32
, Offset
, 1, &gAllZero
);
346 // set the Rom base address: now is hardcode
347 // enable its decoder
349 Value32
= RomBar
| 0x1;
352 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
359 // Programe all upstream bridge
361 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, TRUE
);
364 // Setting the memory space bit in the function's command register
366 PciEnableCommandRegister(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
371 // disable command register decode to memory
373 PciDisableCommandRegister(PciDevice
, EFI_PCI_COMMAND_MEMORY_SPACE
);
376 // Destroy the programmed bar in all the upstream bridge.
378 ProgrameUpstreamBridgeForRom(PciDevice
, RomBar
, FALSE
);
381 // disable rom decode
383 Value32
= 0xFFFFFFFE;
386 (EFI_PCI_IO_PROTOCOL_WIDTH
) EfiPciWidthUint32
,
400 PCI_IO_DEVICE
*PciDevice
406 Process the oprom image.
409 PciDevice A pointer to a pci device.
422 EFI_HANDLE ImageHandle
;
424 EFI_STATUS retStatus
;
427 UINT32 DestinationSize
;
431 VOID
*DecompressedImageBuffer
;
433 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
434 EFI_PCI_EXPANSION_ROM_HEADER
*EfiRomHeader
;
435 PCI_DATA_STRUCTURE
*Pcir
;
436 EFI_DEVICE_PATH_PROTOCOL
*PciOptionRomImageDevicePath
;
441 // Get the Address of the Rom image
443 RomBar
= PciDevice
->PciIo
.RomImage
;
444 RomBarOffset
= (UINT8
*) RomBar
;
445 retStatus
= EFI_NOT_FOUND
;
449 EfiRomHeader
= (EFI_PCI_EXPANSION_ROM_HEADER
*) RomBarOffset
;
450 if (EfiRomHeader
->Signature
!= PCI_EXPANSION_ROM_HEADER_SIGNATURE
) {
451 RomBarOffset
= RomBarOffset
+ 512;
460 Pcir
= (PCI_DATA_STRUCTURE
*) (RomBarOffset
+ EfiRomHeader
->PcirOffset
);
461 ImageSize
= (UINT32
) (Pcir
->ImageLength
* 512);
462 Indicator
= Pcir
->Indicator
;
464 if ((Pcir
->CodeType
== PCI_CODE_TYPE_EFI_IMAGE
) &&
465 (EfiRomHeader
->EfiSignature
== EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE
)) {
467 if ((EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
468 (EfiRomHeader
->EfiSubsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) {
470 ImageOffset
= EfiRomHeader
->EfiImageHeaderOffset
;
471 ImageSize
= (UINT32
) (EfiRomHeader
->InitializationSize
* 512);
473 ImageBuffer
= (VOID
*) (RomBarOffset
+ ImageOffset
);
474 ImageLength
= ImageSize
- (UINT32
)ImageOffset
;
475 DecompressedImageBuffer
= NULL
;
478 // decompress here if needed
481 if (EfiRomHeader
->CompressionType
> EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
485 if (EfiRomHeader
->CompressionType
== EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED
) {
486 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**) &Decompress
);
487 if (EFI_ERROR (Status
)) {
491 Status
= Decompress
->GetInfo (
498 if (!EFI_ERROR (Status
)) {
499 DecompressedImageBuffer
= NULL
;
500 DecompressedImageBuffer
= AllocatePool (DestinationSize
);
501 if (DecompressedImageBuffer
!= NULL
) {
502 Scratch
= AllocatePool (ScratchSize
);
503 if (Scratch
!= NULL
) {
504 Status
= Decompress
->Decompress (
508 DecompressedImageBuffer
,
513 if (!EFI_ERROR (Status
)) {
514 ImageBuffer
= DecompressedImageBuffer
;
515 ImageLength
= DestinationSize
;
519 gBS
->FreePool (Scratch
);
528 // Build Memory Mapped device path node to record the image offset into the PCI Option ROM
530 mPciOptionRomImageDevicePathNodeTemplate
.StartingAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (RomBarOffset
- (UINT8
*) RomBar
);
531 mPciOptionRomImageDevicePathNodeTemplate
.EndingAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (RomBarOffset
+ ImageSize
- 1 - (UINT8
*) RomBar
);
532 PciOptionRomImageDevicePath
= AppendDevicePathNode (PciDevice
->DevicePath
, (const EFI_DEVICE_PATH_PROTOCOL
*)&mPciOptionRomImageDevicePathNodeTemplate
);
533 ASSERT (PciOptionRomImageDevicePath
!= NULL
);
536 // load image and start image
538 Status
= gBS
->LoadImage (
540 gPciBusDriverBinding
.DriverBindingHandle
,
541 PciOptionRomImageDevicePath
,
548 // Free the device path after it has been used by LoadImage
550 gBS
->FreePool (PciOptionRomImageDevicePath
);
552 if (!EFI_ERROR (Status
)) {
553 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
554 if (!EFI_ERROR (Status
)) {
555 AddDriver (PciDevice
, ImageHandle
);
556 PciRomAddImageMapping (
558 PciDevice
->PciRootBridgeIo
->SegmentNumber
,
559 PciDevice
->BusNumber
,
560 PciDevice
->DeviceNumber
,
561 PciDevice
->FunctionNumber
,
562 (UINT64
) (UINTN
) PciDevice
->PciIo
.RomImage
,
563 PciDevice
->PciIo
.RomSize
565 retStatus
= EFI_SUCCESS
;
570 RomBarOffset
= RomBarOffset
+ ImageSize
;
572 RomBarOffset
= RomBarOffset
+ ImageSize
;
575 RomBarOffset
= RomBarOffset
+ ImageSize
;
578 } while (((Indicator
& 0x80) == 0x00) && ((UINTN
) (RomBarOffset
- (UINT8
*) RomBar
) < PciDevice
->RomSize
));