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