Home | History | Annotate | Download | only in Ebl
      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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   1053 EblInitializeDeviceCmd (
   1054   VOID
   1055   )
   1056 {
   1057   EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
   1058   EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
   1059 }
   1060 
   1061