--- /dev/null
+/** @file\r
+ Basic commands and command processing infrastructure for EBL\r
+\r
+ Copyright (c) 2007, Intel Corporation<BR>\r
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+\r
+ All rights reserved. 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
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/BlockIo.h>\r
+\r
+UINTN mCmdTableMaxIndex = EBL_MAX_COMMAND_COUNT;\r
+UINTN mCmdTableNextFreeIndex = 0;\r
+EBL_COMMAND_TABLE *mCmdTable[EBL_MAX_COMMAND_COUNT];\r
+\r
+/**\r
+ Converts a lowercase Ascii character to upper one\r
+\r
+ If Chr is lowercase Ascii character, then converts it to upper one.\r
+\r
+ If Value >= 0xA0, then ASSERT().\r
+ If (Value & 0x0F) >= 0x0A, then ASSERT().\r
+\r
+ @param chr one Ascii character\r
+\r
+ @return The uppercase value of Ascii character \r
+\r
+**/\r
+STATIC\r
+CHAR8\r
+AsciiToUpper (\r
+ IN CHAR8 Chr\r
+ )\r
+{\r
+ return (UINT8) ((Chr >= 'a' && Chr <= 'z') ? Chr - ('a' - 'A') : Chr);\r
+}\r
+\r
+\r
+/**\r
+ Case insensitve comparison of two Null-terminated Unicode strings with maximum\r
+ lengths, and returns the difference between the first mismatched Unicode\r
+ characters.\r
+ This function compares the Null-terminated Unicode string FirstString to the\r
+ Null-terminated Unicode string SecondString. At most, Length Unicode\r
+ characters will be compared. If Length is 0, then 0 is returned. If\r
+ FirstString is identical to SecondString, then 0 is returned. Otherwise, the\r
+ value returned is the first mismatched Unicode character in SecondString\r
+ subtracted from the first mismatched Unicode character in FirstString.\r
+ \r
+ @param FirstString Pointer to a Null-terminated ASCII string. \r
+ @param SecondString Pointer to a Null-terminated ASCII string.\r
+ @param Length Max length to compare.\r
+ \r
+ @retval 0 FirstString is identical to SecondString using case insensitive\r
+ comparisons.\r
+ @retval !=0 FirstString is not identical to SecondString using case\r
+ insensitive comparisons.\r
+\r
+**/\r
+INTN\r
+EFIAPI\r
+AsciiStrniCmp (\r
+ IN CONST CHAR8 *FirstString,\r
+ IN CONST CHAR8 *SecondString,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ if (Length == 0) {\r
+ return 0;\r
+ }\r
+\r
+ while ((AsciiToUpper (*FirstString) != '\0') &&\r
+ (AsciiToUpper (*FirstString) == AsciiToUpper (*SecondString)) &&\r
+ (Length > 1)) {\r
+ FirstString++;\r
+ SecondString++;\r
+ Length--;\r
+ }\r
+ \r
+ return AsciiToUpper (*FirstString) - AsciiToUpper (*SecondString);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Add a command to the mCmdTable. If there is no free space in the command \r
+ table ASSERT. The mCmdTable is maintained in alphabetical order and the \r
+ new entry is inserted into its sorted possition.\r
+\r
+ @param Entry Commnad Entry to add to the CmdTable\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EblAddCommand (\r
+ IN const EBL_COMMAND_TABLE *Entry\r
+ )\r
+{\r
+ UINTN Count;\r
+\r
+ if (mCmdTableNextFreeIndex == EBL_MAX_COMMAND_COUNT) {\r
+ //\r
+ // Ran out of space to store commands. Increase EBL_MAX_COMMAND_COUNT\r
+ //\r
+ ASSERT (FALSE);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Add command and Insertion sort array in the process\r
+ //\r
+ mCmdTable[mCmdTableNextFreeIndex] = (EBL_COMMAND_TABLE *)Entry;\r
+ if (mCmdTableNextFreeIndex != 0) {\r
+ for (Count = mCmdTableNextFreeIndex; Count > 0; Count--) {\r
+ if (AsciiStriCmp (mCmdTable[Count - 1]->Name, Entry->Name) <= 0) {\r
+ break;\r
+ }\r
+ \r
+ mCmdTable[Count] = mCmdTable[Count - 1];\r
+ }\r
+ mCmdTable[Count] = (EBL_COMMAND_TABLE *)Entry;\r
+ }\r
+\r
+ mCmdTableNextFreeIndex++;\r
+}\r
+\r
+\r
+/**\r
+ Add an set of commands to the command table. Most commonly used on static \r
+ array of commands.\r
+\r
+ @param EntryArray Pointer to array of command entries\r
+ @param ArrayCount Number of commnad entries to add\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EblAddCommands (\r
+ IN const EBL_COMMAND_TABLE *EntryArray,\r
+ IN UINTN ArrayCount\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < ArrayCount; Index++) {\r
+ EblAddCommand (&EntryArray[Index]);\r
+ }\r
+}\r
+\r
+\r
+EBL_ADD_COMMAND_PROTOCOL gEblAddCommand = {\r
+ EblAddCommand,\r
+ EblAddCommands,\r
+ EblGetCharKey,\r
+ EblAnyKeyToContinueQtoQuit\r
+};\r
+\r
+\r
+\r
+/**\r
+ Return the best matching command for the passed in command name. The match \r
+ does not have to be exact, it just needs to be unqiue. This enables commands\r
+ to be shortend to the smallest set of starting characters that is unique.\r
+\r
+ @param CommandName Name of command to search for\r
+\r
+ @return NULL CommandName did not match or was not unique\r
+ Other Pointer to EBL_COMMAND_TABLE entry for CommandName\r
+\r
+**/\r
+EBL_COMMAND_TABLE *\r
+EblGetCommand (\r
+ IN CHAR8 *CommandName\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN BestMatchCount;\r
+ UINTN Length;\r
+ EBL_COMMAND_TABLE *Match;\r
+\r
+ Length = AsciiStrLen (CommandName);\r
+ for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) {\r
+ if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) {\r
+ // match a command exactly\r
+ return mCmdTable[Index];\r
+ }\r
+\r
+ if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) {\r
+ // partial match, so keep looking to make sure there is only one partial match\r
+ BestMatchCount++;\r
+ Match = mCmdTable[Index];\r
+ }\r
+ }\r
+\r
+ if (BestMatchCount == 1) {\r
+ return Match;\r
+ }\r
+\r
+ //\r
+ // We had no matches or too many matches\r
+ //\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+ List out help information on all the commands or print extended information \r
+ about a specific passed in command.\r
+\r
+ Argv[0] - "help"\r
+ Argv[1] - Command to display help about\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 comamnd name\r
+\r
+ @return EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EblHelpCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ UINTN Index;\r
+ CHAR8 *Ptr;\r
+ UINTN CurrentRow;\r
+\r
+ if (Argc == 1) {\r
+ // Print all the commands\r
+ AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n");\r
+ for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) {\r
+ EblSetTextColor (EFI_YELLOW);\r
+ AsciiPrint (" %a", mCmdTable[Index]->Name);\r
+ EblSetTextColor (0);\r
+ AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary);\r
+ }\r
+ } else if (Argv[1] != NULL) {\r
+ // Print specific help \r
+ for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) {\r
+ if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) {\r
+ Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help;\r
+ AsciiPrint ("%a%a\n", Argv[1], Ptr);\r
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Exit the EBL. If the commnad processor sees EFI_ABORTED return status it will\r
+ exit the EBL.\r
+\r
+ Argv[0] - "exit"\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 comamnd name\r
+\r
+ @return EFI_ABORTED\r
+\r
+**/\r
+EFI_STATUS\r
+EblExitCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ EFI_STATUS Status;
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINTN DescriptorVersion;
+ UINTN Pages;
+\r
+ if (Argc > 1) { \r
+ if (AsciiStriCmp (Argv[1], "efi") != 0) {\r
+ return EFI_ABORTED;\r
+ }\r
+ } else if (Argc == 1) {\r
+ return EFI_ABORTED;\r
+ }\r
+ \r
+ MemoryMap = NULL;
+ MemoryMapSize = 0;
+ do {
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+
+ Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
+ MemoryMap = AllocatePages (Pages);
+
+ //
+ // Get System MemoryMap
+ //
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ // Don't do anything between the GetMemoryMap() and ExitBootServices()
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->ExitBootServices (gImageHandle, MapKey);
+ if (EFI_ERROR (Status)) {
+ FreePages (MemoryMap, Pages);
+ MemoryMap = NULL;
+ MemoryMapSize = 0;
+ }
+ }
+ }
+ } while (EFI_ERROR (Status));
+\r
+ //\r
+ // At this point it is very dangerous to do things EFI as most of EFI is now gone.\r
+ // This command is useful if you are working with a debugger as it will shutdown\r
+ // DMA and other things that could break a soft resets.\r
+ // \r
+ CpuDeadLoop ();\r
+ \r
+ // Should never get here, but makes the compiler happy\r
+ return EFI_ABORTED;\r
+}\r
+\r
+\r
+/**\r
+ Update the screen by decrementing the timeout value.\r
+ This AsciiPrint has to match the AsciiPrint in \r
+ EblPauseCmd. \r
+\r
+ @param ElaspedTime Current timout value remaining\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EblPauseCallback (\r
+ IN UINTN ElapsedTime\r
+ )\r
+{\r
+ AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime);\r
+}\r
+\r
+/**\r
+ Pause until a key is pressed and abort the remaining commands on the command\r
+ line. If no key is pressed continue processing the command line. This command\r
+ allows the user to stop an operation from happening and return control to the\r
+ command prompt.\r
+\r
+ Argv[0] - "pause"\r
+ Argv[1] - timeout value is decimal seconds\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 comamnd name\r
+\r
+ @return EFI_SUCCESS Timeout expired with no input\r
+ @return EFI_TIMEOUT Stop procesing other commands on the same command line\r
+\r
+**/\r
+EFI_STATUS\r
+EblPauseCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Delay;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);\r
+\r
+ AsciiPrint ("Hit any key to break. You have %3d seconds", Delay);\r
+ Status = EblGetCharKey (&Key, Delay, EblPauseCallback);\r
+ AsciiPrint ("\n");\r
+\r
+ // If we timeout then the pause succeded thus return success\r
+ // If we get a key return timout to stop other commnad on this cmd line\r
+ return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;;\r
+}\r
+\r
+\r
+/**\r
+ On a debug build issue a software breakpoint to enter the debugger\r
+\r
+ Argv[0] - "break"\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 comamnd name\r
+\r
+ @return EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EblBreakPointCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ CpuBreakpoint ();\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reset the system. If no Argument do a Cold reset. If argument use that reset type\r
+ (W)arm = Warm Reset\r
+ (S)hutdown = Shutdown Reset\r
+\r
+ Argv[0] - "reset"\r
+ Argv[1] - warm or shutdown reset type\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 comamnd name\r
+\r
+ @return EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EblResetCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ EFI_RESET_TYPE ResetType;\r
+\r
+ ResetType = EfiResetCold;\r
+ if (Argc > 1) {\r
+ switch (*Argv[1]) {\r
+ case 'W':\r
+ case 'w':\r
+ ResetType = EfiResetWarm;\r
+ break;\r
+ case 'S':\r
+ case 's':\r
+ ResetType = EfiResetShutdown;\r
+ }\r
+ } \r
+\r
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Toggle page break global. This turns on and off prompting to Quit or hit any\r
+ key to continue when a command is about to scroll the screen with its output\r
+\r
+ Argv[0] - "page"\r
+ Argv[1] - on or off\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 comamnd name\r
+\r
+ @return EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EblPageCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ if (Argc <= 1) {\r
+ // toggle setting \r
+ gPageBreak = (gPageBreak) ? FALSE : TRUE;\r
+ } else {\r
+ // use argv to set the value\r
+ if ((Argv[1][0] == 'o') || (Argv[1][0] == 'O')) {\r
+ if ((Argv[1][1] == 'n') || (Argv[1][1] == 'N')) {\r
+ gPageBreak = TRUE;\r
+ } else if ((Argv[1][1] == 'f') || (Argv[1][1] == 'F')) {\r
+ gPageBreak = FALSE;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EblSleepCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ UINTN Delay;\r
+\r
+ Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);\r
+\r
+ gBS->Stall (Delay * 1000000);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+CHAR8\r
+ConvertToTextLine (\r
+ IN CHAR8 Character\r
+ )\r
+{\r
+ if (Character < ' ' || Character > '~')\r
+ {\r
+ return '.';\r
+ }\r
+ else\r
+ {\r
+ return Character;\r
+ }\r
+}\r
+\r
+UINTN\r
+GetBytes (\r
+ IN UINT8 *Address,\r
+ IN UINTN Bytes\r
+ )\r
+{\r
+ UINTN Result = 0;\r
+\r
+ if (Bytes >= 1)\r
+ Result = *Address++;\r
+ \r
+ if (Bytes >= 2)\r
+ Result = (Result << 8) + *Address++;\r
+ \r
+ if (Bytes >= 3)\r
+ Result = (Result << 8) + *Address++;\r
+\r
+ return Result;\r
+}\r
+\r
+CHAR8 mBlanks[] = " ";\r
+\r
+EFI_STATUS\r
+OutputData (\r
+ IN UINT8 *Address,\r
+ IN UINTN Length,\r
+ IN UINTN Width,\r
+ IN UINTN Offset\r
+ )\r
+{\r
+ UINT8 *EndAddress;\r
+ UINTN Line;\r
+ CHAR8 TextLine[0x11];\r
+ UINTN CurrentRow = 0;\r
+ UINTN Bytes;\r
+ UINTN Spaces = 0;\r
+ CHAR8 Blanks[80];\r
+\r
+ AsciiStrCpy (Blanks, mBlanks);\r
+ for (EndAddress = Address + Length; Address < EndAddress; Offset += Line)\r
+ {\r
+ AsciiPrint ("%08x: ", Offset);\r
+ for (Line = 0; (Line < 0x10) && (Address < EndAddress);)\r
+ {\r
+ Bytes = EndAddress - Address;\r
+ \r
+ switch (Width)\r
+ {\r
+ case 4:\r
+ if (Bytes >= 4)\r
+ {\r
+ AsciiPrint ("%08x ", *((UINT32 *)Address));\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ }\r
+ else\r
+ {\r
+ AsciiPrint ("%08x ", GetBytes(Address, Bytes));\r
+ Address += Bytes;\r
+ Line += Bytes;\r
+ }\r
+ break;\r
+\r
+ case 2:\r
+ if (Bytes >= 2)\r
+ {\r
+ AsciiPrint ("%04x ", *((UINT16 *)Address));\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ }\r
+ else\r
+ {\r
+ AsciiPrint ("%04x ", GetBytes(Address, Bytes));\r
+ Address += Bytes;\r
+ Line += Bytes;\r
+ }\r
+ break;\r
+\r
+ case 1:\r
+ AsciiPrint ("%02x ", *((UINT8 *)Address));\r
+ TextLine[Line++] = ConvertToTextLine(*Address++);\r
+ break;\r
+\r
+ default:\r
+ AsciiPrint ("Width must be 1, 2, or 4!\n");\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ // Pad spaces\r
+ if (Line < 0x10)\r
+ {\r
+ switch (Width)\r
+ {\r
+ case 4:\r
+ Spaces = 9 * ((0x10 - Line)/4);\r
+ break;\r
+ case 2:\r
+ Spaces = 5 * ((0x10 - Line)/2);\r
+ break;\r
+ case 1:\r
+ Spaces = 3 * (0x10 - Line);\r
+ break;\r
+ }\r
+\r
+ Blanks[Spaces] = '\0';\r
+\r
+ AsciiPrint(Blanks);\r
+ \r
+ Blanks[Spaces] = ' ';\r
+ }\r
+\r
+ TextLine[Line] = 0;\r
+ AsciiPrint ("|%a|\n", TextLine);\r
+\r
+ if (EblAnyKeyToContinueQtoQuit(&CurrentRow, FALSE))\r
+ {\r
+ return EFI_END_OF_FILE;\r
+ }\r
+ }\r
+\r
+ if (Length % Width != 0)\r
+ {\r
+ AsciiPrint ("%08x\n", Offset);\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+#define HEXDUMP_CHUNK 1024\r
+\r
+EFI_STATUS\r
+EblHexdumpCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ EFI_OPEN_FILE *File;\r
+ VOID *Location;\r
+ UINTN Size;\r
+ UINTN Width = 1;\r
+ UINTN Offset = 0;\r
+ EFI_STATUS Status;\r
+ UINTN Chunk = HEXDUMP_CHUNK;\r
+\r
+ if ((Argc < 2) || (Argc > 3))\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if (Argc == 3)\r
+ {\r
+ Width = AsciiStrDecimalToUintn(Argv[2]);\r
+ }\r
+ \r
+ if ((Width != 1) && (Width != 2) && (Width != 4))\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ File = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);\r
+ if (File == NULL)\r
+ {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Location = AllocatePool(Chunk);\r
+ Size = EfiTell(File, NULL);\r
+\r
+ for (Offset = 0; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk)\r
+ {\r
+ Chunk = HEXDUMP_CHUNK;\r
+ \r
+ Status = EfiRead(File, Location, &Chunk);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint ("Error reading file content\n");\r
+ goto Exit;\r
+ }\r
+\r
+ Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ if (Status == EFI_END_OF_FILE) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ goto Exit;\r
+ }\r
+ }\r
+ \r
+ // Any left over?\r
+ if (Offset < Size)\r
+ {\r
+ Chunk = Size - Offset;\r
+ Status = EfiRead(File, Location, &Chunk);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint ("Error reading file content\n");\r
+ goto Exit;\r
+ }\r
+\r
+ Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ if (Status == EFI_END_OF_FILE) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ EfiClose(File);\r
+\r
+ FreePool(Location);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+#define USE_DISKIO 1\r
+\r
+EFI_STATUS\r
+EblDiskIoCmd (\r
+ IN UINTN Argc,\r
+ IN CHAR8 **Argv\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Offset;\r
+ UINT8 *EndOffset;\r
+ UINTN Length;\r
+ UINTN Line;\r
+ UINT8 *Buffer;\r
+ UINT8 *BufferOffset;\r
+ CHAR8 TextLine[0x11];\r
+#if USE_DISKIO\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+#else\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ UINTN Lba;\r
+#endif \r
+\r
+ if (AsciiStrCmp(Argv[1], "r") == 0)\r
+ { \r
+ Offset = AsciiStrHexToUintn(Argv[2]);\r
+ Length = AsciiStrHexToUintn(Argv[3]);\r
+\r
+#if USE_DISKIO\r
+ Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("Did not locate DiskIO\n");\r
+ return Status;\r
+ }\r
+\r
+ Buffer = AllocatePool(Length);\r
+ BufferOffset = Buffer;\r
+ \r
+ Status = DiskIo->ReadDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("DiskIO read failed\n");\r
+ gBS->FreePool(Buffer);\r
+ return Status;\r
+ } \r
+#else\r
+ Status = gBS->LocateProtocol(&gEfiBlockIoProtocolGuid, NULL, (VOID **)&BlockIo);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("Did not locate BlockIo\n");\r
+ return Status;\r
+ }\r
+ \r
+ Length = BlockIo->Media->BlockSize;\r
+ Buffer = AllocatePool(Length);\r
+ BufferOffset = Buffer;\r
+ Lba = Offset/BlockIo->Media->BlockSize;\r
+ \r
+ Status = BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, Lba, Length, Buffer);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("BlockIo read failed\n");\r
+ gBS->FreePool(Buffer);\r
+ return Status;\r
+ }\r
+ \r
+ // Whack offset to what we actually read from\r
+ Offset = Lba * BlockIo->Media->BlockSize;\r
+ \r
+ Length = 0x100;\r
+#endif\r
+\r
+ for (EndOffset = BufferOffset + Length; BufferOffset < EndOffset; Offset += 0x10)\r
+ {\r
+ AsciiPrint ("%08x: ", Offset);\r
+ \r
+ for (Line = 0; Line < 0x10; Line++)\r
+ {\r
+ AsciiPrint ("%02x ", *BufferOffset);\r
+\r
+ if (*BufferOffset < ' ' || *BufferOffset > '~')\r
+ TextLine[Line] = '.';\r
+ else\r
+ TextLine[Line] = *BufferOffset;\r
+ \r
+ BufferOffset++;\r
+ }\r
+\r
+ TextLine[Line] = '\0';\r
+ AsciiPrint ("|%a|\n", TextLine);\r
+ }\r
+ \r
+ gBS->FreePool(Buffer);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ else if (AsciiStrCmp(Argv[1], "w") == 0)\r
+ {\r
+ Offset = AsciiStrHexToUintn(Argv[2]);\r
+ Length = AsciiStrHexToUintn(Argv[3]);\r
+ Buffer = (UINT8 *)AsciiStrHexToUintn(Argv[4]);\r
+ \r
+#if USE_DISKIO\r
+ Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("Did not locate DiskIO\n");\r
+ return Status;\r
+ }\r
+\r
+ Status = DiskIo->WriteDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);\r
+ if (EFI_ERROR(Status))\r
+ {\r
+ AsciiPrint("DiskIO write failed\n");\r
+ return Status;\r
+ }\r
+\r
+#else\r
+#endif\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+}\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdTemplate[] =\r
+{\r
+ {\r
+ "reset",\r
+ " [type]; Reset system. type = [warm] [shutdown] default is cold reset",\r
+ NULL,\r
+ EblResetCmd\r
+ },\r
+ {\r
+ "exit",\r
+ "; Exit EBL",\r
+ NULL,\r
+ EblExitCmd\r
+ },\r
+ {\r
+ "help",\r
+ " [cmd]; Help on cmd or a list of all commands if cmd is ommited",\r
+ NULL,\r
+ EblHelpCmd\r
+ },\r
+ {\r
+ "break",\r
+ "; Generate debugging breakpoint",\r
+ NULL,\r
+ EblBreakPointCmd\r
+ },\r
+ {\r
+ "page",\r
+ " [on|off]]; toggle promting on command output larger than screen",\r
+ NULL,\r
+ EblPageCmd\r
+ },\r
+ {\r
+ "pause",\r
+ " [sec]; Pause for sec[10] seconds. ",\r
+ NULL,\r
+ EblPauseCmd\r
+ },\r
+ {\r
+ "sleep",\r
+ " [sec]; Sleep for sec[10] seconds. ",\r
+ NULL,\r
+ EblSleepCmd\r
+ },\r
+ {\r
+ "hexdump",\r
+ " filename ; dump a file as hex bytes",\r
+ NULL,\r
+ EblHexdumpCmd\r
+ },\r
+ {\r
+ "diskio",\r
+ " [r|w] offset [length [dataptr]]; do a DiskIO read or write ",\r
+ NULL,\r
+ EblDiskIoCmd\r
+ } \r
+};\r
+\r
+\r
+EFI_HANDLE gExternalCmdHandle = NULL;\r
+\r
+/**\r
+ Initialize the commands in this in this file\r
+**/\r
+VOID\r
+EblInitializeCmdTable (\r
+ VOID\r
+ )\r
+{\r
+\r
+ EblAddCommands (mCmdTemplate, sizeof (mCmdTemplate)/sizeof (EBL_COMMAND_TABLE));\r
+ \r
+ gBS->InstallProtocolInterface (\r
+ &gExternalCmdHandle,\r
+ &gEfiEblAddCommandProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &gEblAddCommand\r
+ );\r
+\r
+}\r
+\r
+\r
+VOID\r
+EblShutdownExternalCmdTable (\r
+ VOID\r
+ )\r
+{\r
+ gBS->UninstallProtocolInterface (gExternalCmdHandle, &gEfiEblAddCommandProtocolGuid, &gEblAddCommand);\r
+}\r
+\r
+\r