• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*++
2 
3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   PciOptionRomSupport.c
15 
16 Abstract:
17 
18   PCI Bus Driver
19 
20 Revision History
21 
22 --*/
23 
24 #include "PciBus.h"
25 
26 
27 EFI_STATUS
28 RomDecode (
29   IN PCI_IO_DEVICE   *PciDevice,
30   IN UINT8           RomBarIndex,
31   IN UINT32          RomBar,
32   IN BOOLEAN         Enable
33 );
34 
35 EFI_STATUS
GetOpRomInfo(IN PCI_IO_DEVICE * PciIoDevice)36 GetOpRomInfo (
37   IN PCI_IO_DEVICE    *PciIoDevice
38   )
39 /*++
40 
41 Routine Description:
42 
43 Arguments:
44 
45 Returns:
46 
47 --*/
48 {
49   UINT8                           RomBarIndex;
50   UINT32                          AllOnes;
51   UINT64                          Address;
52   EFI_STATUS                      Status;
53   UINT8                           Bus;
54   UINT8                           Device;
55   UINT8                           Function;
56   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
57 
58   Bus             = PciIoDevice->BusNumber;
59   Device          = PciIoDevice->DeviceNumber;
60   Function        = PciIoDevice->FunctionNumber;
61 
62   PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
63 
64   //
65   // offset is 0x30 if is not ppb
66   //
67 
68   //
69   // 0x30
70   //
71   RomBarIndex = PCI_EXPANSION_ROM_BASE;
72 
73   if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
74     //
75     // if is ppb
76     //
77 
78     //
79     // 0x38
80     //
81     RomBarIndex = PCI_BRIDGE_ROMBAR;
82   }
83   //
84   // the bit0 is 0 to prevent the enabling of the Rom address decoder
85   //
86   AllOnes = 0xfffffffe;
87   Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
88 
89   Status = PciRootBridgeIo->Pci.Write (
90                                   PciRootBridgeIo,
91                                   EfiPciWidthUint32,
92                                   Address,
93                                   1,
94                                   &AllOnes
95                                   );
96   if (EFI_ERROR (Status)) {
97     return Status;
98   }
99 
100   //
101   // read back
102   //
103   Status = PciRootBridgeIo->Pci.Read (
104                                   PciRootBridgeIo,
105                                   EfiPciWidthUint32,
106                                   Address,
107                                   1,
108                                   &AllOnes
109                                   );
110   if (EFI_ERROR (Status)) {
111     return Status;
112   }
113 
114   //
115   // Bits [1, 10] are reserved
116   //
117   AllOnes &= 0xFFFFF800;
118   if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
119     return EFI_NOT_FOUND;
120   }
121 
122   DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));
123   DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));
124 
125   PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
126   return EFI_SUCCESS;
127 }
128 
129 EFI_STATUS
LoadOpRomImage(IN PCI_IO_DEVICE * PciDevice,IN UINT64 ReservedMemoryBase)130 LoadOpRomImage (
131   IN PCI_IO_DEVICE   *PciDevice,
132   IN UINT64          ReservedMemoryBase
133   )
134 /*++
135 
136 Routine Description:
137 
138     Load option rom image for specified PCI device
139 
140 Arguments:
141 
142 Returns:
143 
144 --*/
145 {
146   UINT8                     RomBarIndex;
147   UINT8                     Indicator;
148   UINT16                    OffsetPcir;
149   UINT32                    RomBarOffset;
150   UINT32                    RomBar;
151   EFI_STATUS                retStatus;
152   BOOLEAN                   FirstCheck;
153   UINT8                     *Image;
154   PCI_EXPANSION_ROM_HEADER  *RomHeader;
155   PCI_DATA_STRUCTURE        *RomPcir;
156   UINT64                    RomSize;
157   UINT64                    RomImageSize;
158   UINT32                    LegacyImageLength;
159   UINT8                     *RomInMemory;
160   UINT8                     CodeType;
161 
162   RomSize       = PciDevice->RomSize;
163 
164   Indicator     = 0;
165   RomImageSize  = 0;
166   RomInMemory   = NULL;
167   CodeType      = 0xFF;
168 
169   //
170   // Get the RomBarIndex
171   //
172 
173   //
174   // 0x30
175   //
176   RomBarIndex = PCI_EXPANSION_ROM_BASE;
177   if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
178     //
179     // if is ppb
180     //
181 
182     //
183     // 0x38
184     //
185     RomBarIndex = PCI_BRIDGE_ROMBAR;
186   }
187   //
188   // Allocate memory for Rom header and PCIR
189   //
190   RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
191   if (RomHeader == NULL) {
192     return EFI_OUT_OF_RESOURCES;
193   }
194 
195   RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
196   if (RomPcir == NULL) {
197     gBS->FreePool (RomHeader);
198     return EFI_OUT_OF_RESOURCES;
199   }
200 
201   RomBar = (UINT32)ReservedMemoryBase;
202 
203   //
204   // Enable RomBar
205   //
206   RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
207 
208   RomBarOffset  = RomBar;
209   retStatus     = EFI_NOT_FOUND;
210   FirstCheck    = TRUE;
211   LegacyImageLength = 0;
212 
213   do {
214     PciDevice->PciRootBridgeIo->Mem.Read (
215                                       PciDevice->PciRootBridgeIo,
216                                       EfiPciWidthUint8,
217                                       RomBarOffset,
218                                       sizeof (PCI_EXPANSION_ROM_HEADER),
219                                       (UINT8 *) RomHeader
220                                       );
221 
222     if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
223       RomBarOffset = RomBarOffset + 512;
224       if (FirstCheck) {
225         break;
226       } else {
227         RomImageSize = RomImageSize + 512;
228         continue;
229       }
230     }
231 
232     FirstCheck  = FALSE;
233     OffsetPcir  = RomHeader->PcirOffset;
234     //
235     // If the pointer to the PCI Data Structure is invalid, no further images can be located.
236     // The PCI Data Structure must be DWORD aligned.
237     //
238     if (OffsetPcir == 0 ||
239        (OffsetPcir & 3) != 0 ||
240        RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
241       break;
242     }
243     PciDevice->PciRootBridgeIo->Mem.Read (
244                                       PciDevice->PciRootBridgeIo,
245                                       EfiPciWidthUint8,
246                                       RomBarOffset + OffsetPcir,
247                                       sizeof (PCI_DATA_STRUCTURE),
248                                       (UINT8 *) RomPcir
249                                       );
250     //
251     // If a valid signature is not present in the PCI Data Structure, no further images can be located.
252     //
253     if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
254       break;
255     }
256     if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
257       break;
258     }
259     if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
260       CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
261       LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
262     }
263     Indicator     = RomPcir->Indicator;
264     RomImageSize  = RomImageSize + RomPcir->ImageLength * 512;
265     RomBarOffset  = RomBarOffset + RomPcir->ImageLength * 512;
266   } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
267 
268   //
269   // Some Legacy Cards do not report the correct ImageLength so used the maximum
270   // of the legacy length and the PCIR Image Length
271   //
272   if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
273     RomImageSize = MAX (RomImageSize, LegacyImageLength);
274   }
275 
276   if (RomImageSize > 0) {
277     retStatus = EFI_SUCCESS;
278     Image     = AllocatePool ((UINT32) RomImageSize);
279     if (Image == NULL) {
280       RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
281       gBS->FreePool (RomHeader);
282       gBS->FreePool (RomPcir);
283       return EFI_OUT_OF_RESOURCES;
284     }
285 
286     //
287     // Copy Rom image into memory
288     //
289     PciDevice->PciRootBridgeIo->Mem.Read (
290                                       PciDevice->PciRootBridgeIo,
291                                       EfiPciWidthUint8,
292                                       RomBar,
293                                       (UINT32) RomImageSize,
294                                       Image
295                                       );
296     RomInMemory = Image;
297   }
298 
299   RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
300 
301   PciDevice->PciIo.RomSize  = RomImageSize;
302   PciDevice->PciIo.RomImage = RomInMemory;
303 
304   //
305   // Free allocated memory
306   //
307   gBS->FreePool (RomHeader);
308   gBS->FreePool (RomPcir);
309 
310   return retStatus;
311 }
312 
313 EFI_STATUS
RomDecode(IN PCI_IO_DEVICE * PciDevice,IN UINT8 RomBarIndex,IN UINT32 RomBar,IN BOOLEAN Enable)314 RomDecode (
315   IN PCI_IO_DEVICE   *PciDevice,
316   IN UINT8           RomBarIndex,
317   IN UINT32          RomBar,
318   IN BOOLEAN         Enable
319   )
320 /*++
321 
322 Routine Description:
323 
324 Arguments:
325 
326 Returns:
327 
328 --*/
329 {
330   UINT16                          CommandValue;
331   UINT32                          Value32;
332   UINT64                          Address;
333   //EFI_STATUS                      Status;
334   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
335 
336   PciRootBridgeIo = PciDevice->PciRootBridgeIo;
337   if (Enable) {
338     Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
339     //
340     // set the Rom base address: now is hardcode
341     //
342     PciRootBridgeIo->Pci.Write(
343                                PciRootBridgeIo,
344                                EfiPciWidthUint32,
345                                Address,
346                                1,
347                                &RomBar);
348 
349     //
350     // enable its decoder
351     //
352     Value32 = RomBar | 0x1;
353     PciRootBridgeIo->Pci.Write(
354                                PciRootBridgeIo,
355                                EfiPciWidthUint32,
356                                Address,
357                                1,
358                                &Value32);
359 
360     //
361     //setting the memory space bit in the function's command register
362     //
363     Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);
364     PciRootBridgeIo->Pci.Read(
365                               PciRootBridgeIo,
366                               EfiPciWidthUint16,
367                               Address,
368                               1,
369                               &CommandValue);
370 
371     CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003
372     PciRootBridgeIo->Pci.Write(
373                                PciRootBridgeIo,
374                                EfiPciWidthUint16,
375                                Address,
376                                1,
377                                &CommandValue);
378   } else {
379     //
380     // disable rom decode
381     //
382     Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
383     Value32 = 0xfffffffe;
384     PciRootBridgeIo->Pci.Write(
385                                PciRootBridgeIo,
386                                EfiPciWidthUint32,
387                                Address,
388                                1,
389                                &Value32);
390   }
391 
392   return EFI_SUCCESS;
393 
394 }
395 
396 EFI_STATUS
ProcessOpRomImage(PCI_IO_DEVICE * PciDevice)397 ProcessOpRomImage (
398   PCI_IO_DEVICE   *PciDevice
399   )
400 /*++
401 
402 Routine Description:
403 
404   Process the oprom image.
405 
406 Arguments:
407   PciDevice       A pointer to a pci device.
408 
409 Returns:
410 
411   EFI Status.
412 
413 --*/
414 {
415   UINT8                         Indicator;
416   UINT32                        ImageSize;
417   UINT16                        ImageOffset;
418   VOID                          *RomBar;
419   UINT8                         *RomBarOffset;
420   EFI_HANDLE                    ImageHandle;
421   EFI_STATUS                    Status;
422   EFI_STATUS                    retStatus;
423   BOOLEAN                       SkipImage;
424   UINT32                        DestinationSize;
425   UINT32                        ScratchSize;
426   UINT8                         *Scratch;
427   VOID                          *ImageBuffer;
428   VOID                          *DecompressedImageBuffer;
429   UINT32                        ImageLength;
430   EFI_DECOMPRESS_PROTOCOL       *Decompress;
431   EFI_PCI_EXPANSION_ROM_HEADER  *EfiRomHeader;
432   PCI_DATA_STRUCTURE            *Pcir;
433   UINT32                        InitializationSize;
434 
435   Indicator = 0;
436 
437   //
438   // Get the Address of the Rom image
439   //
440   RomBar        = PciDevice->PciIo.RomImage;
441   RomBarOffset  = (UINT8 *) RomBar;
442   retStatus     = EFI_NOT_FOUND;
443 
444   if (RomBarOffset == NULL) {
445     return retStatus;
446   }
447   ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
448 
449   do {
450     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
451     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
452       RomBarOffset = RomBarOffset + 512;
453       continue;
454     }
455 
456     Pcir        = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
457     ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
458     ImageSize   = (UINT32) (Pcir->ImageLength * 512);
459     Indicator   = Pcir->Indicator;
460 
461     if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
462         (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
463         ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
464          (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
465 
466       ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
467       InitializationSize      = EfiRomHeader->InitializationSize * 512;
468 
469       if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
470 
471         ImageBuffer             = (VOID *) (RomBarOffset + ImageOffset);
472         ImageLength             =  InitializationSize - (UINT32)ImageOffset;
473         DecompressedImageBuffer = NULL;
474 
475         //
476         // decompress here if needed
477         //
478         SkipImage = FALSE;
479         if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
480           SkipImage = TRUE;
481         }
482 
483         if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
484           Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
485           if (EFI_ERROR (Status)) {
486             SkipImage = TRUE;
487           } else {
488             SkipImage = TRUE;
489             Status = Decompress->GetInfo (
490                                   Decompress,
491                                   ImageBuffer,
492                                   ImageLength,
493                                   &DestinationSize,
494                                   &ScratchSize
495                                   );
496             if (!EFI_ERROR (Status)) {
497               DecompressedImageBuffer = NULL;
498               DecompressedImageBuffer = AllocatePool (DestinationSize);
499               if (DecompressedImageBuffer != NULL) {
500                 Scratch = AllocatePool (ScratchSize);
501                 if (Scratch != NULL) {
502                   Status = Decompress->Decompress (
503                                         Decompress,
504                                         ImageBuffer,
505                                         ImageLength,
506                                         DecompressedImageBuffer,
507                                         DestinationSize,
508                                         Scratch,
509                                         ScratchSize
510                                         );
511                   if (!EFI_ERROR (Status)) {
512                     ImageBuffer = DecompressedImageBuffer;
513                     ImageLength = DestinationSize;
514                     SkipImage   = FALSE;
515                   }
516 
517                   gBS->FreePool (Scratch);
518                 }
519               }
520             }
521           }
522         }
523 
524         if (!SkipImage) {
525           //
526           // load image and start image
527           //
528           Status = gBS->LoadImage (
529                           FALSE,
530                           gPciBusDriverBinding.DriverBindingHandle,
531                           NULL,
532                           ImageBuffer,
533                           ImageLength,
534                           &ImageHandle
535                           );
536           if (!EFI_ERROR (Status)) {
537             Status = gBS->StartImage (ImageHandle, NULL, NULL);
538             if (!EFI_ERROR (Status)) {
539               AddDriver (PciDevice, ImageHandle);
540               retStatus = EFI_SUCCESS;
541             }
542           }
543         }
544 
545         RomBarOffset = RomBarOffset + ImageSize;
546       } else {
547         RomBarOffset = RomBarOffset + ImageSize;
548       }
549     } else {
550       RomBarOffset = RomBarOffset + ImageSize;
551     }
552 
553   } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
554 
555   return retStatus;
556 
557 }
558