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