Trailing spaces create issue/warning when generating/applying patches. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15833 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1051 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1051 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   EBL commands for EFI and PI Devices
 | |
| 
 | |
|   Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
 | |
|   Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Ebl.h"
 | |
| 
 | |
| 
 | |
| EFI_DXE_SERVICES  *gDS = NULL;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print information about the File System device.
 | |
| 
 | |
|   @param  File  Open File for the device
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EblPrintFsInfo (
 | |
|   IN  EFI_OPEN_FILE   *File
 | |
|   )
 | |
| {
 | |
|   CHAR16 *Str;
 | |
| 
 | |
|   if (File == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("  %a: ", File->DeviceName);
 | |
|   if (File->FsInfo != NULL) {
 | |
|     for (Str = File->FsInfo->VolumeLabel; *Str != '\0'; Str++) {
 | |
|       if (*Str == ' ') {
 | |
|         // UI makes you enter _ for space, so make the printout match that
 | |
|         *Str = '_';
 | |
|       }
 | |
|       AsciiPrint ("%c", *Str);
 | |
|     }
 | |
|     AsciiPrint (":");
 | |
|     if (File->FsInfo->ReadOnly) {
 | |
|       AsciiPrint ("ReadOnly");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("\n");
 | |
|   EfiClose (File);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print information about the FV devices.
 | |
| 
 | |
|   @param  File  Open File for the device
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EblPrintFvbInfo (
 | |
|   IN  EFI_OPEN_FILE   *File
 | |
|   )
 | |
| {
 | |
|   if (File == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("  %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize);
 | |
|   EfiClose (File);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print information about the Blk IO devices.
 | |
|   If the device supports PXE dump out extra information
 | |
| 
 | |
|   @param  File  Open File for the device
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EblPrintBlkIoInfo (
 | |
|   IN  EFI_OPEN_FILE   *File
 | |
|   )
 | |
| {
 | |
|   UINT64                    DeviceSize;
 | |
|   UINTN                     Index;
 | |
|   UINTN                     Max;
 | |
|   EFI_OPEN_FILE             *FsFile;
 | |
| 
 | |
|   if (File == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("  %a: ", File->DeviceName);
 | |
| 
 | |
|   // print out name of file system, if any, on this block device
 | |
|   Max = EfiGetDeviceCounts (EfiOpenFileSystem);
 | |
|   if (Max != 0) {
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       FsFile = EfiDeviceOpenByType (EfiOpenFileSystem, Index);
 | |
|       if (FsFile != NULL) {
 | |
|         if (FsFile->EfiHandle == File->EfiHandle) {
 | |
|           AsciiPrint ("fs%d: ", Index);
 | |
|           EfiClose (FsFile);
 | |
|           break;
 | |
|         }
 | |
|         EfiClose (FsFile);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Print out useful Block IO media properties
 | |
|   if (File->FsBlockIoMedia->RemovableMedia) {
 | |
|     AsciiPrint ("Removable ");
 | |
|   }
 | |
|   if (!File->FsBlockIoMedia->MediaPresent) {
 | |
|     AsciiPrint ("No Media\n");
 | |
|   } else {
 | |
|     if (File->FsBlockIoMedia->LogicalPartition) {
 | |
|       AsciiPrint ("Partition ");
 | |
|     }
 | |
|     DeviceSize = MultU64x32 (File->FsBlockIoMedia->LastBlock + 1, File->FsBlockIoMedia->BlockSize);
 | |
|     AsciiPrint ("Size = 0x%lX\n", DeviceSize);
 | |
|   }
 | |
|   EfiClose (File);
 | |
| }
 | |
| 
 | |
|  /**
 | |
|   Print information about the Load File devices.
 | |
|   If the device supports PXE dump out extra information
 | |
| 
 | |
|   @param  File  Open File for the device
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EblPrintLoadFileInfo (
 | |
|   IN  EFI_OPEN_FILE   *File
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL    *DevicePathNode;
 | |
|   MAC_ADDR_DEVICE_PATH        *MacAddr;
 | |
|   UINTN                       HwAddressSize;
 | |
|   UINTN                       Index;
 | |
| 
 | |
|   if (File == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("  %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle));
 | |
| 
 | |
|   if (File->DevicePath != NULL) {
 | |
|     // Try to print out the MAC address
 | |
|     for (DevicePathNode = File->DevicePath;
 | |
|         !IsDevicePathEnd (DevicePathNode);
 | |
|         DevicePathNode = NextDevicePathNode (DevicePathNode)) {
 | |
| 
 | |
|       if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) {
 | |
|         MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode;
 | |
| 
 | |
|         HwAddressSize = sizeof (EFI_MAC_ADDRESS);
 | |
|         if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) {
 | |
|           HwAddressSize = 6;
 | |
|         }
 | |
| 
 | |
|         AsciiPrint ("MAC ");
 | |
|         for (Index = 0; Index < HwAddressSize; Index++) {
 | |
|           AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   AsciiPrint ("\n");
 | |
|   EfiClose (File);
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Dump information about devices in the system.
 | |
| 
 | |
|   fv:       PI Firmware Volume
 | |
|   fs:       EFI Simple File System
 | |
|   blk:      EFI Block IO
 | |
|   LoadFile: EFI Load File Protocol (commonly PXE network boot)
 | |
| 
 | |
|   Argv[0] - "device"
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblDeviceCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   UINTN         CurrentRow;
 | |
|   UINTN         Max;
 | |
| 
 | |
|   CurrentRow = 0;
 | |
| 
 | |
|   // Need to call here to make sure Device Counts are valid
 | |
|   EblUpdateDeviceLists ();
 | |
| 
 | |
|   // Now we can print out the info...
 | |
|   Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume);
 | |
|   if (Max != 0) {
 | |
|     AsciiPrint ("Firmware Volume Devices:\n");
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index));
 | |
|       if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Max = EfiGetDeviceCounts (EfiOpenFileSystem);
 | |
|   if (Max != 0) {
 | |
|     AsciiPrint ("File System Devices:\n");
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index));
 | |
|       if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Max = EfiGetDeviceCounts (EfiOpenBlockIo);
 | |
|   if (Max != 0) {
 | |
|     AsciiPrint ("Block IO Devices:\n");
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index));
 | |
|       if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Max = EfiGetDeviceCounts (EfiOpenLoadFile);
 | |
|   if (Max != 0) {
 | |
|     AsciiPrint ("LoadFile Devices: (usually network)\n");
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index));
 | |
|       if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start an EFI image (PE32+ with EFI defined entry point).
 | |
| 
 | |
|   Argv[0] - "start"
 | |
|   Argv[1] - device name and path
 | |
|   Argv[2] - "" string to pass into image being started
 | |
| 
 | |
|   start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the
 | |
|                                       ; ascii string arg to pass to the image
 | |
|   start fv0:\FV                       ; load an FV from an FV (not common)
 | |
|   start LoadFile0:                    ; load an FV via a PXE boot
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblStartCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_OPEN_FILE               *File;
 | |
|   EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
 | |
|   EFI_HANDLE                  ImageHandle;
 | |
|   UINTN                       ExitDataSize;
 | |
|   CHAR16                      *ExitData;
 | |
|   VOID                        *Buffer;
 | |
|   UINTN                       BufferSize;
 | |
|   EFI_LOADED_IMAGE_PROTOCOL   *ImageInfo;
 | |
| 
 | |
|   ImageHandle = NULL;
 | |
| 
 | |
|   if (Argc < 2) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|   if (File == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   DevicePath = File->DevicePath;
 | |
|   if (DevicePath != NULL) {
 | |
|     // check for device path form: blk, fv, fs, and loadfile
 | |
|     Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle);
 | |
|   } else {
 | |
|     // Check for buffer form: A0x12345678:0x1234 syntax.
 | |
|     // Means load using buffer starting at 0x12345678 of size 0x1234.
 | |
| 
 | |
|     Status = EfiReadAllocatePool (File, &Buffer, &BufferSize);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       EfiClose (File);
 | |
|       return Status;
 | |
|     }
 | |
|     Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle);
 | |
| 
 | |
|     FreePool (Buffer);
 | |
|   }
 | |
| 
 | |
|   EfiClose (File);
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     if (Argc >= 3) {
 | |
|       // Argv[2] is a "" string that we pass directly to the EFI application without the ""
 | |
|       // We don't pass Argv[0] to the EFI Application (it's name) just the args
 | |
|       Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|       ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]);
 | |
|       ImageInfo->LoadOptions     = AllocatePool (ImageInfo->LoadOptionsSize);
 | |
|       AsciiStrCpy (ImageInfo->LoadOptions, Argv[2]);
 | |
|     }
 | |
| 
 | |
|     // Transfer control to the EFI image we loaded with LoadImage()
 | |
|     Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Load a Firmware Volume (FV) into memory from a device. This causes drivers in
 | |
|   the FV to be dispatched if the dependencies of the drivers are met.
 | |
| 
 | |
|   Argv[0] - "loadfv"
 | |
|   Argv[1] - device name and path
 | |
| 
 | |
|   loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk
 | |
|   loadfv fv0:\FV         ; load an FV from an FV (not common)
 | |
|   loadfv LoadFile0:      ; load an FV via a PXE boot
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblLoadFvCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_OPEN_FILE                     *File;
 | |
|   VOID                              *FvStart;
 | |
|   UINTN                             FvSize;
 | |
|   EFI_HANDLE                        FvHandle;
 | |
| 
 | |
| 
 | |
|   if (Argc < 2) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|   if (File == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (File->Type == EfiOpenMemoryBuffer) {
 | |
|     // If it is a address just use it.
 | |
|     Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle);
 | |
|   } else {
 | |
|     // If it is a file read it into memory and use it
 | |
|     Status = EfiReadAllocatePool (File, &FvStart, &FvSize);
 | |
|     EfiClose (File);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FreePool (FvStart);
 | |
|     }
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Perform an EFI connect to connect devices that follow the EFI driver model.
 | |
|   If it is a PI system also call the dispatcher in case a new FV was made
 | |
|   available by one of the connect EFI drivers (this is not a common case).
 | |
| 
 | |
|   Argv[0] - "connect"
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblConnectCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   UINTN         HandleCount;
 | |
|   EFI_HANDLE    *HandleBuffer;
 | |
|   UINTN         Index;
 | |
|   BOOLEAN       Dispatch;
 | |
|   EFI_OPEN_FILE *File;
 | |
| 
 | |
| 
 | |
|   if (Argc > 1) {
 | |
|     if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) {
 | |
|       Status = gBS->LocateHandleBuffer (
 | |
|                       AllHandles,
 | |
|                       NULL,
 | |
|                       NULL,
 | |
|                       &HandleCount,
 | |
|                       &HandleBuffer
 | |
|                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       for (Index = 0; Index < HandleCount; Index++) {
 | |
|         gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Given we disconnect our console we should go and do a connect now
 | |
|       //
 | |
|     } else {
 | |
|       File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|       if (File != NULL) {
 | |
|         AsciiPrint ("Connecting %a\n", Argv[1]);
 | |
|         gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE);
 | |
|         EfiClose (File);
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Dispatch = FALSE;
 | |
|   do {
 | |
|     Status = gBS->LocateHandleBuffer (
 | |
|                     AllHandles,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &HandleCount,
 | |
|                     &HandleBuffer
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < HandleCount; Index++) {
 | |
|       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
 | |
|     }
 | |
| 
 | |
|     FreePool (HandleBuffer);
 | |
| 
 | |
|     //
 | |
|     // Check to see if it's possible to dispatch an more DXE drivers.
 | |
|     // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
 | |
|     // If anything is Dispatched Status == EFI_SUCCESS and we will try
 | |
|     // the connect again.
 | |
|     //
 | |
|     if (gDS == NULL) {
 | |
|       Status = EFI_NOT_FOUND;
 | |
|     } else {
 | |
|       Status = gDS->Dispatch ();
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         Dispatch = TRUE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   } while (!EFI_ERROR (Status));
 | |
| 
 | |
|   if (Dispatch) {
 | |
|     AsciiPrint ("Connected and dispatched\n");
 | |
|   } else {
 | |
|     AsciiPrint ("Connect\n");
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| CHAR8 *gMemMapType[] = {
 | |
|   "reserved  ",
 | |
|   "LoaderCode",
 | |
|   "LoaderData",
 | |
|   "BS_code   ",
 | |
|   "BS_data   ",
 | |
|   "RT_code   ",
 | |
|   "RT_data   ",
 | |
|   "available ",
 | |
|   "Unusable  ",
 | |
|   "ACPI_recl ",
 | |
|   "ACPI_NVS  ",
 | |
|   "MemMapIO  ",
 | |
|   "MemPortIO ",
 | |
|   "PAL_code  "
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Dump out the EFI memory map
 | |
| 
 | |
|   Argv[0] - "memmap"
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblMemMapCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_MEMORY_DESCRIPTOR *MemMap;
 | |
|   EFI_MEMORY_DESCRIPTOR *OrigMemMap;
 | |
|   UINTN                 MemMapSize;
 | |
|   UINTN                 MapKey;
 | |
|   UINTN                 DescriptorSize;
 | |
|   UINT32                DescriptorVersion;
 | |
|   UINT64                PageCount[EfiMaxMemoryType];
 | |
|   UINTN                 Index;
 | |
|   UINT64                EntrySize;
 | |
|   UINTN                 CurrentRow;
 | |
|   UINT64                TotalMemory;
 | |
| 
 | |
|   ZeroMem (PageCount, sizeof (PageCount));
 | |
| 
 | |
|   AsciiPrint ("EFI Memory Map\n");
 | |
| 
 | |
|   // First call is to figure out how big the buffer needs to be
 | |
|   MemMapSize = 0;
 | |
|   MemMap     = NULL;
 | |
|   Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     // In case the AllocatPool changes the memory map we added in some extra descriptors
 | |
|     MemMapSize += (DescriptorSize * 0x100);
 | |
|     OrigMemMap = MemMap = AllocatePool (MemMapSize);
 | |
|     if (OrigMemMap != NULL) {
 | |
|       // 2nd time we get the data
 | |
|       Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) {
 | |
|           EntrySize = LShiftU64 (MemMap->NumberOfPages, 12);
 | |
|           AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute);
 | |
|           if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages;
 | |
|           MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) {
 | |
|         if (PageCount[Index] != 0) {
 | |
|           AsciiPrint ("\n  %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12));
 | |
|           if (Index == EfiLoaderCode ||
 | |
|               Index == EfiLoaderData ||
 | |
|               Index == EfiBootServicesCode ||
 | |
|               Index == EfiBootServicesData ||
 | |
|               Index == EfiRuntimeServicesCode ||
 | |
|               Index == EfiRuntimeServicesData ||
 | |
|               Index == EfiConventionalMemory ||
 | |
|               Index == EfiACPIReclaimMemory ||
 | |
|               Index == EfiACPIMemoryNVS ||
 | |
|               Index == EfiPalCode
 | |
|           ) {
 | |
|             // Count total memory
 | |
|             TotalMemory += PageCount[Index];
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12));
 | |
| 
 | |
|       FreePool (OrigMemMap);
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Load a file into memory and optionally jump to it. A load address can be
 | |
|   specified or automatically allocated. A quoted command line can optionally
 | |
|   be passed into the image.
 | |
| 
 | |
|   Argv[0] - "go"
 | |
|   Argv[1] - Device Name:path for the file to load
 | |
|   Argv[2] - Address to load to or '*' if the load address will be allocated
 | |
|   Argv[3] - Optional Entry point to the image. Image will be called if present
 | |
|   Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs
 | |
|             to include the command name
 | |
| 
 | |
|   go fv1:\EblCmdX  0x10000  0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX
 | |
|     from FV1 to location 0x10000 and call the entry point at 0x10010 passing
 | |
|     in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
 | |
| 
 | |
|   go fv0:\EblCmdX  *  0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0
 | |
|     to location allocated by this command and call the entry point at offset 0x10
 | |
|     passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
 | |
| 
 | |
|   go fv1:\EblCmdX  0x10000; Load EblCmdX to address 0x10000 and return
 | |
| 
 | |
|   @param  Argc   Number of command arguments in Argv
 | |
|   @param  Argv   Array of strings that represent the parsed command line.
 | |
|                  Argv[0] is the command name
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EblGoCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_OPEN_FILE                 *File;
 | |
|   VOID                          *Address;
 | |
|   UINTN                         Size;
 | |
|   EBL_COMMMAND                  EntryPoint;
 | |
|   UINTN                         EntryPointArgc;
 | |
|   CHAR8                         *EntryPointArgv[MAX_ARGS];
 | |
| 
 | |
| 
 | |
|   if (Argc <= 2) {
 | |
|     // device name and laod address are required
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|   if (File == NULL) {
 | |
|     AsciiPrint ("  %a is not a valid path\n", Argv[1]);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   EntryPoint  = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL);
 | |
|   if (Argv[2][0] == '*') {
 | |
|     // * Means allocate the buffer
 | |
|     Status = EfiReadAllocatePool (File, &Address, &Size);
 | |
| 
 | |
|     // EntryPoint is relative to the start of the image
 | |
|     EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address);
 | |
| 
 | |
|   } else {
 | |
|     Address = (VOID *)AsciiStrHexToUintn (Argv[2]);
 | |
|     Size = File->Size;
 | |
| 
 | |
|     // File->Size for LoadFile is lazy so we need to use the tell to figure it out
 | |
|     EfiTell (File, NULL);
 | |
|     Status = EfiRead (File, Address, &Size);
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address);
 | |
| 
 | |
|     if (Argc > 3) {
 | |
|       if (Argc > 4) {
 | |
|         ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv);
 | |
|       } else {
 | |
|         EntryPointArgc = 1;
 | |
|         EntryPointArgv[0] = File->FileName;
 | |
|       }
 | |
| 
 | |
|       Status = EntryPoint (EntryPointArgc, EntryPointArgv);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   EfiClose (File);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| #define FILE_COPY_CHUNK 0x20000
 | |
| 
 | |
| EFI_STATUS
 | |
| EblFileCopyCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_OPEN_FILE *Source      = NULL;
 | |
|   EFI_OPEN_FILE *Destination = NULL;
 | |
|   EFI_STATUS    Status       = EFI_SUCCESS;
 | |
|   VOID          *Buffer      = NULL;
 | |
|   UINTN         Size;
 | |
|   UINTN         Offset;
 | |
|   UINTN         Chunk        = FILE_COPY_CHUNK;
 | |
|   UINTN         FileNameLen;
 | |
|   CHAR8*        DestFileName;
 | |
|   CHAR8*        SrcFileName;
 | |
|   CHAR8*        SrcPtr;
 | |
| 
 | |
|   if (Argc < 3) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   DestFileName = Argv[2];
 | |
|   FileNameLen = AsciiStrLen (DestFileName);
 | |
| 
 | |
|   // Check if the destination file name looks like a directory
 | |
|   if ((DestFileName[FileNameLen-1] == '\\') || (DestFileName[FileNameLen-1] == ':')) {
 | |
|     // Set the pointer after the source drive (eg: after fs1:)
 | |
|     SrcPtr = AsciiStrStr (Argv[1], ":");
 | |
|     if (SrcPtr == NULL) {
 | |
|       SrcPtr = Argv[1];
 | |
|     } else {
 | |
|       SrcPtr++;
 | |
|       if (*SrcPtr == '\\') {
 | |
|         SrcPtr++;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (*SrcPtr == '\0') {
 | |
|       AsciiPrint("Source file incorrect.\n");
 | |
|     }
 | |
| 
 | |
|     // Skip the Source Directories
 | |
|     while (1) {
 | |
|       SrcFileName = SrcPtr;
 | |
|       SrcPtr = AsciiStrStr (SrcPtr,"\\");
 | |
|       if (SrcPtr != NULL) {
 | |
|         SrcPtr++;
 | |
|       } else {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (*SrcFileName == '\0') {
 | |
|       AsciiPrint("Source file incorrect (Error 2).\n");
 | |
|     }
 | |
| 
 | |
|     // Construct the destination filepath
 | |
|     DestFileName = (CHAR8*)AllocatePool (FileNameLen + AsciiStrLen (SrcFileName) + 1);
 | |
|     AsciiStrCpy (DestFileName, Argv[2]);
 | |
|     AsciiStrCat (DestFileName, SrcFileName);
 | |
|   }
 | |
| 
 | |
|   Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|   if (Source == NULL) {
 | |
|     AsciiPrint("Source file open error.\n");
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Destination = EfiOpen(DestFileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
 | |
|   if (Destination == NULL) {
 | |
|     AsciiPrint("Destination file open error.\n");
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Buffer = AllocatePool(FILE_COPY_CHUNK);
 | |
|   if (Buffer == NULL) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Size = EfiTell(Source, NULL);
 | |
| 
 | |
|   for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {
 | |
|     Chunk = FILE_COPY_CHUNK;
 | |
| 
 | |
|     Status = EfiRead(Source, Buffer, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Read file error %r\n", Status);
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = EfiWrite(Destination, Buffer, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Write file error %r\n", Status);
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Any left over?
 | |
|   if (Offset < Size) {
 | |
|     Chunk = Size - Offset;
 | |
| 
 | |
|     Status = EfiRead(Source, Buffer, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Read file error %r\n", Status);
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = EfiWrite(Destination, Buffer, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Write file error %r\n", Status);
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| Exit:
 | |
|   if (Source != NULL) {
 | |
|     Status = EfiClose(Source);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Source close error %r\n", Status);
 | |
|     }
 | |
|   }
 | |
|   if (Destination != NULL) {
 | |
|     Status = EfiClose(Destination);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("Destination close error %r\n", Status);
 | |
|     }
 | |
| 
 | |
|     // Case when we have concated the filename to the destination directory
 | |
|     if (DestFileName != Argv[2]) {
 | |
|       FreePool (DestFileName);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Buffer != NULL) {
 | |
|     FreePool(Buffer);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EblFileDiffCmd (
 | |
|   IN UINTN  Argc,
 | |
|   IN CHAR8  **Argv
 | |
|   )
 | |
| {
 | |
|   EFI_OPEN_FILE *File1   = NULL;
 | |
|   EFI_OPEN_FILE *File2   = NULL;
 | |
|   EFI_STATUS    Status   = EFI_SUCCESS;
 | |
|   VOID          *Buffer1 = NULL;
 | |
|   VOID          *Buffer2 = NULL;
 | |
|   UINTN         Size1;
 | |
|   UINTN         Size2;
 | |
|   UINTN         Offset;
 | |
|   UINTN         Chunk   = FILE_COPY_CHUNK;
 | |
| 
 | |
|   if (Argc != 3) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
 | |
|   if (File1 == NULL) {
 | |
|     AsciiPrint("File 1 open error.\n");
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0);
 | |
|   if (File2 == NULL) {
 | |
|     AsciiPrint("File 2 open error.\n");
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Size1 = EfiTell(File1, NULL);
 | |
|   Size2 = EfiTell(File2, NULL);
 | |
| 
 | |
|   if (Size1 != Size2) {
 | |
|     AsciiPrint("Files differ.\n");
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Buffer1 = AllocatePool(FILE_COPY_CHUNK);
 | |
|   if (Buffer1 == NULL) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Buffer2 = AllocatePool(FILE_COPY_CHUNK);
 | |
|   if (Buffer2 == NULL) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) {
 | |
|     Chunk = FILE_COPY_CHUNK;
 | |
| 
 | |
|     Status = EfiRead(File1, Buffer1, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 1 read error\n");
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = EfiRead(File2, Buffer2, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 2 read error\n");
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
 | |
|       AsciiPrint("Files differ.\n");
 | |
|       goto Exit;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   // Any left over?
 | |
|   if (Offset < Size1) {
 | |
|     Chunk = Size1 - Offset;
 | |
| 
 | |
|     Status = EfiRead(File1, Buffer1, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 1 read error\n");
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = EfiRead(File2, Buffer2, &Chunk);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 2 read error\n");
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
 | |
|     AsciiPrint("Files differ.\n");
 | |
|   } else {
 | |
|     AsciiPrint("Files are identical.\n");
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   if (File1 != NULL) {
 | |
|     Status = EfiClose(File1);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 1 close error %r\n", Status);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (File2 != NULL) {
 | |
|     Status = EfiClose(File2);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       AsciiPrint("File 2 close error %r\n", Status);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Buffer1 != NULL) {
 | |
|     FreePool(Buffer1);
 | |
|   }
 | |
| 
 | |
|   if (Buffer2 != NULL) {
 | |
|     FreePool(Buffer2);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] =
 | |
| {
 | |
|   {
 | |
|     "connect",
 | |
|     "[d]; Connect all EFI devices. d means disconnect",
 | |
|     NULL,
 | |
|     EblConnectCmd
 | |
|   },
 | |
|   {
 | |
|     "device",
 | |
|     "; Show information about boot devices",
 | |
|     NULL,
 | |
|     EblDeviceCmd
 | |
|   },
 | |
|   {
 | |
|     "go",
 | |
|     " dev:path loadaddress entrypoint args; load to given address and jump in",
 | |
|     NULL,
 | |
|     EblGoCmd
 | |
|   },
 | |
|   {
 | |
|     "loadfv",
 | |
|     " devname; Load PI FV from device",
 | |
|     NULL,
 | |
|     EblLoadFvCmd
 | |
|   },
 | |
|   {
 | |
|     "start",
 | |
|     " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
 | |
|     NULL,
 | |
|     EblStartCmd
 | |
|   },
 | |
|   {
 | |
|     "memmap",
 | |
|     "; dump EFI memory map",
 | |
|     NULL,
 | |
|     EblMemMapCmd
 | |
|   },
 | |
|   {
 | |
|     "cp",
 | |
|     " file1 file2; copy file only.",
 | |
|     NULL,
 | |
|     EblFileCopyCmd
 | |
|   },
 | |
|   {
 | |
|     "diff",
 | |
|     " file1 file2; compare files",
 | |
|     NULL,
 | |
|     EblFileDiffCmd
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize the commands in this in this file
 | |
| **/
 | |
| 
 | |
| VOID
 | |
| EblInitializeDeviceCmd (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
 | |
|   EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
 | |
| }
 | |
| 
 |