summaryrefslogtreecommitdiff
path: root/EmbeddedPkg/Ebl/EfiDevice.c
diff options
context:
space:
mode:
Diffstat (limited to 'EmbeddedPkg/Ebl/EfiDevice.c')
-rw-r--r--EmbeddedPkg/Ebl/EfiDevice.c969
1 files changed, 969 insertions, 0 deletions
diff --git a/EmbeddedPkg/Ebl/EfiDevice.c b/EmbeddedPkg/Ebl/EfiDevice.c
new file mode 100644
index 0000000000..7633d66934
--- /dev/null
+++ b/EmbeddedPkg/Ebl/EfiDevice.c
@@ -0,0 +1,969 @@
+/** @file
+ EBL commands for EFI and PI Devices
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. 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
+ )
+{
+ if (File == NULL) {
+ return;
+ }
+
+ AsciiPrint (" %a: ", File->DeviceName);
+ if (File->FsInfo != NULL) {
+ AsciiPrint ("%s: ", File->FsInfo->VolumeLabel);
+ 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;
+
+
+ if (File == NULL) {
+ return;
+ }
+
+ AsciiPrint (" %a: ", File->DeviceName);
+ if (File->FsBlockIoMedia.RemovableMedia) {
+ AsciiPrint ("Removable ");
+ }
+ if (!File->FsBlockIoMedia.MediaPresent) {
+ AsciiPrint ("No Media ");
+ }
+ 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 comamnd 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 ();
+
+ 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 comamnd 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 dependancies 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 comamnd 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);
+ 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
+ availible 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 comamnd 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 comamnd 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 addres 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 comamnd 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 comamnd 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 relatvie 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;
+
+ if (Argc < 3) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
+ if (Source == NULL) {
+ AsciiPrint("Source file open error.\n");
+ return EFI_NOT_FOUND;
+ }
+
+ Destination = EfiOpen(Argv[2], 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\n");
+ goto Exit;
+ }
+
+ Status = EfiWrite(Destination, Buffer, &Chunk);
+ if (EFI_ERROR(Status)) {
+ AsciiPrint("Write file error\n");
+ goto Exit;
+ }
+ }
+
+ // Any left over?
+ if (Offset < Size) {
+ Chunk = Size - Offset;
+
+ Status = EfiRead(Source, Buffer, &Chunk);
+ if (EFI_ERROR(Status)) {
+ AsciiPrint("Read file error\n");
+ goto Exit;
+ }
+
+ Status = EfiWrite(Destination, Buffer, &Chunk);
+ if (EFI_ERROR(Status)) {
+ AsciiPrint("Write file error\n");
+ 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);
+ }
+ }
+
+ 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",
+ 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));
+}
+