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