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       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
    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;
    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
    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
   1052 EblInitializeDeviceCmd (
   1053   VOID
   1054   )
   1055 {
   1056   EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
   1057   EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
   1058 }
   1059 
   1060