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