1 /** @file
2   Main file for LoadPciRom shell Debug1 function.
3 
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "UefiShellDebug1CommandsLib.h"
17 #include <IndustryStandard/Pci22.h>
18 #include <IndustryStandard/Pci23.h>
19 #include <IndustryStandard/PeImage.h>
20 #include <Protocol/Decompress.h>
21 
22 /**
23   Connects all available drives and controllers.
24 
25   @retval EFI_SUCCESS     The operation was successful.
26   @retval EFI_ABORTED     The abort mechanism was received.
27 **/
28 EFI_STATUS
29 LoadPciRomConnectAllDriversToAllControllers (
30   VOID
31   );
32 
33 /**
34   Command entry point.
35 
36   @param[in] RomBar       The Rom Base address.
37   @param[in] RomSize      The Rom size.
38   @param[in] FileName     The file name.
39 
40   @retval EFI_SUCCESS             The command completed successfully.
41   @retval EFI_INVALID_PARAMETER   Command usage error.
42   @retval EFI_UNSUPPORTED         Protocols unsupported.
43   @retval EFI_OUT_OF_RESOURCES    Out of memory.
44   @retval Other value             Unknown error.
45 **/
46 EFI_STATUS
47 LoadEfiDriversFromRomImage (
48   VOID                      *RomBar,
49   UINTN                     RomSize,
50   CONST CHAR16              *FileName
51   );
52 
53 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
54   {L"-nc", TypeFlag},
55   {NULL, TypeMax}
56   };
57 
58 /**
59   Function for 'loadpcirom' command.
60 
61   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
62   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
63 **/
64 SHELL_STATUS
65 EFIAPI
ShellCommandRunLoadPciRom(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)66 ShellCommandRunLoadPciRom (
67   IN EFI_HANDLE        ImageHandle,
68   IN EFI_SYSTEM_TABLE  *SystemTable
69   )
70 {
71   EFI_SHELL_FILE_INFO     *FileList;
72   UINTN                   SourceSize;
73   UINT8                   *File1Buffer;
74   EFI_STATUS              Status;
75   LIST_ENTRY              *Package;
76   CHAR16                  *ProblemParam;
77   SHELL_STATUS            ShellStatus;
78   BOOLEAN                 Connect;
79   CONST CHAR16            *Param;
80   UINTN                   ParamCount;
81   EFI_SHELL_FILE_INFO     *Node;
82   //
83   // Local variable initializations
84   //
85   File1Buffer = NULL;
86   ShellStatus = SHELL_SUCCESS;
87   FileList    = NULL;
88 
89 
90   //
91   // verify number of arguments
92   //
93   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
94   if (EFI_ERROR(Status)) {
95     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
96       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"loadpcirom", ProblemParam);
97       FreePool(ProblemParam);
98       ShellStatus = SHELL_INVALID_PARAMETER;
99     } else {
100       ASSERT(FALSE);
101     }
102   } else {
103     if (ShellCommandLineGetCount(Package) < 2) {
104       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"loadpcirom");
105       ShellStatus = SHELL_INVALID_PARAMETER;
106     } else {
107       if (ShellCommandLineGetFlag(Package, L"-nc")) {
108         Connect = FALSE;
109       } else {
110         Connect = TRUE;
111       }
112 
113       //
114       // get a list with each file specified by parameters
115       // if parameter is a directory then add all the files below it to the list
116       //
117       for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount)
118           ; Param != NULL
119           ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount)
120          ){
121         Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
122         if (EFI_ERROR(Status)) {
123           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Param);
124           ShellStatus = SHELL_ACCESS_DENIED;
125           break;
126         }
127       }
128       if (ShellStatus == SHELL_SUCCESS  && FileList != NULL) {
129         //
130         // loop through the list and make sure we are not aborting...
131         //
132         for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link)
133             ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag()
134             ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link)
135            ){
136           if (EFI_ERROR(Node->Status)){
137             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName);
138             ShellStatus = SHELL_INVALID_PARAMETER;
139             continue;
140           }
141           if (FileHandleIsDirectory(Node->Handle) == EFI_SUCCESS) {
142             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_DIR), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName);
143             ShellStatus = SHELL_INVALID_PARAMETER;
144             continue;
145           }
146           SourceSize  = (UINTN) Node->Info->FileSize;
147           File1Buffer = AllocateZeroPool (SourceSize);
148           if (File1Buffer == NULL) {
149             ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"loadpcirom");
150             ShellStatus = SHELL_OUT_OF_RESOURCES;
151             continue;
152           }
153           Status = gEfiShellProtocol->ReadFile(Node->Handle, &SourceSize, File1Buffer);
154           if (EFI_ERROR(Status)) {
155             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_READ_FAIL), gShellDebug1HiiHandle, L"loadpcirom", Node->FullName);
156             ShellStatus = SHELL_INVALID_PARAMETER;
157           } else {
158             Status = LoadEfiDriversFromRomImage (
159                       File1Buffer,
160                       SourceSize,
161                       Node->FullName
162                      );
163 
164             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_PCI_ROM_RES), gShellDebug1HiiHandle, Node->FullName, Status);
165           }
166           FreePool(File1Buffer);
167         }
168       } else if (ShellStatus == SHELL_SUCCESS) {
169         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_FILE_NOT_SPEC), gShellDebug1HiiHandle, "loadpcirom");
170         ShellStatus = SHELL_NOT_FOUND;
171       }
172       if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
173         Status = ShellCloseFileMetaArg(&FileList);
174       }
175       FileList = NULL;
176 
177       if (Connect) {
178         Status = LoadPciRomConnectAllDriversToAllControllers ();
179       }
180     }
181   }
182 
183   return (ShellStatus);
184 }
185 
186 /**
187   Command entry point.
188 
189   @param[in] RomBar       The Rom Base address.
190   @param[in] RomSize      The Rom size.
191   @param[in] FileName     The file name.
192 
193   @retval EFI_SUCCESS             The command completed successfully.
194   @retval EFI_INVALID_PARAMETER   Command usage error.
195   @retval EFI_UNSUPPORTED         Protocols unsupported.
196   @retval EFI_OUT_OF_RESOURCES    Out of memory.
197   @retval Other value             Unknown error.
198 **/
199 EFI_STATUS
LoadEfiDriversFromRomImage(VOID * RomBar,UINTN RomSize,CONST CHAR16 * FileName)200 LoadEfiDriversFromRomImage (
201   VOID                      *RomBar,
202   UINTN                     RomSize,
203   CONST CHAR16              *FileName
204   )
205 
206 {
207   EFI_PCI_EXPANSION_ROM_HEADER  *EfiRomHeader;
208   PCI_DATA_STRUCTURE            *Pcir;
209   UINTN                         ImageIndex;
210   UINTN                         RomBarOffset;
211   UINT32                        ImageSize;
212   UINT16                        ImageOffset;
213   EFI_HANDLE                    ImageHandle;
214   EFI_STATUS                    Status;
215   EFI_STATUS                    ReturnStatus;
216   CHAR16                        RomFileName[280];
217   EFI_DEVICE_PATH_PROTOCOL      *FilePath;
218   BOOLEAN                       SkipImage;
219   UINT32                        DestinationSize;
220   UINT32                        ScratchSize;
221   UINT8                         *Scratch;
222   VOID                          *ImageBuffer;
223   VOID                          *DecompressedImageBuffer;
224   UINT32                        ImageLength;
225   EFI_DECOMPRESS_PROTOCOL       *Decompress;
226   UINT32                        InitializationSize;
227 
228   ImageIndex    = 0;
229   ReturnStatus     = EFI_NOT_FOUND;
230   RomBarOffset  = (UINTN) RomBar;
231 
232   do {
233 
234     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset;
235 
236     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
237       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_CORRUPT), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex);
238 //      PrintToken (STRING_TOKEN (STR_LOADPCIROM_IMAGE_CORRUPT), HiiHandle, ImageIndex);
239       return ReturnStatus;
240     }
241 
242     //
243     // If the pointer to the PCI Data Structure is invalid, no further images can be located.
244     // The PCI Data Structure must be DWORD aligned.
245     //
246     if (EfiRomHeader->PcirOffset == 0 ||
247         (EfiRomHeader->PcirOffset & 3) != 0 ||
248         RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
249       break;
250     }
251 
252     Pcir      = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset);
253     //
254     // If a valid signature is not present in the PCI Data Structure, no further images can be located.
255     //
256     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
257       break;
258     }
259     ImageSize = Pcir->ImageLength * 512;
260     if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) {
261       break;
262     }
263 
264     if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
265         (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
266         ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
267          (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
268 
269       ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
270       InitializationSize      = EfiRomHeader->InitializationSize * 512;
271 
272       if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
273 
274         ImageBuffer             = (VOID *) (UINTN) (RomBarOffset + ImageOffset);
275         ImageLength             = InitializationSize - ImageOffset;
276         DecompressedImageBuffer = NULL;
277 
278         //
279         // decompress here if needed
280         //
281         SkipImage = FALSE;
282         if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
283           SkipImage = TRUE;
284         }
285 
286         if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
287           Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID**)&Decompress);
288           ASSERT_EFI_ERROR(Status);
289           if (EFI_ERROR (Status)) {
290             SkipImage = TRUE;
291           } else {
292             SkipImage = TRUE;
293             Status = Decompress->GetInfo (
294                                   Decompress,
295                                   ImageBuffer,
296                                   ImageLength,
297                                   &DestinationSize,
298                                   &ScratchSize
299                                  );
300             if (!EFI_ERROR (Status)) {
301               DecompressedImageBuffer = AllocateZeroPool (DestinationSize);
302               if (ImageBuffer != NULL) {
303                 Scratch = AllocateZeroPool (ScratchSize);
304                 if (Scratch != NULL) {
305                   Status = Decompress->Decompress (
306                                         Decompress,
307                                         ImageBuffer,
308                                         ImageLength,
309                                         DecompressedImageBuffer,
310                                         DestinationSize,
311                                         Scratch,
312                                         ScratchSize
313                                        );
314                   if (!EFI_ERROR (Status)) {
315                     ImageBuffer = DecompressedImageBuffer;
316                     ImageLength = DestinationSize;
317                     SkipImage   = FALSE;
318                   }
319 
320                   FreePool (Scratch);
321                 }
322               }
323             }
324           }
325         }
326 
327         if (!SkipImage) {
328           //
329           // load image and start image
330           //
331           UnicodeSPrint (RomFileName, sizeof (RomFileName), L"%s[%d]", FileName, ImageIndex);
332           FilePath = FileDevicePath (NULL, RomFileName);
333 
334           Status = gBS->LoadImage (
335                         TRUE,
336                         gImageHandle,
337                         FilePath,
338                         ImageBuffer,
339                         ImageLength,
340                         &ImageHandle
341                        );
342           if (EFI_ERROR (Status)) {
343             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_LOAD_FAIL), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex);
344 //            PrintToken (STRING_TOKEN (STR_LOADPCIROM_LOAD_IMAGE_ERROR), HiiHandle, ImageIndex, Status);
345           } else {
346             Status = gBS->StartImage (ImageHandle, NULL, NULL);
347             if (EFI_ERROR (Status)) {
348               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOADPCIROM_START_FAIL), gShellDebug1HiiHandle, L"loadpcirom", FileName, ImageIndex);
349 //              PrintToken (STRING_TOKEN (STR_LOADPCIROM_START_IMAGE), HiiHandle, ImageIndex, Status);
350             } else {
351               ReturnStatus = Status;
352             }
353           }
354         }
355 
356         if (DecompressedImageBuffer != NULL) {
357           FreePool (DecompressedImageBuffer);
358         }
359 
360       }
361     }
362 
363     RomBarOffset = RomBarOffset + ImageSize;
364     ImageIndex++;
365   } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize));
366 
367   return ReturnStatus;
368 }
369 
370 /**
371   Connects all available drives and controllers.
372 
373   @retval EFI_SUCCESS     The operation was successful.
374   @retval EFI_ABORTED     The abort mechanism was received.
375 **/
376 EFI_STATUS
LoadPciRomConnectAllDriversToAllControllers(VOID)377 LoadPciRomConnectAllDriversToAllControllers (
378   VOID
379   )
380 {
381   EFI_STATUS  Status;
382   UINTN       HandleCount;
383   EFI_HANDLE  *HandleBuffer;
384   UINTN       Index;
385 
386   Status = gBS->LocateHandleBuffer (
387                   AllHandles,
388                   NULL,
389                   NULL,
390                   &HandleCount,
391                   &HandleBuffer
392                   );
393   if (EFI_ERROR (Status)) {
394     return Status;
395   }
396 
397   for (Index = 0; Index < HandleCount; Index++) {
398     if (ShellGetExecutionBreakFlag ()) {
399       Status = EFI_ABORTED;
400       break;
401     }
402     gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
403   }
404 
405   if (HandleBuffer != NULL) {
406     FreePool (HandleBuffer);
407   }
408   return Status;
409 }
410