• 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   PciRomTable.c
15 
16 Abstract:
17 
18   Option Rom Support for PCI Bus Driver
19 
20 Revision History
21 
22 --*/
23 
24 #include "PciBus.h"
25 
26 typedef struct {
27   EFI_HANDLE  ImageHandle;
28   UINTN       Seg;
29   UINT8       Bus;
30   UINT8       Dev;
31   UINT8       Func;
32 } EFI_PCI_ROM_IMAGE_MAPPING;
33 
34 UINTN                      mNumberOfPciRomImages     = 0;
35 UINTN                      mMaxNumberOfPciRomImages  = 0;
36 EFI_PCI_ROM_IMAGE_MAPPING  *mRomImageTable           = NULL;
37 
38 CHAR16 mHexDigit[17] = L"0123456789ABCDEF";
39 
40 VOID
PciRomAddImageMapping(IN EFI_HANDLE ImageHandle,IN UINTN Seg,IN UINT8 Bus,IN UINT8 Dev,IN UINT8 Func)41 PciRomAddImageMapping (
42   IN EFI_HANDLE  ImageHandle,
43   IN UINTN       Seg,
44   IN UINT8       Bus,
45   IN UINT8       Dev,
46   IN UINT8       Func
47   )
48 
49 {
50   EFI_PCI_ROM_IMAGE_MAPPING *TempMapping;
51 
52   if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) {
53 
54     mMaxNumberOfPciRomImages += 0x20;
55 
56     TempMapping = NULL;
57     TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
58     if (TempMapping == NULL) {
59       return ;
60     }
61 
62     CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
63 
64     if (mRomImageTable != NULL) {
65       gBS->FreePool (mRomImageTable);
66     }
67 
68     mRomImageTable = TempMapping;
69   }
70 
71   mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle;
72   mRomImageTable[mNumberOfPciRomImages].Seg         = Seg;
73   mRomImageTable[mNumberOfPciRomImages].Bus         = Bus;
74   mRomImageTable[mNumberOfPciRomImages].Dev         = Dev;
75   mRomImageTable[mNumberOfPciRomImages].Func        = Func;
76   mNumberOfPciRomImages++;
77 }
78 
79 VOID
HexToString(CHAR16 * String,UINTN Value,UINTN Digits)80 HexToString (
81   CHAR16  *String,
82   UINTN   Value,
83   UINTN   Digits
84   )
85 
86 {
87   for (; Digits > 0; Digits--, String++) {
88     *String = mHexDigit[((Value >> (4*(Digits-1))) & 0x0f)];
89   }
90 }
91 
92 EFI_STATUS
PciRomLoadEfiDriversFromRomImage(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_PCI_OPTION_ROM_DESCRIPTOR * PciOptionRomDescriptor)93 PciRomLoadEfiDriversFromRomImage (
94   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
95   IN EFI_PCI_OPTION_ROM_DESCRIPTOR  *PciOptionRomDescriptor
96   )
97 /*++
98 
99 Routine Description:
100   Command entry point.
101 
102 Arguments:
103   ImageHandle     The image handle.
104   SystemTable     The system table.
105 
106 Returns:
107   EFI_SUCCESS             - The command completed successfully
108   EFI_INVALID_PARAMETER   - Command usage error
109   EFI_UNSUPPORTED         - Protocols unsupported
110   EFI_OUT_OF_RESOURCES    - Out of memory
111   Other value             - Unknown error
112 
113 --*/
114 {
115   VOID                          *RomBar;
116   UINTN                         RomSize;
117   CHAR16                        *FileName;
118   EFI_PCI_EXPANSION_ROM_HEADER  *EfiRomHeader;
119   PCI_DATA_STRUCTURE            *Pcir;
120   UINTN                         ImageIndex;
121   UINTN                         RomBarOffset;
122   UINT32                        ImageSize;
123   UINT16                        ImageOffset;
124   EFI_HANDLE                    ImageHandle;
125   EFI_STATUS                    Status;
126   EFI_STATUS                    retStatus;
127   EFI_DEVICE_PATH_PROTOCOL      *FilePath;
128   BOOLEAN                       SkipImage;
129   UINT32                        DestinationSize;
130   UINT32                        ScratchSize;
131   UINT8                         *Scratch;
132   VOID                          *ImageBuffer;
133   VOID                          *DecompressedImageBuffer;
134   UINT32                        ImageLength;
135   EFI_DECOMPRESS_PROTOCOL       *Decompress;
136   UINT32                        InitializationSize;
137 
138   RomBar = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress;
139   RomSize = (UINTN) PciOptionRomDescriptor->RomLength;
140   FileName = L"PciRom Seg=00000000 Bus=00 Dev=00 Func=00 Image=0000";
141 
142   HexToString (&FileName[11], PciOptionRomDescriptor->Seg, 8);
143   HexToString (&FileName[24], PciOptionRomDescriptor->Bus, 2);
144   HexToString (&FileName[31], PciOptionRomDescriptor->Dev, 2);
145   HexToString (&FileName[39], PciOptionRomDescriptor->Func, 2);
146 
147   ImageIndex    = 0;
148   retStatus     = EFI_NOT_FOUND;
149   RomBarOffset  = (UINTN) RomBar;
150 
151   do {
152 
153     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset;
154 
155 
156     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
157       return retStatus;
158     }
159 
160     //
161     // If the pointer to the PCI Data Structure is invalid, no further images can be located.
162     // The PCI Data Structure must be DWORD aligned.
163     //
164     if (EfiRomHeader->PcirOffset == 0 ||
165         (EfiRomHeader->PcirOffset & 3) != 0 ||
166         RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
167       break;
168     }
169     Pcir      = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset);
170     //
171     // If a valid signature is not present in the PCI Data Structure, no further images can be located.
172     //
173     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
174       break;
175     }
176     ImageSize = Pcir->ImageLength * 512;
177     if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) {
178       break;
179     }
180 
181     if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
182         (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
183         ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
184          (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
185 
186       ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
187       InitializationSize      = EfiRomHeader->InitializationSize * 512;
188 
189       if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
190 
191         ImageBuffer             = (VOID *) (UINTN) (RomBarOffset + ImageOffset);
192         ImageLength             = InitializationSize - ImageOffset;
193         DecompressedImageBuffer = NULL;
194 
195         //
196         // decompress here if needed
197         //
198         SkipImage = FALSE;
199         if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
200           SkipImage = TRUE;
201         }
202 
203         if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
204           Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
205           if (EFI_ERROR (Status)) {
206             SkipImage = TRUE;
207           } else {
208             SkipImage = TRUE;
209             Status = Decompress->GetInfo (
210                                   Decompress,
211                                   ImageBuffer,
212                                   ImageLength,
213                                   &DestinationSize,
214                                   &ScratchSize
215                                   );
216             if (!EFI_ERROR (Status)) {
217               DecompressedImageBuffer = NULL;
218               DecompressedImageBuffer = AllocatePool (DestinationSize);
219               if (DecompressedImageBuffer != NULL) {
220                 Scratch = AllocatePool (ScratchSize);
221                 if (Scratch != NULL) {
222                   Status = Decompress->Decompress (
223                                         Decompress,
224                                         ImageBuffer,
225                                         ImageLength,
226                                         DecompressedImageBuffer,
227                                         DestinationSize,
228                                         Scratch,
229                                         ScratchSize
230                                         );
231                   if (!EFI_ERROR (Status)) {
232                     ImageBuffer = DecompressedImageBuffer;
233                     ImageLength = DestinationSize;
234                     SkipImage   = FALSE;
235                   }
236 
237                   gBS->FreePool (Scratch);
238                 }
239               }
240             }
241           }
242         }
243 
244         if (!SkipImage) {
245 
246           //
247           // load image and start image
248           //
249 
250           HexToString (&FileName[48], ImageIndex, 4);
251           FilePath = FileDevicePath (NULL, FileName);
252 
253           Status = gBS->LoadImage (
254                           FALSE,
255                           This->ImageHandle,
256                           FilePath,
257                           ImageBuffer,
258                           ImageLength,
259                           &ImageHandle
260                           );
261           if (!EFI_ERROR (Status)) {
262             Status = gBS->StartImage (ImageHandle, NULL, NULL);
263             if (!EFI_ERROR (Status)) {
264               PciRomAddImageMapping (
265                 ImageHandle,
266                 PciOptionRomDescriptor->Seg,
267                 PciOptionRomDescriptor->Bus,
268                 PciOptionRomDescriptor->Dev,
269                 PciOptionRomDescriptor->Func
270                 );
271               retStatus = Status;
272             }
273           }
274           if (FilePath != NULL) {
275             gBS->FreePool (FilePath);
276           }
277         }
278 
279         if (DecompressedImageBuffer != NULL) {
280           gBS->FreePool (DecompressedImageBuffer);
281         }
282 
283       }
284     }
285 
286     RomBarOffset = RomBarOffset + ImageSize;
287     ImageIndex++;
288   } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize));
289 
290   return retStatus;
291 }
292 
293 EFI_STATUS
PciRomLoadEfiDriversFromOptionRomTable(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo)294 PciRomLoadEfiDriversFromOptionRomTable (
295   IN EFI_DRIVER_BINDING_PROTOCOL      *This,
296   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo
297   )
298 /*++
299 
300 Routine Description:
301 
302 Arguments:
303 
304 Returns:
305 
306 --*/
307 {
308   EFI_STATUS                        Status;
309   EFI_PCI_OPTION_ROM_TABLE          *PciOptionRomTable;
310   EFI_PCI_OPTION_ROM_DESCRIPTOR     *PciOptionRomDescriptor;
311   UINTN                             Index;
312   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
313   UINT16                            MinBus;
314   UINT16                            MaxBus;
315 
316   Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable);
317   if (EFI_ERROR (Status)) {
318     return EFI_NOT_FOUND;
319   }
320 
321   Status = EFI_NOT_FOUND;
322 
323   for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) {
324     PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index];
325     if (!PciOptionRomDescriptor->DontLoadEfiRom) {
326       if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber) {
327         Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
328         if (EFI_ERROR (Status)) {
329           return Status;
330         }
331 
332         PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL);
333         if ((MinBus <= PciOptionRomDescriptor->Bus) && (PciOptionRomDescriptor->Bus <= MaxBus)) {
334           Status = PciRomLoadEfiDriversFromRomImage (This, PciOptionRomDescriptor);
335           PciOptionRomDescriptor->DontLoadEfiRom |= 2;
336         }
337       }
338     }
339   }
340 
341   return Status;
342 }
343 
344 EFI_STATUS
PciRomGetRomResourceFromPciOptionRomTable(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo,PCI_IO_DEVICE * PciIoDevice)345 PciRomGetRomResourceFromPciOptionRomTable (
346   IN EFI_DRIVER_BINDING_PROTOCOL      *This,
347   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,
348   PCI_IO_DEVICE                       *PciIoDevice
349   )
350 /*++
351 
352 Routine Description:
353 
354 Arguments:
355 
356 Returns:
357 
358 --*/
359 {
360   EFI_STATUS                    Status;
361   EFI_PCI_OPTION_ROM_TABLE      *PciOptionRomTable;
362   EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor;
363   UINTN                         Index;
364 
365   Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable);
366   if (EFI_ERROR (Status)) {
367     return EFI_NOT_FOUND;
368   }
369 
370   for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) {
371     PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index];
372     if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber &&
373         PciOptionRomDescriptor->Bus == PciIoDevice->BusNumber         &&
374         PciOptionRomDescriptor->Dev == PciIoDevice->DeviceNumber      &&
375         PciOptionRomDescriptor->Func == PciIoDevice->FunctionNumber ) {
376 
377       PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress;
378       PciIoDevice->PciIo.RomSize  = (UINTN) PciOptionRomDescriptor->RomLength;
379     }
380   }
381 
382   for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
383     if (mRomImageTable[Index].Seg  == PciRootBridgeIo->SegmentNumber &&
384         mRomImageTable[Index].Bus  == PciIoDevice->BusNumber         &&
385         mRomImageTable[Index].Dev  == PciIoDevice->DeviceNumber      &&
386         mRomImageTable[Index].Func == PciIoDevice->FunctionNumber    ) {
387 
388       AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle);
389     }
390   }
391 
392   return EFI_SUCCESS;
393 }
394