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