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