1 /** @file
2   PCI Rom supporting funtions implementation for PCI Bus module.
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "PciBus.h"
10 
11 /**
12   Load the EFI Image from Option ROM
13 
14   @param PciIoDevice   PCI IO device instance.
15   @param FilePath      The file path of the EFI Image
16   @param BufferSize    On input the size of Buffer in bytes. On output with a return
17                        code of EFI_SUCCESS, the amount of data transferred to Buffer.
18                        On output with a return code of EFI_BUFFER_TOO_SMALL,
19                        the size of Buffer required to retrieve the requested file.
20   @param Buffer        The memory buffer to transfer the file to. If Buffer is NULL,
21                        then no the size of the requested file is returned in BufferSize.
22 
23   @retval EFI_SUCCESS           The file was loaded.
24   @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
25                                 BufferSize is NULL.
26   @retval EFI_NOT_FOUND         Not found PCI Option Rom on PCI device.
27   @retval EFI_DEVICE_ERROR      Failed to decompress PCI Option Rom image.
28   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current directory entry.
29                                 BufferSize has been updated with the size needed to complete the request.
30 **/
31 EFI_STATUS
LocalLoadFile2(IN PCI_IO_DEVICE * PciIoDevice,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN OUT UINTN * BufferSize,IN VOID * Buffer OPTIONAL)32 LocalLoadFile2 (
33   IN PCI_IO_DEVICE            *PciIoDevice,
34   IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
35   IN OUT UINTN                *BufferSize,
36   IN VOID                     *Buffer      OPTIONAL
37   )
38 {
39   EFI_STATUS                                Status;
40   MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH   *EfiOpRomImageNode;
41   EFI_PCI_EXPANSION_ROM_HEADER              *EfiRomHeader;
42   PCI_DATA_STRUCTURE                        *Pcir;
43   UINT32                                    ImageSize;
44   UINT8                                     *ImageBuffer;
45   UINT32                                    ImageLength;
46   UINT32                                    DestinationSize;
47   UINT32                                    ScratchSize;
48   VOID                                      *Scratch;
49   EFI_DECOMPRESS_PROTOCOL                   *Decompress;
50   UINT32                                    InitializationSize;
51 
52   EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;
53   if ((EfiOpRomImageNode == NULL) ||
54       (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||
55       (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||
56       (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||
57       (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||
58       (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||
59       (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||
60       (BufferSize == NULL)
61       ) {
62     return EFI_INVALID_PARAMETER;
63   }
64 
65   EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (
66       (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset
67       );
68   if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
69     return EFI_NOT_FOUND;
70   }
71 
72 
73   Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);
74   ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
75 
76   if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
77       (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
78       ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
79        (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&
80       (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)
81        ) {
82 
83     ImageSize = Pcir->ImageLength * 512;
84     InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;
85     if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset >=  InitializationSize) {
86       return EFI_NOT_FOUND;
87     }
88 
89     ImageBuffer             = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;
90     ImageLength             = InitializationSize - EfiRomHeader->EfiImageHeaderOffset;
91 
92     if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
93       //
94       // Uncompressed: Copy the EFI Image directly to user's buffer
95       //
96       if (Buffer == NULL || *BufferSize < ImageLength) {
97         *BufferSize = ImageLength;
98         return EFI_BUFFER_TOO_SMALL;
99       }
100 
101       *BufferSize = ImageLength;
102       CopyMem (Buffer, ImageBuffer, ImageLength);
103       return EFI_SUCCESS;
104 
105     } else {
106       //
107       // Compressed: Uncompress before copying
108       //
109       Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
110       if (EFI_ERROR (Status)) {
111         return EFI_DEVICE_ERROR;
112       }
113       Status = Decompress->GetInfo (
114                              Decompress,
115                              ImageBuffer,
116                              ImageLength,
117                              &DestinationSize,
118                              &ScratchSize
119                              );
120       if (EFI_ERROR (Status)) {
121         return EFI_DEVICE_ERROR;
122       }
123 
124       if (Buffer == NULL || *BufferSize < DestinationSize) {
125         *BufferSize = DestinationSize;
126         return EFI_BUFFER_TOO_SMALL;
127       }
128 
129       *BufferSize = DestinationSize;
130       Scratch = AllocatePool (ScratchSize);
131       if (Scratch == NULL) {
132         return EFI_DEVICE_ERROR;
133       }
134 
135       Status = Decompress->Decompress (
136                              Decompress,
137                              ImageBuffer,
138                              ImageLength,
139                              Buffer,
140                              DestinationSize,
141                              Scratch,
142                              ScratchSize
143                              );
144       FreePool (Scratch);
145 
146       if (EFI_ERROR (Status)) {
147         return EFI_DEVICE_ERROR;
148       }
149       return EFI_SUCCESS;
150     }
151   }
152 
153   return EFI_NOT_FOUND;
154 }
155 
156 /**
157   Initialize a PCI LoadFile2 instance.
158 
159   @param PciIoDevice   PCI IO Device.
160 
161 **/
162 VOID
InitializePciLoadFile2(IN PCI_IO_DEVICE * PciIoDevice)163 InitializePciLoadFile2 (
164   IN PCI_IO_DEVICE       *PciIoDevice
165   )
166 {
167   PciIoDevice->LoadFile2.LoadFile = LoadFile2;
168 }
169 
170 /**
171   Causes the driver to load a specified file.
172 
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.
182 
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
186                                 BufferSize is NULL.
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.
191 
192 **/
193 EFI_STATUS
194 EFIAPI
LoadFile2(IN EFI_LOAD_FILE2_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN BOOLEAN BootPolicy,IN OUT UINTN * BufferSize,IN VOID * Buffer OPTIONAL)195 LoadFile2 (
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
201   )
202 {
203   PCI_IO_DEVICE                             *PciIoDevice;
204 
205   if (BootPolicy) {
206     return EFI_UNSUPPORTED;
207   }
208   PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
209 
210   return LocalLoadFile2 (
211            PciIoDevice,
212            FilePath,
213            BufferSize,
214            Buffer
215            );
216 }
217 
218 /**
219   Get Pci device's oprom information.
220 
221   @param PciIoDevice    Input Pci device instance.
222                         Output Pci device instance with updated OptionRom size.
223 
224   @retval EFI_NOT_FOUND Pci device has not Option Rom.
225   @retval EFI_SUCCESS   Pci device has Option Rom.
226 
227 **/
228 EFI_STATUS
GetOpRomInfo(IN OUT PCI_IO_DEVICE * PciIoDevice)229 GetOpRomInfo (
230   IN OUT PCI_IO_DEVICE    *PciIoDevice
231   )
232 {
233   UINT8                           RomBarIndex;
234   UINT32                          AllOnes;
235   UINT64                          Address;
236   EFI_STATUS                      Status;
237   UINT8                           Bus;
238   UINT8                           Device;
239   UINT8                           Function;
240   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
241 
242   Bus             = PciIoDevice->BusNumber;
243   Device          = PciIoDevice->DeviceNumber;
244   Function        = PciIoDevice->FunctionNumber;
245 
246   PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
247 
248   //
249   // Offset is 0x30 if is not ppb
250   //
251 
252   //
253   // 0x30
254   //
255   RomBarIndex = PCI_EXPANSION_ROM_BASE;
256 
257   if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
258     //
259     // If is ppb, 0x38
260     //
261     RomBarIndex = PCI_BRIDGE_ROMBAR;
262   }
263   //
264   // The bit0 is 0 to prevent the enabling of the Rom address decoder
265   //
266   AllOnes = 0xfffffffe;
267   Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
268 
269   Status = PciRootBridgeIo->Pci.Write (
270                                   PciRootBridgeIo,
271                                   EfiPciWidthUint32,
272                                   Address,
273                                   1,
274                                   &AllOnes
275                                   );
276   if (EFI_ERROR (Status)) {
277     return EFI_NOT_FOUND;
278   }
279 
280   //
281   // Read back
282   //
283   Status = PciRootBridgeIo->Pci.Read(
284                                   PciRootBridgeIo,
285                                   EfiPciWidthUint32,
286                                   Address,
287                                   1,
288                                   &AllOnes
289                                   );
290   if (EFI_ERROR (Status)) {
291     return EFI_NOT_FOUND;
292   }
293 
294   //
295   // Bits [1, 10] are reserved
296   //
297   AllOnes &= 0xFFFFF800;
298   if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
299     return EFI_NOT_FOUND;
300   }
301 
302   PciIoDevice->RomSize = (~AllOnes) + 1;
303   return EFI_SUCCESS;
304 }
305 
306 /**
307   Check if the RomImage contains EFI Images.
308 
309   @param  RomImage  The ROM address of Image for check.
310   @param  RomSize   Size of ROM for check.
311 
312   @retval TRUE     ROM contain EFI Image.
313   @retval FALSE    ROM not contain EFI Image.
314 
315 **/
316 BOOLEAN
ContainEfiImage(IN VOID * RomImage,IN UINT64 RomSize)317 ContainEfiImage (
318   IN VOID            *RomImage,
319   IN UINT64          RomSize
320   )
321 {
322   PCI_EXPANSION_ROM_HEADER  *RomHeader;
323   PCI_DATA_STRUCTURE        *RomPcir;
324   UINT8                     Indicator;
325 
326   Indicator = 0;
327   RomHeader = RomImage;
328   if (RomHeader == NULL) {
329     return FALSE;
330   }
331 
332   do {
333     if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
334       RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);
335       continue;
336     }
337 
338     //
339     // The PCI Data Structure must be DWORD aligned.
340     //
341     if (RomHeader->PcirOffset == 0 ||
342         (RomHeader->PcirOffset & 3) != 0 ||
343         (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) {
344       break;
345     }
346 
347     RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);
348     if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
349       break;
350     }
351 
352     if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
353       return TRUE;
354     }
355 
356     Indicator = RomPcir->Indicator;
357     RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->ImageLength * 512);
358   } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) && ((Indicator & 0x80) == 0x00));
359 
360   return FALSE;
361 }
362 
363 /**
364   Load Option Rom image for specified PCI device.
365 
366   @param PciDevice Pci device instance.
367   @param RomBase   Base address of Option Rom.
368 
369   @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
370   @retval EFI_SUCESS           Successfully loaded Option Rom.
371 
372 **/
373 EFI_STATUS
LoadOpRomImage(IN PCI_IO_DEVICE * PciDevice,IN UINT64 RomBase)374 LoadOpRomImage (
375   IN PCI_IO_DEVICE   *PciDevice,
376   IN UINT64          RomBase
377   )
378 {
379   UINT8                     RomBarIndex;
380   UINT8                     Indicator;
381   UINT16                    OffsetPcir;
382   UINT32                    RomBarOffset;
383   UINT32                    RomBar;
384   EFI_STATUS                RetStatus;
385   BOOLEAN                   FirstCheck;
386   UINT8                     *Image;
387   PCI_EXPANSION_ROM_HEADER  *RomHeader;
388   PCI_DATA_STRUCTURE        *RomPcir;
389   UINT64                    RomSize;
390   UINT64                    RomImageSize;
391   UINT32                    LegacyImageLength;
392   UINT8                     *RomInMemory;
393   UINT8                     CodeType;
394 
395   RomSize       = PciDevice->RomSize;
396 
397   Indicator     = 0;
398   RomImageSize  = 0;
399   RomInMemory   = NULL;
400   CodeType      = 0xFF;
401 
402   //
403   // Get the RomBarIndex
404   //
405 
406   //
407   // 0x30
408   //
409   RomBarIndex = PCI_EXPANSION_ROM_BASE;
410   if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
411     //
412     // if is ppb
413     //
414 
415     //
416     // 0x38
417     //
418     RomBarIndex = PCI_BRIDGE_ROMBAR;
419   }
420   //
421   // Allocate memory for Rom header and PCIR
422   //
423   RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
424   if (RomHeader == NULL) {
425     return EFI_OUT_OF_RESOURCES;
426   }
427 
428   RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
429   if (RomPcir == NULL) {
430     FreePool (RomHeader);
431     return EFI_OUT_OF_RESOURCES;
432   }
433 
434   RomBar = (UINT32) RomBase;
435 
436   //
437   // Enable RomBar
438   //
439   RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
440 
441   RomBarOffset  = RomBar;
442   RetStatus     = EFI_NOT_FOUND;
443   FirstCheck    = TRUE;
444   LegacyImageLength = 0;
445 
446   do {
447     PciDevice->PciRootBridgeIo->Mem.Read (
448                                       PciDevice->PciRootBridgeIo,
449                                       EfiPciWidthUint8,
450                                       RomBarOffset,
451                                       sizeof (PCI_EXPANSION_ROM_HEADER),
452                                       (UINT8 *) RomHeader
453                                       );
454 
455     if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
456       RomBarOffset = RomBarOffset + 512;
457       if (FirstCheck) {
458         break;
459       } else {
460         RomImageSize = RomImageSize + 512;
461         continue;
462       }
463     }
464 
465     FirstCheck  = FALSE;
466     OffsetPcir  = RomHeader->PcirOffset;
467     //
468     // If the pointer to the PCI Data Structure is invalid, no further images can be located.
469     // The PCI Data Structure must be DWORD aligned.
470     //
471     if (OffsetPcir == 0 ||
472         (OffsetPcir & 3) != 0 ||
473         RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
474       break;
475     }
476     PciDevice->PciRootBridgeIo->Mem.Read (
477                                       PciDevice->PciRootBridgeIo,
478                                       EfiPciWidthUint8,
479                                       RomBarOffset + OffsetPcir,
480                                       sizeof (PCI_DATA_STRUCTURE),
481                                       (UINT8 *) RomPcir
482                                       );
483     //
484     // If a valid signature is not present in the PCI Data Structure, no further images can be located.
485     //
486     if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
487       break;
488     }
489     if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
490       break;
491     }
492     if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
493       CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
494       LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
495     }
496     Indicator     = RomPcir->Indicator;
497     RomImageSize  = RomImageSize + RomPcir->ImageLength * 512;
498     RomBarOffset  = RomBarOffset + RomPcir->ImageLength * 512;
499   } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
500 
501   //
502   // Some Legacy Cards do not report the correct ImageLength so used the maximum
503   // of the legacy length and the PCIR Image Length
504   //
505   if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
506     RomImageSize = MAX (RomImageSize, LegacyImageLength);
507   }
508 
509   if (RomImageSize > 0) {
510     RetStatus = EFI_SUCCESS;
511     Image     = AllocatePool ((UINT32) RomImageSize);
512     if (Image == NULL) {
513       RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
514       FreePool (RomHeader);
515       FreePool (RomPcir);
516       return EFI_OUT_OF_RESOURCES;
517     }
518 
519     //
520     // Copy Rom image into memory
521     //
522     PciDevice->PciRootBridgeIo->Mem.Read (
523                                       PciDevice->PciRootBridgeIo,
524                                       EfiPciWidthUint8,
525                                       RomBar,
526                                       (UINT32) RomImageSize,
527                                       Image
528                                       );
529     RomInMemory = Image;
530   }
531 
532   RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
533 
534   PciDevice->EmbeddedRom    = TRUE;
535   PciDevice->PciIo.RomSize  = RomImageSize;
536   PciDevice->PciIo.RomImage = RomInMemory;
537 
538   //
539   // For OpROM read from PCI device:
540   //   Add the Rom Image to internal database for later PCI light enumeration
541   //
542   PciRomAddImageMapping (
543     NULL,
544     PciDevice->PciRootBridgeIo->SegmentNumber,
545     PciDevice->BusNumber,
546     PciDevice->DeviceNumber,
547     PciDevice->FunctionNumber,
548     PciDevice->PciIo.RomImage,
549     PciDevice->PciIo.RomSize
550     );
551 
552   //
553   // Free allocated memory
554   //
555   FreePool (RomHeader);
556   FreePool (RomPcir);
557 
558   return RetStatus;
559 }
560 
561 /**
562   Enable/Disable Option Rom decode.
563 
564   @param PciDevice    Pci device instance.
565   @param RomBarIndex  The BAR index of the standard PCI Configuration header to use as the
566                       base address for resource range. The legal range for this field is 0..5.
567   @param RomBar       Base address of Option Rom.
568   @param Enable       Flag for enable/disable decode.
569 
570 **/
571 VOID
RomDecode(IN PCI_IO_DEVICE * PciDevice,IN UINT8 RomBarIndex,IN UINT32 RomBar,IN BOOLEAN Enable)572 RomDecode (
573   IN PCI_IO_DEVICE   *PciDevice,
574   IN UINT8           RomBarIndex,
575   IN UINT32          RomBar,
576   IN BOOLEAN         Enable
577   )
578 {
579   UINT32              Value32;
580   EFI_PCI_IO_PROTOCOL *PciIo;
581 
582   PciIo = &PciDevice->PciIo;
583   if (Enable) {
584 
585     //
586     // set the Rom base address: now is hardcode
587     // enable its decoder
588     //
589     Value32 = RomBar | 0x1;
590     PciIo->Pci.Write (
591                  PciIo,
592                  (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
593                  RomBarIndex,
594                  1,
595                  &Value32
596                  );
597 
598     //
599     // Programe all upstream bridge
600     //
601     ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE);
602 
603     //
604     // Setting the memory space bit in the function's command register
605     //
606     PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
607 
608   } else {
609 
610     //
611     // disable command register decode to memory
612     //
613     PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
614 
615     //
616     // Destroy the programmed bar in all the upstream bridge.
617     //
618     ProgramUpstreamBridgeForRom (PciDevice, RomBar, FALSE);
619 
620     //
621     // disable rom decode
622     //
623     Value32 = 0xFFFFFFFE;
624     PciIo->Pci.Write (
625                  PciIo,
626                  (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
627                  RomBarIndex,
628                  1,
629                  &Value32
630                  );
631 
632   }
633 }
634 
635 /**
636   Load and start the Option Rom image.
637 
638   @param PciDevice       Pci device instance.
639 
640   @retval EFI_SUCCESS    Successfully loaded and started PCI Option Rom image.
641   @retval EFI_NOT_FOUND  Failed to process PCI Option Rom image.
642 
643 **/
644 EFI_STATUS
ProcessOpRomImage(IN PCI_IO_DEVICE * PciDevice)645 ProcessOpRomImage (
646   IN  PCI_IO_DEVICE   *PciDevice
647   )
648 {
649   UINT8                                    Indicator;
650   UINT32                                   ImageSize;
651   VOID                                     *RomBar;
652   UINT8                                    *RomBarOffset;
653   EFI_HANDLE                               ImageHandle;
654   EFI_STATUS                               Status;
655   EFI_STATUS                               RetStatus;
656   EFI_PCI_EXPANSION_ROM_HEADER             *EfiRomHeader;
657   PCI_DATA_STRUCTURE                       *Pcir;
658   EFI_DEVICE_PATH_PROTOCOL                 *PciOptionRomImageDevicePath;
659   MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH  EfiOpRomImageNode;
660   VOID                                     *Buffer;
661   UINTN                                    BufferSize;
662 
663   Indicator = 0;
664 
665   //
666   // Get the Address of the Option Rom image
667   //
668   RomBar        = PciDevice->PciIo.RomImage;
669   RomBarOffset  = (UINT8 *) RomBar;
670   RetStatus     = EFI_NOT_FOUND;
671 
672   if (RomBar == NULL) {
673     return RetStatus;
674   }
675   ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
676 
677   do {
678     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
679     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
680       RomBarOffset += 512;
681       continue;
682     }
683 
684     Pcir        = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
685     ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
686     ImageSize   = (UINT32) (Pcir->ImageLength * 512);
687     Indicator   = Pcir->Indicator;
688 
689     //
690     // Skip the image if it is not an EFI PCI Option ROM image
691     //
692     if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
693       goto NextImage;
694     }
695 
696     //
697     // Ignore the EFI PCI Option ROM image if it is an EFI application
698     //
699     if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
700       goto NextImage;
701     }
702 
703     //
704     // Create Pci Option Rom Image device path header
705     //
706     EfiOpRomImageNode.Header.Type     = MEDIA_DEVICE_PATH;
707     EfiOpRomImageNode.Header.SubType  = MEDIA_RELATIVE_OFFSET_RANGE_DP;
708     SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
709     EfiOpRomImageNode.StartingOffset  = (UINTN) RomBarOffset - (UINTN) RomBar;
710     EfiOpRomImageNode.EndingOffset    = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
711 
712     PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
713     ASSERT (PciOptionRomImageDevicePath != NULL);
714 
715     //
716     // load image and start image
717     //
718     BufferSize  = 0;
719     Buffer      = NULL;
720     ImageHandle = NULL;
721 
722     Status = gBS->LoadImage (
723                     FALSE,
724                     gPciBusDriverBinding.DriverBindingHandle,
725                     PciOptionRomImageDevicePath,
726                     Buffer,
727                     BufferSize,
728                     &ImageHandle
729                     );
730     if (EFI_ERROR (Status)) {
731       //
732       // Record the Option ROM Image device path when LoadImage fails.
733       // PciOverride.GetDriver() will try to look for the Image Handle using the device path later.
734       //
735       AddDriver (PciDevice, NULL, PciOptionRomImageDevicePath);
736     } else {
737       Status = gBS->StartImage (ImageHandle, NULL, NULL);
738       if (!EFI_ERROR (Status)) {
739         //
740         // Record the Option ROM Image Handle
741         //
742         AddDriver (PciDevice, ImageHandle, NULL);
743         PciRomAddImageMapping (
744           ImageHandle,
745           PciDevice->PciRootBridgeIo->SegmentNumber,
746           PciDevice->BusNumber,
747           PciDevice->DeviceNumber,
748           PciDevice->FunctionNumber,
749           PciDevice->PciIo.RomImage,
750           PciDevice->PciIo.RomSize
751           );
752         RetStatus = EFI_SUCCESS;
753       }
754     }
755     FreePool (PciOptionRomImageDevicePath);
756 
757 NextImage:
758     RomBarOffset += ImageSize;
759 
760   } while (((Indicator & 0x80) == 0x00) && (((UINTN) RomBarOffset - (UINTN) RomBar) < PciDevice->RomSize));
761 
762   return RetStatus;
763 }
764 
765