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