]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Ebl/EfiDevice.c
Fix bug in LoadFv command. Don't free the buffer the file was loaded into as the...
[mirror_edk2.git] / EmbeddedPkg / Ebl / EfiDevice.c
CommitLineData
2ef2b01e
A
1/** @file\r
2 EBL commands for EFI and PI Devices\r
3\r
60274cca
HT
4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>\r
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
2ef2b01e 6\r
60274cca 7 This program and the accompanying materials\r
2ef2b01e
A
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "Ebl.h"\r
18\r
19\r
20EFI_DXE_SERVICES *gDS = NULL;\r
21\r
22\r
23/**\r
24 Print information about the File System device.\r
25\r
26 @param File Open File for the device\r
27\r
28**/\r
29VOID\r
30EblPrintFsInfo (\r
31 IN EFI_OPEN_FILE *File\r
32 )\r
33{\r
638909f1 34 CHAR16 *Str;\r
35\r
2ef2b01e
A
36 if (File == NULL) {\r
37 return;\r
38 }\r
39\r
40 AsciiPrint (" %a: ", File->DeviceName);\r
41 if (File->FsInfo != NULL) {\r
638909f1 42 for (Str = File->FsInfo->VolumeLabel; *Str != '\0'; Str++) {\r
43 if (*Str == ' ') {\r
44 // UI makes you enter _ for space, so make the printout match that\r
45 *Str = '_';\r
46 }\r
47 AsciiPrint ("%c", *Str);\r
48 }\r
49 AsciiPrint (":");\r
2ef2b01e
A
50 if (File->FsInfo->ReadOnly) {\r
51 AsciiPrint ("ReadOnly");\r
52 }\r
53 }\r
54\r
55 AsciiPrint ("\n");\r
56 EfiClose (File);\r
57}\r
58\r
59\r
60/**\r
61 Print information about the FV devices.\r
62\r
63 @param File Open File for the device\r
64\r
65**/\r
66VOID\r
67EblPrintFvbInfo (\r
68 IN EFI_OPEN_FILE *File\r
69 )\r
70{\r
71 if (File == NULL) {\r
72 return;\r
73 }\r
74\r
75 AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize);\r
76 EfiClose (File);\r
77}\r
78\r
79\r
80/**\r
81 Print information about the Blk IO devices.\r
82 If the device supports PXE dump out extra information\r
83\r
84 @param File Open File for the device\r
85\r
86**/\r
87VOID\r
88EblPrintBlkIoInfo (\r
89 IN EFI_OPEN_FILE *File\r
90 )\r
91{\r
92 UINT64 DeviceSize;\r
6f72e28d 93 UINTN Index;\r
94 UINTN Max;\r
95 EFI_OPEN_FILE *FsFile;\r
2ef2b01e
A
96\r
97 if (File == NULL) {\r
98 return;\r
99 }\r
100\r
101 AsciiPrint (" %a: ", File->DeviceName);\r
6f72e28d 102\r
103 // print out name of file system, if any, on this block device\r
104 Max = EfiGetDeviceCounts (EfiOpenFileSystem);\r
105 if (Max != 0) {\r
106 for (Index = 0; Index < Max; Index++) {\r
107 FsFile = EfiDeviceOpenByType (EfiOpenFileSystem, Index);\r
108 if (FsFile != NULL) {\r
109 if (FsFile->EfiHandle == File->EfiHandle) {\r
110 AsciiPrint ("fs%d: ", Index);\r
111 EfiClose (FsFile);\r
112 break;\r
113 }\r
0a0951ea 114 EfiClose (FsFile);\r
6f72e28d 115 }\r
6f72e28d 116 }\r
117 }\r
118\r
119 // Print out useful Block IO media properties\r
0a0951ea 120 if (File->FsBlockIoMedia->RemovableMedia) {\r
2ef2b01e
A
121 AsciiPrint ("Removable ");\r
122 }\r
0a0951ea 123 if (!File->FsBlockIoMedia->MediaPresent) {\r
124 AsciiPrint ("No Media\n");\r
125 } else {\r
126 if (File->FsBlockIoMedia->LogicalPartition) {\r
127 AsciiPrint ("Partition ");\r
128 }\r
129 DeviceSize = MultU64x32 (File->FsBlockIoMedia->LastBlock + 1, File->FsBlockIoMedia->BlockSize);\r
130 AsciiPrint ("Size = 0x%lX\n", DeviceSize);\r
2ef2b01e 131 }\r
2ef2b01e
A
132 EfiClose (File);\r
133}\r
134\r
2ef2b01e
A
135 /**\r
136 Print information about the Load File devices.\r
137 If the device supports PXE dump out extra information\r
138\r
139 @param File Open File for the device\r
140\r
141**/\r
142VOID\r
143EblPrintLoadFileInfo (\r
144 IN EFI_OPEN_FILE *File\r
145 )\r
146{\r
147 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
148 MAC_ADDR_DEVICE_PATH *MacAddr;\r
149 UINTN HwAddressSize;\r
150 UINTN Index;\r
151\r
152 if (File == NULL) {\r
153 return;\r
154 }\r
155\r
156 AsciiPrint (" %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle));\r
157\r
158 if (File->DevicePath != NULL) {\r
159 // Try to print out the MAC address\r
160 for (DevicePathNode = File->DevicePath; \r
161 !IsDevicePathEnd (DevicePathNode); \r
162 DevicePathNode = NextDevicePathNode (DevicePathNode)) {\r
163 \r
164 if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) {\r
165 MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode;\r
166 \r
167 HwAddressSize = sizeof (EFI_MAC_ADDRESS);\r
168 if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) {\r
169 HwAddressSize = 6;\r
170 }\r
171 \r
172 AsciiPrint ("MAC ");\r
173 for (Index = 0; Index < HwAddressSize; Index++) {\r
174 AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff);\r
175 }\r
176 } \r
177 }\r
178 }\r
179\r
180 AsciiPrint ("\n");\r
181 EfiClose (File);\r
182 return;\r
183}\r
184\r
185\r
186\r
187/**\r
188 Dump information about devices in the system. \r
189\r
190 fv: PI Firmware Volume\r
191 fs: EFI Simple File System\r
192 blk: EFI Block IO\r
193 LoadFile: EFI Load File Protocol (commonly PXE network boot)\r
194\r
195 Argv[0] - "device"\r
196\r
197 @param Argc Number of command arguments in Argv\r
198 @param Argv Array of strings that represent the parsed command line. \r
199 Argv[0] is the comamnd name\r
200\r
201 @return EFI_SUCCESS\r
202\r
203**/\r
204EFI_STATUS\r
205EblDeviceCmd (\r
206 IN UINTN Argc,\r
207 IN CHAR8 **Argv\r
208 )\r
209{\r
210 UINTN Index;\r
211 UINTN CurrentRow;\r
212 UINTN Max;\r
213\r
214 CurrentRow = 0;\r
208a8330 215\r
2ef2b01e
A
216 // Need to call here to make sure Device Counts are valid\r
217 EblUpdateDeviceLists ();\r
218\r
f6381f4c 219 // Now we can print out the info...\r
2ef2b01e
A
220 Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume);\r
221 if (Max != 0) {\r
222 AsciiPrint ("Firmware Volume Devices:\n");\r
223 for (Index = 0; Index < Max; Index++) {\r
224 EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index));\r
225 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {\r
226 break;\r
227 }\r
228 }\r
229 }\r
230\r
231 Max = EfiGetDeviceCounts (EfiOpenFileSystem);\r
232 if (Max != 0) {\r
233 AsciiPrint ("File System Devices:\n");\r
234 for (Index = 0; Index < Max; Index++) {\r
235 EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index));\r
236 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {\r
237 break;\r
238 }\r
239 }\r
240 }\r
241\r
242 Max = EfiGetDeviceCounts (EfiOpenBlockIo);\r
243 if (Max != 0) {\r
244 AsciiPrint ("Block IO Devices:\n");\r
245 for (Index = 0; Index < Max; Index++) {\r
246 EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index));\r
247 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {\r
248 break;\r
249 }\r
250 }\r
251 }\r
252 \r
253 Max = EfiGetDeviceCounts (EfiOpenLoadFile);\r
254 if (Max != 0) {\r
255 AsciiPrint ("LoadFile Devices: (usually network)\n");\r
256 for (Index = 0; Index < Max; Index++) {\r
257 EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index));\r
258 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {\r
259 break;\r
260 }\r
261 }\r
262 }\r
263\r
264 return EFI_SUCCESS;\r
265}\r
266\r
267\r
268/**\r
269 Start an EFI image (PE32+ with EFI defined entry point). \r
270\r
271 Argv[0] - "start"\r
272 Argv[1] - device name and path\r
273 Argv[2] - "" string to pass into image being started\r
274\r
275 start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the\r
276 ; ascii string arg to pass to the image\r
277 start fv0:\FV ; load an FV from an FV (not common)\r
278 start LoadFile0: ; load an FV via a PXE boot\r
279\r
280 @param Argc Number of command arguments in Argv\r
281 @param Argv Array of strings that represent the parsed command line. \r
282 Argv[0] is the comamnd name\r
283\r
284 @return EFI_SUCCESS\r
285\r
286**/\r
287EFI_STATUS\r
288EblStartCmd (\r
289 IN UINTN Argc,\r
290 IN CHAR8 **Argv\r
291 )\r
292{\r
293 EFI_STATUS Status;\r
294 EFI_OPEN_FILE *File;\r
295 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
296 EFI_HANDLE ImageHandle;\r
297 UINTN ExitDataSize;\r
298 CHAR16 *ExitData;\r
299 VOID *Buffer;\r
300 UINTN BufferSize;\r
301 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
302\r
303 ImageHandle = NULL;\r
304\r
305 if (Argc < 2) {\r
306 return EFI_INVALID_PARAMETER;\r
307 }\r
308\r
309 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
310 if (File == NULL) {\r
311 return EFI_INVALID_PARAMETER; \r
312 }\r
313\r
314 DevicePath = File->DevicePath;\r
315 if (DevicePath != NULL) {\r
316 // check for device path form: blk, fv, fs, and loadfile\r
317 Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle);\r
318 } else {\r
319 // Check for buffer form: A0x12345678:0x1234 syntax.\r
320 // Means load using buffer starting at 0x12345678 of size 0x1234.\r
321\r
322 Status = EfiReadAllocatePool (File, &Buffer, &BufferSize);\r
323 if (EFI_ERROR (Status)) {\r
324 EfiClose (File);\r
325 return Status;\r
326 }\r
327 Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle);\r
328\r
329 FreePool (Buffer);\r
330 }\r
331 \r
332 EfiClose (File);\r
333\r
334 if (!EFI_ERROR (Status)) {\r
335 if (Argc >= 3) {\r
336 // Argv[2] is a "" string that we pass directly to the EFI application without the ""\r
337 // We don't pass Argv[0] to the EFI Application (it's name) just the args\r
338 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);\r
339 ASSERT_EFI_ERROR (Status);\r
340 \r
341 ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]);\r
342 ImageInfo->LoadOptions = AllocatePool (ImageInfo->LoadOptionsSize);\r
343 AsciiStrCpy (ImageInfo->LoadOptions, Argv[2]);\r
344 }\r
345\r
346 // Transfer control to the EFI image we loaded with LoadImage()\r
347 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);\r
348 }\r
349\r
350 return Status;\r
351}\r
352\r
353\r
354/**\r
355 Load a Firmware Volume (FV) into memory from a device. This causes drivers in\r
356 the FV to be dispatched if the dependancies of the drivers are met.\r
357 \r
358 Argv[0] - "loadfv"\r
359 Argv[1] - device name and path\r
360\r
361 loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk\r
362 loadfv fv0:\FV ; load an FV from an FV (not common)\r
363 loadfv LoadFile0: ; load an FV via a PXE boot\r
364\r
365 @param Argc Number of command arguments in Argv\r
366 @param Argv Array of strings that represent the parsed command line. \r
367 Argv[0] is the comamnd name\r
368\r
369 @return EFI_SUCCESS\r
370\r
371**/\r
372EFI_STATUS\r
373EblLoadFvCmd (\r
374 IN UINTN Argc,\r
375 IN CHAR8 **Argv\r
376 )\r
377{\r
378 EFI_STATUS Status;\r
379 EFI_OPEN_FILE *File;\r
380 VOID *FvStart;\r
381 UINTN FvSize;\r
382 EFI_HANDLE FvHandle;\r
383\r
384\r
385 if (Argc < 2) {\r
386 return EFI_INVALID_PARAMETER;\r
387 }\r
388\r
389 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
390 if (File == NULL) {\r
391 return EFI_INVALID_PARAMETER; \r
392 }\r
393\r
394 if (File->Type == EfiOpenMemoryBuffer) {\r
395 // If it is a address just use it.\r
396 Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle);\r
397 } else {\r
398 // If it is a file read it into memory and use it\r
399 Status = EfiReadAllocatePool (File, &FvStart, &FvSize);\r
400 EfiClose (File);\r
401 if (EFI_ERROR (Status)) {\r
402 return Status;\r
403 }\r
404 \r
405 Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle);\r
abeca79a 406 if (EFI_ERROR (Status)) {\r
407 FreePool (FvStart);\r
408 } \r
2ef2b01e
A
409 }\r
410 return Status;\r
411}\r
412\r
413\r
414/**\r
415 Perform an EFI connect to connect devices that follow the EFI driver model. \r
416 If it is a PI system also call the dispatcher in case a new FV was made\r
417 availible by one of the connect EFI drivers (this is not a common case).\r
418 \r
419 Argv[0] - "connect"\r
420\r
421 @param Argc Number of command arguments in Argv\r
422 @param Argv Array of strings that represent the parsed command line. \r
423 Argv[0] is the comamnd name\r
424\r
425 @return EFI_SUCCESS\r
426\r
427**/\r
428EFI_STATUS\r
429EblConnectCmd (\r
430 IN UINTN Argc,\r
431 IN CHAR8 **Argv\r
432 )\r
433{\r
434 EFI_STATUS Status;\r
435 UINTN HandleCount;\r
436 EFI_HANDLE *HandleBuffer;\r
437 UINTN Index;\r
438 BOOLEAN Dispatch;\r
439 EFI_OPEN_FILE *File;\r
440\r
441\r
442 if (Argc > 1) {\r
443 if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) {\r
444 Status = gBS->LocateHandleBuffer (\r
445 AllHandles,\r
446 NULL,\r
447 NULL,\r
448 &HandleCount,\r
449 &HandleBuffer\r
450 );\r
451 if (EFI_ERROR (Status)) {\r
452 return Status;\r
453 }\r
454 \r
455 for (Index = 0; Index < HandleCount; Index++) {\r
456 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
457 }\r
458 \r
459 //\r
460 // Given we disconnect our console we should go and do a connect now\r
461 //\r
462 } else {\r
463 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
464 if (File != NULL) {\r
465 AsciiPrint ("Connecting %a\n", Argv[1]);\r
466 gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE);\r
467 EfiClose (File);\r
468 return EFI_SUCCESS;\r
469 }\r
470 }\r
471 }\r
472\r
473 Dispatch = FALSE;\r
474 do {\r
475 Status = gBS->LocateHandleBuffer (\r
476 AllHandles,\r
477 NULL,\r
478 NULL,\r
479 &HandleCount,\r
480 &HandleBuffer\r
481 );\r
482 if (EFI_ERROR (Status)) {\r
483 return Status;\r
484 }\r
485\r
486 for (Index = 0; Index < HandleCount; Index++) {\r
487 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
488 }\r
489\r
490 FreePool (HandleBuffer);\r
491\r
492 //\r
493 // Check to see if it's possible to dispatch an more DXE drivers.\r
494 // The BdsLibConnectAllEfi () may have made new DXE drivers show up.\r
495 // If anything is Dispatched Status == EFI_SUCCESS and we will try\r
496 // the connect again.\r
497 //\r
498 if (gDS == NULL) {\r
499 Status = EFI_NOT_FOUND;\r
500 } else {\r
501 Status = gDS->Dispatch ();\r
502 if (!EFI_ERROR (Status)) {\r
503 Dispatch = TRUE;\r
504 }\r
505 }\r
506\r
507 } while (!EFI_ERROR (Status));\r
508\r
509 if (Dispatch) {\r
510 AsciiPrint ("Connected and dispatched\n");\r
511 } else {\r
512 AsciiPrint ("Connect\n");\r
513 }\r
514\r
515 return EFI_SUCCESS;\r
516}\r
517\r
518\r
519\r
520CHAR8 *gMemMapType[] = {\r
521 "reserved ",\r
522 "LoaderCode",\r
523 "LoaderData",\r
524 "BS_code ",\r
525 "BS_data ",\r
526 "RT_code ",\r
527 "RT_data ",\r
528 "available ",\r
529 "Unusable ",\r
530 "ACPI_recl ",\r
531 "ACPI_NVS ",\r
532 "MemMapIO ",\r
533 "MemPortIO ",\r
534 "PAL_code "\r
535};\r
536\r
537\r
538/**\r
539 Dump out the EFI memory map\r
540 \r
541 Argv[0] - "memmap"\r
542\r
543 @param Argc Number of command arguments in Argv\r
544 @param Argv Array of strings that represent the parsed command line. \r
545 Argv[0] is the comamnd name\r
546\r
547 @return EFI_SUCCESS\r
548\r
549**/\r
550EFI_STATUS\r
551EblMemMapCmd (\r
552 IN UINTN Argc,\r
553 IN CHAR8 **Argv\r
554 )\r
555{\r
556 EFI_STATUS Status;\r
557 EFI_MEMORY_DESCRIPTOR *MemMap;\r
558 EFI_MEMORY_DESCRIPTOR *OrigMemMap;\r
559 UINTN MemMapSize;\r
560 UINTN MapKey;\r
561 UINTN DescriptorSize;\r
562 UINT32 DescriptorVersion;\r
563 UINT64 PageCount[EfiMaxMemoryType];\r
564 UINTN Index;\r
565 UINT64 EntrySize;\r
566 UINTN CurrentRow;\r
567 UINT64 TotalMemory;\r
568\r
569 ZeroMem (PageCount, sizeof (PageCount));\r
570\r
571 AsciiPrint ("EFI Memory Map\n");\r
572 \r
573 // First call is to figure out how big the buffer needs to be\r
574 MemMapSize = 0;\r
575 MemMap = NULL;\r
576 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
577 if (Status == EFI_BUFFER_TOO_SMALL) {\r
578 // In case the AllocatPool changes the memory map we added in some extra descriptors\r
579 MemMapSize += (DescriptorSize * 0x100);\r
580 OrigMemMap = MemMap = AllocatePool (MemMapSize);\r
581 if (OrigMemMap != NULL) {\r
582 // 2nd time we get the data\r
583 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
584 if (!EFI_ERROR (Status)) {\r
585 for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) {\r
586 EntrySize = LShiftU64 (MemMap->NumberOfPages, 12);\r
587 AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute);\r
588 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {\r
589 break;\r
590 }\r
591\r
592 PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages;\r
593 MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize);\r
594 }\r
595 }\r
596 \r
597 for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) {\r
598 if (PageCount[Index] != 0) {\r
599 AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12));\r
600 if (Index == EfiLoaderCode ||\r
601 Index == EfiLoaderData ||\r
602 Index == EfiBootServicesCode ||\r
603 Index == EfiBootServicesData ||\r
604 Index == EfiRuntimeServicesCode ||\r
605 Index == EfiRuntimeServicesData ||\r
606 Index == EfiConventionalMemory ||\r
607 Index == EfiACPIReclaimMemory ||\r
608 Index == EfiACPIMemoryNVS ||\r
609 Index == EfiPalCode\r
610 ) {\r
611 // Count total memory\r
612 TotalMemory += PageCount[Index];\r
613 }\r
614 }\r
615 }\r
616\r
617 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12));\r
618\r
619 FreePool (OrigMemMap);\r
620\r
621 }\r
622 }\r
623\r
624 return EFI_SUCCESS;\r
625}\r
626\r
627\r
628\r
629\r
630/**\r
631 Load a file into memory and optionally jump to it. A load addres can be \r
632 specified or automatically allocated. A quoted command line can optionally\r
633 be passed into the image. \r
634\r
635 Argv[0] - "go"\r
636 Argv[1] - Device Name:path for the file to load\r
637 Argv[2] - Address to load to or '*' if the load address will be allocated\r
638 Argv[3] - Optional Entry point to the image. Image will be called if present\r
639 Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs \r
640 to include the command name\r
641\r
642 go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX \r
643 from FV1 to location 0x10000 and call the entry point at 0x10010 passing \r
644 in "EblCmdX Arg2 Arg3 Arg4" as the arguments.\r
645\r
646 go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0 \r
647 to location allocated by this comamnd and call the entry point at offset 0x10 \r
648 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.\r
649\r
650 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return\r
651\r
652 @param Argc Number of command arguments in Argv\r
653 @param Argv Array of strings that represent the parsed command line. \r
654 Argv[0] is the comamnd name\r
655\r
656 @return EFI_SUCCESS\r
657\r
658**/\r
659EFI_STATUS\r
660EblGoCmd (\r
661 IN UINTN Argc,\r
662 IN CHAR8 **Argv\r
663 )\r
664{\r
665 EFI_STATUS Status;\r
666 EFI_OPEN_FILE *File;\r
667 VOID *Address;\r
668 UINTN Size;\r
669 EBL_COMMMAND EntryPoint;\r
670 UINTN EntryPointArgc;\r
671 CHAR8 *EntryPointArgv[MAX_ARGS];\r
672 \r
673\r
674 if (Argc <= 2) {\r
675 // device name and laod address are required\r
676 return EFI_SUCCESS;\r
677 }\r
678\r
679 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
680 if (File == NULL) {\r
681 AsciiPrint (" %a is not a valid path\n", Argv[1]);\r
682 return EFI_SUCCESS;\r
683 }\r
684\r
685 EntryPoint = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL);\r
686 if (Argv[2][0] == '*') {\r
687 // * Means allocate the buffer\r
688 Status = EfiReadAllocatePool (File, &Address, &Size);\r
689 \r
690 // EntryPoint is relatvie to the start of the image \r
691 EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address);\r
692\r
693 } else {\r
694 Address = (VOID *)AsciiStrHexToUintn (Argv[2]);\r
695 Size = File->Size;\r
696\r
697 // File->Size for LoadFile is lazy so we need to use the tell to figure it out\r
698 EfiTell (File, NULL);\r
699 Status = EfiRead (File, Address, &Size);\r
700 }\r
701\r
702 if (!EFI_ERROR (Status)) {\r
703 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address);\r
704\r
705 if (Argc > 3) {\r
706 if (Argc > 4) {\r
707 ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv);\r
708 } else {\r
709 EntryPointArgc = 1;\r
710 EntryPointArgv[0] = File->FileName;\r
711 }\r
712 \r
713 Status = EntryPoint (EntryPointArgc, EntryPointArgv);\r
714 }\r
715 }\r
716\r
717 EfiClose (File);\r
718 return Status;\r
719}\r
720\r
721#define FILE_COPY_CHUNK 0x20000\r
722\r
723EFI_STATUS\r
724EblFileCopyCmd (\r
725 IN UINTN Argc,\r
726 IN CHAR8 **Argv\r
727 )\r
728{\r
729 EFI_OPEN_FILE *Source = NULL;\r
730 EFI_OPEN_FILE *Destination = NULL;\r
731 EFI_STATUS Status = EFI_SUCCESS;\r
732 VOID *Buffer = NULL;\r
733 UINTN Size;\r
734 UINTN Offset;\r
735 UINTN Chunk = FILE_COPY_CHUNK;\r
f6381f4c 736\r
2ef2b01e
A
737 if (Argc < 3) {\r
738 return EFI_INVALID_PARAMETER;\r
739 }\r
740 \r
741 Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);\r
742 if (Source == NULL) {\r
743 AsciiPrint("Source file open error.\n");\r
744 return EFI_NOT_FOUND;\r
745 }\r
746 \r
747 Destination = EfiOpen(Argv[2], EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);\r
748 if (Destination == NULL) {\r
749 AsciiPrint("Destination file open error.\n");\r
750 return EFI_NOT_FOUND;\r
751 }\r
752\r
753 Buffer = AllocatePool(FILE_COPY_CHUNK);\r
754 if (Buffer == NULL) {\r
755 goto Exit;\r
756 }\r
757 \r
758 Size = EfiTell(Source, NULL);\r
759\r
760 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {\r
761 Chunk = FILE_COPY_CHUNK;\r
762 \r
763 Status = EfiRead(Source, Buffer, &Chunk);\r
764 if (EFI_ERROR(Status)) {\r
f6381f4c 765 AsciiPrint("Read file error %r\n", Status);\r
2ef2b01e
A
766 goto Exit;\r
767 }\r
768\r
769 Status = EfiWrite(Destination, Buffer, &Chunk);\r
770 if (EFI_ERROR(Status)) {\r
f6381f4c 771 AsciiPrint("Write file error %r\n", Status);\r
2ef2b01e
A
772 goto Exit;\r
773 } \r
774 }\r
775 \r
776 // Any left over?\r
777 if (Offset < Size) {\r
778 Chunk = Size - Offset;\r
779 \r
780 Status = EfiRead(Source, Buffer, &Chunk);\r
781 if (EFI_ERROR(Status)) {\r
f6381f4c 782 AsciiPrint("Read file error %r\n", Status);\r
2ef2b01e
A
783 goto Exit;\r
784 }\r
785\r
786 Status = EfiWrite(Destination, Buffer, &Chunk);\r
787 if (EFI_ERROR(Status)) {\r
f6381f4c 788 AsciiPrint("Write file error %r\n", Status);\r
2ef2b01e
A
789 goto Exit;\r
790 } \r
791 }\r
792\r
f6381f4c 793\r
2ef2b01e
A
794Exit:\r
795 if (Source != NULL) {\r
796 Status = EfiClose(Source);\r
797 if (EFI_ERROR(Status)) {\r
798 AsciiPrint("Source close error %r\n", Status);\r
799 }\r
800 }\r
2ef2b01e
A
801 if (Destination != NULL) {\r
802 Status = EfiClose(Destination);\r
803 if (EFI_ERROR(Status)) {\r
804 AsciiPrint("Destination close error %r\n", Status);\r
805 }\r
806 }\r
807 \r
808 if (Buffer != NULL) {\r
809 FreePool(Buffer);\r
810 }\r
811 \r
812 return Status;\r
813}\r
814\r
815EFI_STATUS\r
816EblFileDiffCmd (\r
817 IN UINTN Argc,\r
818 IN CHAR8 **Argv\r
819 )\r
820{\r
821 EFI_OPEN_FILE *File1 = NULL;\r
822 EFI_OPEN_FILE *File2 = NULL;\r
823 EFI_STATUS Status = EFI_SUCCESS;\r
824 VOID *Buffer1 = NULL;\r
825 VOID *Buffer2 = NULL;\r
826 UINTN Size1;\r
827 UINTN Size2;\r
828 UINTN Offset;\r
829 UINTN Chunk = FILE_COPY_CHUNK;\r
830 \r
831 if (Argc != 3) {\r
832 return EFI_INVALID_PARAMETER;\r
833 }\r
834 \r
835 File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);\r
836 if (File1 == NULL) {\r
837 AsciiPrint("File 1 open error.\n");\r
838 return EFI_NOT_FOUND;\r
839 }\r
840 \r
841 File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0);\r
842 if (File2 == NULL) {\r
843 AsciiPrint("File 2 open error.\n");\r
844 return EFI_NOT_FOUND;\r
845 }\r
846\r
847 Size1 = EfiTell(File1, NULL);\r
848 Size2 = EfiTell(File2, NULL);\r
849\r
850 if (Size1 != Size2) {\r
851 AsciiPrint("Files differ.\n");\r
852 goto Exit;\r
853 }\r
854\r
855 Buffer1 = AllocatePool(FILE_COPY_CHUNK);\r
856 if (Buffer1 == NULL) {\r
857 goto Exit;\r
858 }\r
859 \r
860 Buffer2 = AllocatePool(FILE_COPY_CHUNK);\r
861 if (Buffer2 == NULL) {\r
862 goto Exit;\r
863 } \r
864\r
865 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) {\r
866 Chunk = FILE_COPY_CHUNK;\r
867 \r
868 Status = EfiRead(File1, Buffer1, &Chunk);\r
869 if (EFI_ERROR(Status)) {\r
870 AsciiPrint("File 1 read error\n");\r
871 goto Exit;\r
872 }\r
873\r
874 Status = EfiRead(File2, Buffer2, &Chunk);\r
875 if (EFI_ERROR(Status)) {\r
876 AsciiPrint("File 2 read error\n");\r
877 goto Exit;\r
878 }\r
879 \r
880 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {\r
881 AsciiPrint("Files differ.\n");\r
882 goto Exit;\r
883 };\r
884 }\r
885 \r
886 // Any left over?\r
887 if (Offset < Size1) {\r
888 Chunk = Size1 - Offset;\r
889 \r
890 Status = EfiRead(File1, Buffer1, &Chunk);\r
891 if (EFI_ERROR(Status)) {\r
892 AsciiPrint("File 1 read error\n");\r
893 goto Exit;\r
894 }\r
895\r
896 Status = EfiRead(File2, Buffer2, &Chunk);\r
897 if (EFI_ERROR(Status)) {\r
898 AsciiPrint("File 2 read error\n");\r
899 goto Exit;\r
900 } \r
901 }\r
902 \r
903 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {\r
904 AsciiPrint("Files differ.\n");\r
905 } else {\r
906 AsciiPrint("Files are identical.\n");\r
907 }\r
908\r
909Exit:\r
910 if (File1 != NULL) {\r
911 Status = EfiClose(File1);\r
912 if (EFI_ERROR(Status)) {\r
913 AsciiPrint("File 1 close error %r\n", Status);\r
914 }\r
915 }\r
916 \r
917 if (File2 != NULL) {\r
918 Status = EfiClose(File2);\r
919 if (EFI_ERROR(Status)) {\r
920 AsciiPrint("File 2 close error %r\n", Status);\r
921 }\r
922 }\r
923 \r
924 if (Buffer1 != NULL) {\r
925 FreePool(Buffer1);\r
926 }\r
927 \r
928 if (Buffer2 != NULL) {\r
929 FreePool(Buffer2);\r
930 }\r
931 \r
932 return Status;\r
933}\r
934\r
935GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] =\r
936{\r
937 {\r
938 "connect",\r
939 "[d]; Connect all EFI devices. d means disconnect",\r
940 NULL,\r
941 EblConnectCmd\r
942 },\r
943 {\r
944 "device",\r
945 "; Show information about boot devices",\r
946 NULL,\r
947 EblDeviceCmd\r
948 },\r
949 {\r
950 "go",\r
951 " dev:path loadaddress entrypoint args; load to given address and jump in", \r
952 NULL,\r
953 EblGoCmd\r
954 },\r
955 {\r
956 "loadfv",\r
957 " devname; Load PI FV from device", \r
958 NULL,\r
959 EblLoadFvCmd\r
960 },\r
961 {\r
962 "start",\r
963 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI", \r
964 NULL,\r
965 EblStartCmd\r
966 },\r
967 {\r
968 "memmap",\r
969 "; dump EFI memory map", \r
970 NULL,\r
971 EblMemMapCmd\r
972 },\r
973 {\r
974 "cp",\r
975 " file1 file2; copy file",\r
976 NULL,\r
977 EblFileCopyCmd\r
978 },\r
979 {\r
980 "diff",\r
981 " file1 file2; compare files",\r
982 NULL,\r
983 EblFileDiffCmd\r
984 }\r
985};\r
986\r
987\r
988/**\r
989 Initialize the commands in this in this file\r
990**/\r
991\r
992VOID\r
993EblInitializeDeviceCmd (\r
994 VOID\r
995 )\r
996{\r
997 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);\r
998 EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));\r
999}\r
1000\r