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