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       AsciiStrCpy (ImageInfo->LoadOptions, 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;
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     DestFileName = (CHAR8*)AllocatePool (FileNameLen + AsciiStrLen (SrcFileName) + 1);
790     AsciiStrCpy (DestFileName, Argv[2]);
791     AsciiStrCat (DestFileName, SrcFileName);
792   }
793 
794   Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
795   if (Source == NULL) {
796     AsciiPrint("Source file open error.\n");
797     return EFI_NOT_FOUND;
798   }
799 
800   Destination = EfiOpen(DestFileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
801   if (Destination == NULL) {
802     AsciiPrint("Destination file open error.\n");
803     return EFI_NOT_FOUND;
804   }
805 
806   Buffer = AllocatePool(FILE_COPY_CHUNK);
807   if (Buffer == NULL) {
808     goto Exit;
809   }
810 
811   Size = EfiTell(Source, NULL);
812 
813   for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {
814     Chunk = FILE_COPY_CHUNK;
815 
816     Status = EfiRead(Source, Buffer, &Chunk);
817     if (EFI_ERROR(Status)) {
818       AsciiPrint("Read file error %r\n", Status);
819       goto Exit;
820     }
821 
822     Status = EfiWrite(Destination, Buffer, &Chunk);
823     if (EFI_ERROR(Status)) {
824       AsciiPrint("Write file error %r\n", Status);
825       goto Exit;
826     }
827   }
828 
829   // Any left over?
830   if (Offset < Size) {
831     Chunk = Size - Offset;
832 
833     Status = EfiRead(Source, Buffer, &Chunk);
834     if (EFI_ERROR(Status)) {
835       AsciiPrint("Read file error %r\n", Status);
836       goto Exit;
837     }
838 
839     Status = EfiWrite(Destination, Buffer, &Chunk);
840     if (EFI_ERROR(Status)) {
841       AsciiPrint("Write file error %r\n", Status);
842       goto Exit;
843     }
844   }
845 
846 
847 Exit:
848   if (Source != NULL) {
849     Status = EfiClose(Source);
850     if (EFI_ERROR(Status)) {
851       AsciiPrint("Source close error %r\n", Status);
852     }
853   }
854   if (Destination != NULL) {
855     Status = EfiClose(Destination);
856     if (EFI_ERROR(Status)) {
857       AsciiPrint("Destination close error %r\n", Status);
858     }
859 
860     // Case when we have concated the filename to the destination directory
861     if (DestFileName != Argv[2]) {
862       FreePool (DestFileName);
863     }
864   }
865 
866   if (Buffer != NULL) {
867     FreePool(Buffer);
868   }
869 
870   return Status;
871 }
872 
873 EFI_STATUS
874 EFIAPI
EblFileDiffCmd(IN UINTN Argc,IN CHAR8 ** Argv)875 EblFileDiffCmd (
876   IN UINTN  Argc,
877   IN CHAR8  **Argv
878   )
879 {
880   EFI_OPEN_FILE *File1   = NULL;
881   EFI_OPEN_FILE *File2   = NULL;
882   EFI_STATUS    Status   = EFI_SUCCESS;
883   VOID          *Buffer1 = NULL;
884   VOID          *Buffer2 = NULL;
885   UINTN         Size1;
886   UINTN         Size2;
887   UINTN         Offset;
888   UINTN         Chunk   = FILE_COPY_CHUNK;
889 
890   if (Argc != 3) {
891     return EFI_INVALID_PARAMETER;
892   }
893 
894   File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
895   if (File1 == NULL) {
896     AsciiPrint("File 1 open error.\n");
897     return EFI_NOT_FOUND;
898   }
899 
900   File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0);
901   if (File2 == NULL) {
902     AsciiPrint("File 2 open error.\n");
903     return EFI_NOT_FOUND;
904   }
905 
906   Size1 = EfiTell(File1, NULL);
907   Size2 = EfiTell(File2, NULL);
908 
909   if (Size1 != Size2) {
910     AsciiPrint("Files differ.\n");
911     goto Exit;
912   }
913 
914   Buffer1 = AllocatePool(FILE_COPY_CHUNK);
915   if (Buffer1 == NULL) {
916     goto Exit;
917   }
918 
919   Buffer2 = AllocatePool(FILE_COPY_CHUNK);
920   if (Buffer2 == NULL) {
921     goto Exit;
922   }
923 
924   for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) {
925     Chunk = FILE_COPY_CHUNK;
926 
927     Status = EfiRead(File1, Buffer1, &Chunk);
928     if (EFI_ERROR(Status)) {
929       AsciiPrint("File 1 read error\n");
930       goto Exit;
931     }
932 
933     Status = EfiRead(File2, Buffer2, &Chunk);
934     if (EFI_ERROR(Status)) {
935       AsciiPrint("File 2 read error\n");
936       goto Exit;
937     }
938 
939     if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
940       AsciiPrint("Files differ.\n");
941       goto Exit;
942     };
943   }
944 
945   // Any left over?
946   if (Offset < Size1) {
947     Chunk = Size1 - Offset;
948 
949     Status = EfiRead(File1, Buffer1, &Chunk);
950     if (EFI_ERROR(Status)) {
951       AsciiPrint("File 1 read error\n");
952       goto Exit;
953     }
954 
955     Status = EfiRead(File2, Buffer2, &Chunk);
956     if (EFI_ERROR(Status)) {
957       AsciiPrint("File 2 read error\n");
958       goto Exit;
959     }
960   }
961 
962   if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
963     AsciiPrint("Files differ.\n");
964   } else {
965     AsciiPrint("Files are identical.\n");
966   }
967 
968 Exit:
969   if (File1 != NULL) {
970     Status = EfiClose(File1);
971     if (EFI_ERROR(Status)) {
972       AsciiPrint("File 1 close error %r\n", Status);
973     }
974   }
975 
976   if (File2 != NULL) {
977     Status = EfiClose(File2);
978     if (EFI_ERROR(Status)) {
979       AsciiPrint("File 2 close error %r\n", Status);
980     }
981   }
982 
983   if (Buffer1 != NULL) {
984     FreePool(Buffer1);
985   }
986 
987   if (Buffer2 != NULL) {
988     FreePool(Buffer2);
989   }
990 
991   return Status;
992 }
993 
994 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] =
995 {
996   {
997     "connect",
998     "[d]; Connect all EFI devices. d means disconnect",
999     NULL,
1000     EblConnectCmd
1001   },
1002   {
1003     "device",
1004     "; Show information about boot devices",
1005     NULL,
1006     EblDeviceCmd
1007   },
1008   {
1009     "go",
1010     " dev:path loadaddress entrypoint args; load to given address and jump in",
1011     NULL,
1012     EblGoCmd
1013   },
1014   {
1015     "loadfv",
1016     " devname; Load PI FV from device",
1017     NULL,
1018     EblLoadFvCmd
1019   },
1020   {
1021     "start",
1022     " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
1023     NULL,
1024     EblStartCmd
1025   },
1026   {
1027     "memmap",
1028     "; dump EFI memory map",
1029     NULL,
1030     EblMemMapCmd
1031   },
1032   {
1033     "cp",
1034     " file1 file2; copy file only.",
1035     NULL,
1036     EblFileCopyCmd
1037   },
1038   {
1039     "diff",
1040     " file1 file2; compare files",
1041     NULL,
1042     EblFileDiffCmd
1043   }
1044 };
1045 
1046 
1047 /**
1048   Initialize the commands in this in this file
1049 **/
1050 
1051 VOID
EblInitializeDeviceCmd(VOID)1052 EblInitializeDeviceCmd (
1053   VOID
1054   )
1055 {
1056   EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
1057   EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
1058 }
1059 
1060