summaryrefslogtreecommitdiff
path: root/EmbeddedPkg/Ebl
diff options
context:
space:
mode:
authorAJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-06 01:57:05 +0000
committerAJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-06 01:57:05 +0000
commit2ef2b01e07c02db339f34004445734a2dbdd80e1 (patch)
tree19532a6be8d8bdb0aef04bd00c1efb582f6dc841 /EmbeddedPkg/Ebl
parentf7753a96ba1653ddd31b01c198a352f6332ac404 (diff)
downloadedk2-2ef2b01e07c02db339f34004445734a2dbdd80e1.zip
edk2-2ef2b01e07c02db339f34004445734a2dbdd80e1.tar.gz
edk2-2ef2b01e07c02db339f34004445734a2dbdd80e1.tar.bz2
Adding support for BeagleBoard.
ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers. EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell. BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine). git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EmbeddedPkg/Ebl')
-rw-r--r--EmbeddedPkg/Ebl/CmdTemplate.c65
-rw-r--r--EmbeddedPkg/Ebl/Command.c978
-rw-r--r--EmbeddedPkg/Ebl/Dir.c305
-rw-r--r--EmbeddedPkg/Ebl/Ebl.h194
-rw-r--r--EmbeddedPkg/Ebl/Ebl.inf110
-rw-r--r--EmbeddedPkg/Ebl/EfiDevice.c969
-rw-r--r--EmbeddedPkg/Ebl/Hob.c232
-rw-r--r--EmbeddedPkg/Ebl/HwDebug.c342
-rw-r--r--EmbeddedPkg/Ebl/HwIoDebug.c153
-rw-r--r--EmbeddedPkg/Ebl/Main.c616
-rw-r--r--EmbeddedPkg/Ebl/Network.c104
-rw-r--r--EmbeddedPkg/Ebl/Script.c126
12 files changed, 4194 insertions, 0 deletions
diff --git a/EmbeddedPkg/Ebl/CmdTemplate.c b/EmbeddedPkg/Ebl/CmdTemplate.c
new file mode 100644
index 0000000..456c4af
--- /dev/null
+++ b/EmbeddedPkg/Ebl/CmdTemplate.c
@@ -0,0 +1,65 @@
+/** @file
+ %CommandName% for EBL (Embedded Boot Loader)
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ 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.
+
+ Module Name: CmdTemplate.c
+
+ Search/Replace %CommandName% with the name of your new command
+
+**/
+
+#include "Ebl.h"
+
+
+/**
+ Fill Me In
+
+ Argv[0] - "%CommandName%"
+
+ @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
+Ebl%CommandName%Cmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmd%CommandName%Template[] =
+{
+ {
+ "%CommandName%",
+ " [show args] ; explain args and command",
+ NULL,
+ Ebl%CommandName%Cmd
+ }
+};
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitialize%CommandName%Cmd (
+ VOID
+ )
+{
+ EblAddCommands (mCmd%CommandName%Template, sizeof (mCmd%CommandName%Template)/sizeof (EBL_COMMAND_TABLE));
+}
+
diff --git a/EmbeddedPkg/Ebl/Command.c b/EmbeddedPkg/Ebl/Command.c
new file mode 100644
index 0000000..7899a0f
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Command.c
@@ -0,0 +1,978 @@
+/** @file
+ Basic commands and command processing infrastructure for EBL
+
+ 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"
+#include <Protocol/DiskIo.h>
+#include <Protocol/BlockIo.h>
+
+UINTN mCmdTableMaxIndex = EBL_MAX_COMMAND_COUNT;
+UINTN mCmdTableNextFreeIndex = 0;
+EBL_COMMAND_TABLE *mCmdTable[EBL_MAX_COMMAND_COUNT];
+
+/**
+ Converts a lowercase Ascii character to upper one
+
+ If Chr is lowercase Ascii character, then converts it to upper one.
+
+ If Value >= 0xA0, then ASSERT().
+ If (Value & 0x0F) >= 0x0A, then ASSERT().
+
+ @param chr one Ascii character
+
+ @return The uppercase value of Ascii character
+
+**/
+STATIC
+CHAR8
+AsciiToUpper (
+ IN CHAR8 Chr
+ )
+{
+ return (UINT8) ((Chr >= 'a' && Chr <= 'z') ? Chr - ('a' - 'A') : Chr);
+}
+
+
+/**
+ Case insensitve comparison of two Null-terminated Unicode strings with maximum
+ lengths, and returns the difference between the first mismatched Unicode
+ characters.
+ This function compares the Null-terminated Unicode string FirstString to the
+ Null-terminated Unicode string SecondString. At most, Length Unicode
+ characters will be compared. If Length is 0, then 0 is returned. If
+ FirstString is identical to SecondString, then 0 is returned. Otherwise, the
+ value returned is the first mismatched Unicode character in SecondString
+ subtracted from the first mismatched Unicode character in FirstString.
+
+ @param FirstString Pointer to a Null-terminated ASCII string.
+ @param SecondString Pointer to a Null-terminated ASCII string.
+ @param Length Max length to compare.
+
+ @retval 0 FirstString is identical to SecondString using case insensitive
+ comparisons.
+ @retval !=0 FirstString is not identical to SecondString using case
+ insensitive comparisons.
+
+**/
+INTN
+EFIAPI
+AsciiStrniCmp (
+ IN CONST CHAR8 *FirstString,
+ IN CONST CHAR8 *SecondString,
+ IN UINTN Length
+ )
+{
+ if (Length == 0) {
+ return 0;
+ }
+
+ while ((AsciiToUpper (*FirstString) != '\0') &&
+ (AsciiToUpper (*FirstString) == AsciiToUpper (*SecondString)) &&
+ (Length > 1)) {
+ FirstString++;
+ SecondString++;
+ Length--;
+ }
+
+ return AsciiToUpper (*FirstString) - AsciiToUpper (*SecondString);
+}
+
+
+
+/**
+ Add a command to the mCmdTable. If there is no free space in the command
+ table ASSERT. The mCmdTable is maintained in alphabetical order and the
+ new entry is inserted into its sorted possition.
+
+ @param Entry Commnad Entry to add to the CmdTable
+
+**/
+VOID
+EFIAPI
+EblAddCommand (
+ IN const EBL_COMMAND_TABLE *Entry
+ )
+{
+ UINTN Count;
+
+ if (mCmdTableNextFreeIndex == EBL_MAX_COMMAND_COUNT) {
+ //
+ // Ran out of space to store commands. Increase EBL_MAX_COMMAND_COUNT
+ //
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Add command and Insertion sort array in the process
+ //
+ mCmdTable[mCmdTableNextFreeIndex] = (EBL_COMMAND_TABLE *)Entry;
+ if (mCmdTableNextFreeIndex != 0) {
+ for (Count = mCmdTableNextFreeIndex; Count > 0; Count--) {
+ if (AsciiStriCmp (mCmdTable[Count - 1]->Name, Entry->Name) <= 0) {
+ break;
+ }
+
+ mCmdTable[Count] = mCmdTable[Count - 1];
+ }
+ mCmdTable[Count] = (EBL_COMMAND_TABLE *)Entry;
+ }
+
+ mCmdTableNextFreeIndex++;
+}
+
+
+/**
+ Add an set of commands to the command table. Most commonly used on static
+ array of commands.
+
+ @param EntryArray Pointer to array of command entries
+ @param ArrayCount Number of commnad entries to add
+
+**/
+VOID
+EFIAPI
+EblAddCommands (
+ IN const EBL_COMMAND_TABLE *EntryArray,
+ IN UINTN ArrayCount
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < ArrayCount; Index++) {
+ EblAddCommand (&EntryArray[Index]);
+ }
+}
+
+
+EBL_ADD_COMMAND_PROTOCOL gEblAddCommand = {
+ EblAddCommand,
+ EblAddCommands,
+ EblGetCharKey,
+ EblAnyKeyToContinueQtoQuit
+};
+
+
+
+/**
+ Return the best matching command for the passed in command name. The match
+ does not have to be exact, it just needs to be unqiue. This enables commands
+ to be shortend to the smallest set of starting characters that is unique.
+
+ @param CommandName Name of command to search for
+
+ @return NULL CommandName did not match or was not unique
+ Other Pointer to EBL_COMMAND_TABLE entry for CommandName
+
+**/
+EBL_COMMAND_TABLE *
+EblGetCommand (
+ IN CHAR8 *CommandName
+ )
+{
+ UINTN Index;
+ UINTN BestMatchCount;
+ UINTN Length;
+ EBL_COMMAND_TABLE *Match;
+
+ Length = AsciiStrLen (CommandName);
+ for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) {
+ if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) {
+ // match a command exactly
+ return mCmdTable[Index];
+ }
+
+ if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) {
+ // partial match, so keep looking to make sure there is only one partial match
+ BestMatchCount++;
+ Match = mCmdTable[Index];
+ }
+ }
+
+ if (BestMatchCount == 1) {
+ return Match;
+ }
+
+ //
+ // We had no matches or too many matches
+ //
+ return NULL;
+}
+
+
+
+/**
+ List out help information on all the commands or print extended information
+ about a specific passed in command.
+
+ Argv[0] - "help"
+ Argv[1] - Command to display help about
+
+ @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
+EblHelpCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN Index;
+ CHAR8 *Ptr;
+ UINTN CurrentRow;
+
+ if (Argc == 1) {
+ // Print all the commands
+ AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n");
+ for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) {
+ EblSetTextColor (EFI_YELLOW);
+ AsciiPrint (" %a", mCmdTable[Index]->Name);
+ EblSetTextColor (0);
+ AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary);
+ }
+ } else if (Argv[1] != NULL) {
+ // Print specific help
+ for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) {
+ if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) {
+ Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help;
+ AsciiPrint ("%a%a\n", Argv[1], Ptr);
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ break;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Exit the EBL. If the commnad processor sees EFI_ABORTED return status it will
+ exit the EBL.
+
+ Argv[0] - "exit"
+
+ @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_ABORTED
+
+**/
+EFI_STATUS
+EblExitCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINTN DescriptorVersion;
+ UINTN Pages;
+
+ if (Argc > 1) {
+ if (AsciiStriCmp (Argv[1], "efi") != 0) {
+ return EFI_ABORTED;
+ }
+ } else if (Argc == 1) {
+ return EFI_ABORTED;
+ }
+
+ 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));
+
+ //
+ // At this point it is very dangerous to do things EFI as most of EFI is now gone.
+ // This command is useful if you are working with a debugger as it will shutdown
+ // DMA and other things that could break a soft resets.
+ //
+ CpuDeadLoop ();
+
+ // Should never get here, but makes the compiler happy
+ return EFI_ABORTED;
+}
+
+
+/**
+ Update the screen by decrementing the timeout value.
+ This AsciiPrint has to match the AsciiPrint in
+ EblPauseCmd.
+
+ @param ElaspedTime Current timout value remaining
+
+**/
+VOID
+EFIAPI
+EblPauseCallback (
+ IN UINTN ElapsedTime
+ )
+{
+ AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime);
+}
+
+/**
+ Pause until a key is pressed and abort the remaining commands on the command
+ line. If no key is pressed continue processing the command line. This command
+ allows the user to stop an operation from happening and return control to the
+ command prompt.
+
+ Argv[0] - "pause"
+ Argv[1] - timeout value is decimal seconds
+
+ @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 Timeout expired with no input
+ @return EFI_TIMEOUT Stop procesing other commands on the same command line
+
+**/
+EFI_STATUS
+EblPauseCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ UINTN Delay;
+ EFI_INPUT_KEY Key;
+
+ Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
+
+ AsciiPrint ("Hit any key to break. You have %3d seconds", Delay);
+ Status = EblGetCharKey (&Key, Delay, EblPauseCallback);
+ AsciiPrint ("\n");
+
+ // If we timeout then the pause succeded thus return success
+ // If we get a key return timout to stop other commnad on this cmd line
+ return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;;
+}
+
+
+/**
+ On a debug build issue a software breakpoint to enter the debugger
+
+ Argv[0] - "break"
+
+ @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
+EblBreakPointCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ CpuBreakpoint ();
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the system. If no Argument do a Cold reset. If argument use that reset type
+ (W)arm = Warm Reset
+ (S)hutdown = Shutdown Reset
+
+ Argv[0] - "reset"
+ Argv[1] - warm or shutdown reset type
+
+ @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
+EblResetCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_RESET_TYPE ResetType;
+
+ ResetType = EfiResetCold;
+ if (Argc > 1) {
+ switch (*Argv[1]) {
+ case 'W':
+ case 'w':
+ ResetType = EfiResetWarm;
+ break;
+ case 'S':
+ case 's':
+ ResetType = EfiResetShutdown;
+ }
+ }
+
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Toggle page break global. This turns on and off prompting to Quit or hit any
+ key to continue when a command is about to scroll the screen with its output
+
+ Argv[0] - "page"
+ Argv[1] - on or off
+
+ @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
+EblPageCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ if (Argc <= 1) {
+ // toggle setting
+ gPageBreak = (gPageBreak) ? FALSE : TRUE;
+ } else {
+ // use argv to set the value
+ if ((Argv[1][0] == 'o') || (Argv[1][0] == 'O')) {
+ if ((Argv[1][1] == 'n') || (Argv[1][1] == 'N')) {
+ gPageBreak = TRUE;
+ } else if ((Argv[1][1] == 'f') || (Argv[1][1] == 'F')) {
+ gPageBreak = FALSE;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EblSleepCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN Delay;
+
+ Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
+
+ gBS->Stall (Delay * 1000000);
+
+ return EFI_SUCCESS;
+}
+
+CHAR8
+ConvertToTextLine (
+ IN CHAR8 Character
+ )
+{
+ if (Character < ' ' || Character > '~')
+ {
+ return '.';
+ }
+ else
+ {
+ return Character;
+ }
+}
+
+UINTN
+GetBytes (
+ IN UINT8 *Address,
+ IN UINTN Bytes
+ )
+{
+ UINTN Result = 0;
+
+ if (Bytes >= 1)
+ Result = *Address++;
+
+ if (Bytes >= 2)
+ Result = (Result << 8) + *Address++;
+
+ if (Bytes >= 3)
+ Result = (Result << 8) + *Address++;
+
+ return Result;
+}
+
+CHAR8 mBlanks[] = " ";
+
+EFI_STATUS
+OutputData (
+ IN UINT8 *Address,
+ IN UINTN Length,
+ IN UINTN Width,
+ IN UINTN Offset
+ )
+{
+ UINT8 *EndAddress;
+ UINTN Line;
+ CHAR8 TextLine[0x11];
+ UINTN CurrentRow = 0;
+ UINTN Bytes;
+ UINTN Spaces = 0;
+ CHAR8 Blanks[80];
+
+ AsciiStrCpy (Blanks, mBlanks);
+ for (EndAddress = Address + Length; Address < EndAddress; Offset += Line)
+ {
+ AsciiPrint ("%08x: ", Offset);
+ for (Line = 0; (Line < 0x10) && (Address < EndAddress);)
+ {
+ Bytes = EndAddress - Address;
+
+ switch (Width)
+ {
+ case 4:
+ if (Bytes >= 4)
+ {
+ AsciiPrint ("%08x ", *((UINT32 *)Address));
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ }
+ else
+ {
+ AsciiPrint ("%08x ", GetBytes(Address, Bytes));
+ Address += Bytes;
+ Line += Bytes;
+ }
+ break;
+
+ case 2:
+ if (Bytes >= 2)
+ {
+ AsciiPrint ("%04x ", *((UINT16 *)Address));
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ }
+ else
+ {
+ AsciiPrint ("%04x ", GetBytes(Address, Bytes));
+ Address += Bytes;
+ Line += Bytes;
+ }
+ break;
+
+ case 1:
+ AsciiPrint ("%02x ", *((UINT8 *)Address));
+ TextLine[Line++] = ConvertToTextLine(*Address++);
+ break;
+
+ default:
+ AsciiPrint ("Width must be 1, 2, or 4!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ // Pad spaces
+ if (Line < 0x10)
+ {
+ switch (Width)
+ {
+ case 4:
+ Spaces = 9 * ((0x10 - Line)/4);
+ break;
+ case 2:
+ Spaces = 5 * ((0x10 - Line)/2);
+ break;
+ case 1:
+ Spaces = 3 * (0x10 - Line);
+ break;
+ }
+
+ Blanks[Spaces] = '\0';
+
+ AsciiPrint(Blanks);
+
+ Blanks[Spaces] = ' ';
+ }
+
+ TextLine[Line] = 0;
+ AsciiPrint ("|%a|\n", TextLine);
+
+ if (EblAnyKeyToContinueQtoQuit(&CurrentRow, FALSE))
+ {
+ return EFI_END_OF_FILE;
+ }
+ }
+
+ if (Length % Width != 0)
+ {
+ AsciiPrint ("%08x\n", Offset);
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define HEXDUMP_CHUNK 1024
+
+EFI_STATUS
+EblHexdumpCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_OPEN_FILE *File;
+ VOID *Location;
+ UINTN Size;
+ UINTN Width = 1;
+ UINTN Offset = 0;
+ EFI_STATUS Status;
+ UINTN Chunk = HEXDUMP_CHUNK;
+
+ if ((Argc < 2) || (Argc > 3))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Argc == 3)
+ {
+ Width = AsciiStrDecimalToUintn(Argv[2]);
+ }
+
+ if ((Width != 1) && (Width != 2) && (Width != 4))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ File = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
+ if (File == NULL)
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ Location = AllocatePool(Chunk);
+ Size = EfiTell(File, NULL);
+
+ for (Offset = 0; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk)
+ {
+ Chunk = HEXDUMP_CHUNK;
+
+ Status = EfiRead(File, Location, &Chunk);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint ("Error reading file content\n");
+ goto Exit;
+ }
+
+ Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);
+ if (EFI_ERROR(Status))
+ {
+ if (Status == EFI_END_OF_FILE) {
+ Status = EFI_SUCCESS;
+ }
+ goto Exit;
+ }
+ }
+
+ // Any left over?
+ if (Offset < Size)
+ {
+ Chunk = Size - Offset;
+ Status = EfiRead(File, Location, &Chunk);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint ("Error reading file content\n");
+ goto Exit;
+ }
+
+ Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);
+ if (EFI_ERROR(Status))
+ {
+ if (Status == EFI_END_OF_FILE) {
+ Status = EFI_SUCCESS;
+ }
+ goto Exit;
+ }
+ }
+
+Exit:
+ EfiClose(File);
+
+ FreePool(Location);
+
+ return EFI_SUCCESS;
+}
+
+#define USE_DISKIO 1
+
+EFI_STATUS
+EblDiskIoCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ UINT8 *EndOffset;
+ UINTN Length;
+ UINTN Line;
+ UINT8 *Buffer;
+ UINT8 *BufferOffset;
+ CHAR8 TextLine[0x11];
+#if USE_DISKIO
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+#else
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINTN Lba;
+#endif
+
+ if (AsciiStrCmp(Argv[1], "r") == 0)
+ {
+ Offset = AsciiStrHexToUintn(Argv[2]);
+ Length = AsciiStrHexToUintn(Argv[3]);
+
+#if USE_DISKIO
+ Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("Did not locate DiskIO\n");
+ return Status;
+ }
+
+ Buffer = AllocatePool(Length);
+ BufferOffset = Buffer;
+
+ Status = DiskIo->ReadDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("DiskIO read failed\n");
+ gBS->FreePool(Buffer);
+ return Status;
+ }
+#else
+ Status = gBS->LocateProtocol(&gEfiBlockIoProtocolGuid, NULL, (VOID **)&BlockIo);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("Did not locate BlockIo\n");
+ return Status;
+ }
+
+ Length = BlockIo->Media->BlockSize;
+ Buffer = AllocatePool(Length);
+ BufferOffset = Buffer;
+ Lba = Offset/BlockIo->Media->BlockSize;
+
+ Status = BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, Lba, Length, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("BlockIo read failed\n");
+ gBS->FreePool(Buffer);
+ return Status;
+ }
+
+ // Whack offset to what we actually read from
+ Offset = Lba * BlockIo->Media->BlockSize;
+
+ Length = 0x100;
+#endif
+
+ for (EndOffset = BufferOffset + Length; BufferOffset < EndOffset; Offset += 0x10)
+ {
+ AsciiPrint ("%08x: ", Offset);
+
+ for (Line = 0; Line < 0x10; Line++)
+ {
+ AsciiPrint ("%02x ", *BufferOffset);
+
+ if (*BufferOffset < ' ' || *BufferOffset > '~')
+ TextLine[Line] = '.';
+ else
+ TextLine[Line] = *BufferOffset;
+
+ BufferOffset++;
+ }
+
+ TextLine[Line] = '\0';
+ AsciiPrint ("|%a|\n", TextLine);
+ }
+
+ gBS->FreePool(Buffer);
+
+ return EFI_SUCCESS;
+ }
+ else if (AsciiStrCmp(Argv[1], "w") == 0)
+ {
+ Offset = AsciiStrHexToUintn(Argv[2]);
+ Length = AsciiStrHexToUintn(Argv[3]);
+ Buffer = (UINT8 *)AsciiStrHexToUintn(Argv[4]);
+
+#if USE_DISKIO
+ Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("Did not locate DiskIO\n");
+ return Status;
+ }
+
+ Status = DiskIo->WriteDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ AsciiPrint("DiskIO write failed\n");
+ return Status;
+ }
+
+#else
+#endif
+
+ return EFI_SUCCESS;
+ }
+ else
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdTemplate[] =
+{
+ {
+ "reset",
+ " [type]; Reset system. type = [warm] [shutdown] default is cold reset",
+ NULL,
+ EblResetCmd
+ },
+ {
+ "exit",
+ "; Exit EBL",
+ NULL,
+ EblExitCmd
+ },
+ {
+ "help",
+ " [cmd]; Help on cmd or a list of all commands if cmd is ommited",
+ NULL,
+ EblHelpCmd
+ },
+ {
+ "break",
+ "; Generate debugging breakpoint",
+ NULL,
+ EblBreakPointCmd
+ },
+ {
+ "page",
+ " [on|off]]; toggle promting on command output larger than screen",
+ NULL,
+ EblPageCmd
+ },
+ {
+ "pause",
+ " [sec]; Pause for sec[10] seconds. ",
+ NULL,
+ EblPauseCmd
+ },
+ {
+ "sleep",
+ " [sec]; Sleep for sec[10] seconds. ",
+ NULL,
+ EblSleepCmd
+ },
+ {
+ "hexdump",
+ " filename ; dump a file as hex bytes",
+ NULL,
+ EblHexdumpCmd
+ },
+ {
+ "diskio",
+ " [r|w] offset [length [dataptr]]; do a DiskIO read or write ",
+ NULL,
+ EblDiskIoCmd
+ }
+};
+
+
+EFI_HANDLE gExternalCmdHandle = NULL;
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializeCmdTable (
+ VOID
+ )
+{
+
+ EblAddCommands (mCmdTemplate, sizeof (mCmdTemplate)/sizeof (EBL_COMMAND_TABLE));
+
+ gBS->InstallProtocolInterface (
+ &gExternalCmdHandle,
+ &gEfiEblAddCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gEblAddCommand
+ );
+
+}
+
+
+VOID
+EblShutdownExternalCmdTable (
+ VOID
+ )
+{
+ gBS->UninstallProtocolInterface (gExternalCmdHandle, &gEfiEblAddCommandProtocolGuid, &gEblAddCommand);
+}
+
+
diff --git a/EmbeddedPkg/Ebl/Dir.c b/EmbeddedPkg/Ebl/Dir.c
new file mode 100644
index 0000000..4e9f7b9
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Dir.c
@@ -0,0 +1,305 @@
+/** @file
+ Dir for EBL (Embedded Boot Loader)
+
+ 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.
+
+ Module Name: CmdTemplate.c
+
+ Search/Replace Dir with the name of your new command
+
+**/
+
+#include "Ebl.h"
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *gFvFileType[] = {
+ "All",
+ "Raw",
+ "Freeform",
+ "SEC",
+ "PeiCore",
+ "DxeCore",
+ "PEIM",
+ "Driver",
+ "Combo Driver",
+ "Application",
+ "NULL",
+ "FV"
+};
+
+
+/**
+ Perform a dir on a device. The device must support Simple File System Protocol
+ or the FV protocol.
+
+ Argv[0] - "dir"
+ Argv[1] - Device Name:path. Path is optional
+ Argv[2] - Optional filename to match on. A leading * means match substring
+ Argv[3] - Optional FV file type
+
+ dir fs1:\efi ; perform a dir on fs1: device in the efi directory
+ dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but
+ only print out files that contain the string *.efi
+ dir fv1:\ ; perform a dir on fv1: device in the efi directory
+ NOTE: fv devices do not contian subdirs
+ dir fv1:\ * PEIM ; will match all files of type SEC
+
+ @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
+EblDirCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ EFI_OPEN_FILE *File;
+ EFI_FILE_INFO *DirInfo;
+ UINTN ReadSize;
+ UINTN CurrentRow;
+ CHAR16 *MatchSubString;
+ EFI_STATUS GetNextFileStatus;
+ UINTN Key;
+ EFI_FV_FILETYPE SearchType;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_GUID NameGuid;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINT32 AuthenticationStatus;
+ VOID *Section;
+ UINTN SectionSize;
+ EFI_FV_FILETYPE Index;
+ UINTN Length;
+ UINTN BestMatchCount;
+ CHAR16 UnicodeFileName[MAX_CMD_LINE];
+
+
+ if (Argc <= 1) {
+ // CWD not currently supported
+ return EFI_SUCCESS;
+ }
+
+ File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
+ if (File == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (File->Type == EfiOpenFirmwareVolume) {
+ // FV Dir
+
+ SearchType = EFI_FV_FILETYPE_ALL;
+ UnicodeFileName[0] = '\0';
+ MatchSubString = &UnicodeFileName[0];
+ if (Argc > 2) {
+ AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
+ if (UnicodeFileName[0] == '*') {
+ // Handle *Name substring matching
+ MatchSubString = &UnicodeFileName[1];
+ }
+
+ // Handle file type matchs
+ if (Argc > 3) {
+ // match a specific file type, always last argument
+ Length = AsciiStrLen (Argv[3]);
+ for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) {
+ if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) {
+ // exact match
+ SearchType = Index;
+ break;
+ }
+
+ if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) {
+ // partial match, so keep looking to make sure there is only one partial match
+ BestMatchCount++;
+ SearchType = Index;
+ }
+ }
+
+ if (BestMatchCount > 1) {
+ SearchType = EFI_FV_FILETYPE_ALL;
+ }
+ }
+ }
+
+ Fv = File->Fv;
+ Key = 0;
+ CurrentRow = 0;
+ do {
+ Type = SearchType;
+ GetNextFileStatus = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &Type,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (!EFI_ERROR (GetNextFileStatus)) {
+ // Calculate size of entire file
+ Section = NULL;
+ Size = 0;
+ Status = Fv->ReadFile (
+ Fv,
+ &NameGuid,
+ Section,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) {
+ // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid
+ Size = 0;
+ }
+
+ // read the UI seciton to do a name match.
+ Section = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ &Section,
+ &SectionSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ if (StrStr (Section, MatchSubString) != NULL) {
+ AsciiPrint (" %g %s %a %,d\n", &NameGuid, Section, gFvFileType[Type], Size);
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ break;
+ }
+ }
+ FreePool (Section);
+ } else {
+ if (*MatchSubString == '\0') {
+ AsciiPrint (" %g %a %,d\n", &NameGuid, gFvFileType[Type], Size);
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ break;
+ }
+ }
+ }
+ }
+ } while (!EFI_ERROR (GetNextFileStatus));
+
+ } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) {
+ // Simple File System DIR
+
+ if (File->FsFileInfo == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
+ return EFI_SUCCESS;
+ }
+
+ // Handle *Name substring matching
+ MatchSubString = NULL;
+ UnicodeFileName[0] = '\0';
+ if (Argc > 2) {
+ AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
+ if (UnicodeFileName[0] == '*') {
+ MatchSubString = &UnicodeFileName[1];
+ }
+ }
+
+ File->FsFileHandle->SetPosition (File->FsFileHandle, 0);
+ for (CurrentRow = 0;;) {
+ // First read gets the size
+ DirInfo = NULL;
+ ReadSize = 0;
+ Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ // Allocate the buffer for the real read
+ DirInfo = AllocatePool (ReadSize);
+ if (DirInfo == NULL) {
+ goto Done;
+ }
+
+ // Read the data
+ Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
+ if ((EFI_ERROR (Status)) || (ReadSize == 0)) {
+ break;
+ }
+ } else {
+ break;
+ }
+
+ if (MatchSubString != NULL) {
+ if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) {
+ // does not match *name argument, so skip
+ continue;
+ }
+ } else if (UnicodeFileName[0] != '\0') {
+ // is not an exact match for name argument, so skip
+ if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) {
+ continue;
+ }
+ }
+
+ if (DirInfo->Attribute & EFI_FILE_DIRECTORY) {
+ AsciiPrint (" <DIR> %s\n", &DirInfo->FileName[0]);
+ } else {
+ AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]);
+ }
+
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ break;
+ }
+
+ FreePool (DirInfo);
+ }
+
+Done:
+ if (DirInfo != NULL) {
+ FreePool (DirInfo);
+ }
+ }
+
+ EfiClose (File);
+
+ return EFI_SUCCESS;
+}
+
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =
+{
+ {
+ "dir",
+ " dirdev [*match]; directory listing of dirdev. opt match a substring",
+ NULL,
+ EblDirCmd
+ }
+};
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializeDirCmd (
+ VOID
+ )
+{
+ if (FeaturePcdGet (PcdEmbeddedDirCmd)) {
+ EblAddCommands (mCmdDirTemplate, sizeof (mCmdDirTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+}
+
diff --git a/EmbeddedPkg/Ebl/Ebl.h b/EmbeddedPkg/Ebl/Ebl.h
new file mode 100644
index 0000000..705511a
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Ebl.h
@@ -0,0 +1,194 @@
+/** @file
+ Include flie for basic command line parser for EBL (Embedded Boot Loader)
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
+
+ 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.
+
+**/
+
+#ifndef __EBL_H__
+#define __EBL_H__
+
+#include <PiDxe.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/PxeBaseCode.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/EblAddCommand.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/DxeServices.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/EfiFileLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/EblCmdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/EblNetworkLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+//
+// Prompt for the command line
+//
+#define CMD_SEPERATOR ';'
+#define EBL_MAX_COMMAND_COUNT 0x100
+#define MAX_CMD_HISTORY 16
+#define MAX_CMD_LINE 256
+#define MAX_ARGS 32
+
+#define EBL_CR 0x0a
+#define EBL_LF 0x0d
+
+#define EFI_SET_TIMER_TO_SECOND 10000000
+
+
+
+EBL_COMMAND_TABLE *
+EblGetCommand (
+ IN CHAR8 *CommandName
+ );
+
+
+EFI_STATUS
+EblPathToDevice (
+ IN CHAR8 *Path,
+ OUT EFI_HANDLE *DeviceHandle,
+ OUT EFI_DEVICE_PATH_PROTOCOL **PathDevicePath,
+ OUT VOID **Buffer,
+ OUT UINTN *BufferSize
+ );
+
+BOOLEAN
+EblAnyKeyToContinueQtoQuit (
+ IN UINTN *CurrentRow,
+ IN BOOLEAN PrefixNewline
+ );
+
+VOID
+EblUpdateDeviceLists (
+ VOID
+ );
+
+VOID
+EblInitializeCmdTable (
+ VOID
+ );
+
+VOID
+EblShutdownExternalCmdTable (
+ VOID
+ );
+
+VOID
+EblSetTextColor (
+ UINTN Attribute
+ );
+
+
+EFI_STATUS
+EblGetCharKey (
+ IN OUT EFI_INPUT_KEY *Key,
+ IN UINTN TimoutInSec,
+ IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
+ );
+
+// BugBug: Move me to a library
+INTN
+EFIAPI
+AsciiStrniCmp (
+ IN CONST CHAR8 *FirstString,
+ IN CONST CHAR8 *SecondString,
+ IN UINTN Length
+ );
+
+
+VOID
+EblInitializeDeviceCmd (
+ VOID
+ );
+
+VOID
+EblInitializemdHwDebugCmds (
+ VOID
+ );
+
+VOID
+EblInitializeDirCmd (
+ VOID
+ );
+
+VOID
+EblInitializeHobCmd (
+ VOID
+ );
+
+VOID
+EblInitializemdHwIoDebugCmds (
+ VOID
+ );
+
+VOID
+EblInitializeScriptCmd (
+ VOID
+ );
+
+VOID
+EblInitializeNetworkCmd (
+ VOID
+ );
+
+CHAR8 *
+ParseArguments (
+ IN CHAR8 *CmdLine,
+ OUT UINTN *Argc,
+ OUT CHAR8 **Argv
+ );
+
+EFI_STATUS
+ProcessCmdLine (
+ IN CHAR8 *CmdLine,
+ IN UINTN MaxCmdLineSize
+ );
+
+EFI_STATUS
+OutputData (
+ IN UINT8 *Address,
+ IN UINTN Length,
+ IN UINTN Width,
+ IN UINTN Offset
+ );
+
+extern UINTN gScreenColumns;
+extern UINTN gScreenRows;
+extern BOOLEAN gPageBreak;
+extern CHAR8 *gMemMapType[];
+
+#endif
+
diff --git a/EmbeddedPkg/Ebl/Ebl.inf b/EmbeddedPkg/Ebl/Ebl.inf
new file mode 100644
index 0000000..f341354
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Ebl.inf
@@ -0,0 +1,110 @@
+#%HEADER%
+#/** @file
+# EBL Applicaiton
+#
+# This is a shell application that will display Hello World.
+# Copyright (c) 2007, Intel Corporation.
+#
+# 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.
+#
+#
+#**/
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ebl
+ FILE_GUID = 3CEF354A-3B7A-4519-AD70-72A134698311
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = EdkBootLoaderEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+[Sources.common]
+ Main.c
+ Command.c
+ EfiDevice.c
+ HwDebug.c
+ HwIoDebug.c
+ Dir.c
+ Hob.c
+ Script.c
+ Ebl.h
+ Network.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiLib
+ UefiApplicationEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DevicePathLib
+ IoLib
+ PrintLib
+ PcdLib
+ EfiFileLib
+ HobLib
+ BaseLib
+ EblCmdLib
+ EblNetworkLib
+
+[LibraryClasses.ARM]
+ SemihostLib
+
+[Protocols.common]
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiLoadFileProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiPxeBaseCodeProtocolGuid
+ gEfiEblAddCommandProtocolGuid
+ gEfiDiskIoProtocolGuid
+ gEfiPciIoProtocolGuid
+ gEfiSimpleNetworkProtocolGuid
+
+[Guids.common]
+ gEfiDxeServicesTableGuid
+ gEfiFileInfoGuid
+ gEfiHobMemoryAllocModuleGuid
+ gEfiMemoryTypeInformationGuid
+
+[FeaturePcd.common]
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd
+
+[FixedPcd.common]
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedAutomaticBootCommand
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedShellCharacterEcho
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt
+
diff --git a/EmbeddedPkg/Ebl/EfiDevice.c b/EmbeddedPkg/Ebl/EfiDevice.c
new file mode 100644
index 0000000..7633d66
--- /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));
+}
+
diff --git a/EmbeddedPkg/Ebl/Hob.c b/EmbeddedPkg/Ebl/Hob.c
new file mode 100644
index 0000000..c541f66
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Hob.c
@@ -0,0 +1,232 @@
+/** @file
+ Hob command for EBL (Embedded Boot Loader)
+
+ 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.
+
+ Module Name: Hob.c
+
+ Search/Replace Dir with the name of your new command
+
+ Boot Mode:
+ ==========
+ BOOT_WITH_FULL_CONFIGURATION 0x00
+ BOOT_WITH_MINIMAL_CONFIGURATION 0x01
+ BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02
+ BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03
+ BOOT_WITH_DEFAULT_SETTINGS 0x04
+ BOOT_ON_S4_RESUME 0x05
+ BOOT_ON_S5_RESUME 0x06
+ BOOT_ON_S2_RESUME 0x10
+ BOOT_ON_S3_RESUME 0x11
+ BOOT_ON_FLASH_UPDATE 0x12
+ BOOT_IN_RECOVERY_MODE 0x20
+ BOOT_IN_RECOVERY_MODE_MASK 0x40
+ BOOT_SPECIAL_MASK 0x80
+
+ Mem Alloc HOB Type:
+ ===================
+ typedef enum {
+ EfiReservedMemoryType = 0x00
+ EfiLoaderCode = 0x01
+ EfiLoaderData = 0x02
+ EfiBootServicesCode = 0x03
+ EfiBootServicesData = 0x04
+ EfiRuntimeServicesCode = 0x05
+ EfiRuntimeServicesData = 0x06
+ EfiConventionalMemory = 0x07
+ EfiUnusableMemory = 0x08
+ EfiACPIReclaimMemory = 0x09
+ EfiACPIMemoryNVS = 0x0a
+ EfiMemoryMappedIO = 0x0b
+ EfiMemoryMappedIOPortSpace = 0x0c
+ EfiPalCode = 0x0d
+ EfiMaxMemoryType = 0x0e
+ } EFI_MEMORY_TYPE;
+
+ Resource Hob Tye:
+ =================
+ EFI_RESOURCE_SYSTEM_MEMORY 0
+ EFI_RESOURCE_MEMORY_MAPPED_IO 1
+ EFI_RESOURCE_IO 2
+ EFI_RESOURCE_FIRMWARE_DEVICE 3
+ EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 4
+ EFI_RESOURCE_MEMORY_RESERVED 5
+ EFI_RESOURCE_IO_RESERVED 6
+ EFI_RESOURCE_MAX_MEMORY_TYPE 7
+
+ Resource Hob Attribute (last thing printed):
+ ============================================
+ EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
+ EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
+ EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
+ EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
+ EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
+ EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
+ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
+ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
+ EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
+ EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
+
+**/
+
+#include "Ebl.h"
+// BugBug: Autogen does not allow this to be included currently
+//#include <EdkModulePkg/Include/EdkDxe.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED char *mHobResourceType[] = {
+ "Memory ",
+ "MMIO ",
+ "IO ",
+ "Firmware ",
+ "MMIO Port ",
+ "Reserved ",
+ "IO Reserved",
+ "Illegal "
+};
+
+
+/**
+ Dump out the HOBs in the system. HOBs are defined in the PI specificaiton
+ and they are used to hand off information from PEI to DXE.
+
+ Argv[0] - "hob"
+
+ @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
+EblHobCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN CurrentRow;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
+ UINTN Index;
+
+ CurrentRow = 0;
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
+ AsciiPrint ("PHIT HOB Ver %x Boot Mode %02x Top %lx Bottom %lx\n",
+ Hob.HandoffInformationTable->Version,
+ Hob.HandoffInformationTable->BootMode,
+ Hob.HandoffInformationTable->EfiMemoryTop,
+ Hob.HandoffInformationTable->EfiMemoryBottom
+ );
+
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ return EFI_SUCCESS;
+ }
+
+ AsciiPrint (" Free Top %lx Free Bottom %lx End Of HOB %lx\n",
+ Hob.HandoffInformationTable->EfiFreeMemoryTop,
+ Hob.HandoffInformationTable->EfiFreeMemoryBottom,
+ Hob.HandoffInformationTable->EfiEndOfHobList
+ );
+
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ // mod(%) on array index is just to prevent buffer overrun
+ AsciiPrint ("Mem Alloc HOB %a %g %08lx:%lx\n",
+ (Hob.MemoryAllocation->AllocDescriptor.MemoryType < EfiMaxMemoryType) ? gMemMapType[Hob.MemoryAllocation->AllocDescriptor.MemoryType] : "ILLEGAL TYPE",
+ &Hob.MemoryAllocation->AllocDescriptor.Name,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryLength
+ );
+ if (CompareGuid (&gEfiHobMemoryAllocModuleGuid, &Hob.MemoryAllocation->AllocDescriptor.Name)) {
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ return EFI_SUCCESS;
+ }
+ AsciiPrint (" Module Name %g EntryPoint %lx\n", &Hob.MemoryAllocationModule->ModuleName, Hob.MemoryAllocationModule->EntryPoint);
+ }
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ AsciiPrint ("Resource HOB %a %g %08lx:%lx\n Attributes: %08x\n",
+ (Hob.ResourceDescriptor->ResourceType < EFI_RESOURCE_MAX_MEMORY_TYPE) ? mHobResourceType[Hob.ResourceDescriptor->ResourceType] : mHobResourceType[EFI_RESOURCE_MAX_MEMORY_TYPE],
+ &Hob.ResourceDescriptor->Owner,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength,
+ Hob.ResourceDescriptor->ResourceAttribute
+ );
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ return EFI_SUCCESS;
+ }
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {
+ AsciiPrint ("GUID HOB %g\n", &Hob.Guid->Name);
+ if (CompareGuid (&gEfiMemoryTypeInformationGuid, &Hob.Guid->Name)) {
+ EfiMemoryTypeInformation = GET_GUID_HOB_DATA (Hob.Guid);
+ for (Index = 0; Index < (GET_GUID_HOB_DATA_SIZE (Hob.Guid)/sizeof (EFI_MEMORY_TYPE_INFORMATION)); Index++, EfiMemoryTypeInformation++) {
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ return EFI_SUCCESS;
+ }
+ AsciiPrint (" %a 0x%08x\n",
+ (EfiMemoryTypeInformation->Type < EfiMaxMemoryType) ? gMemMapType[EfiMemoryTypeInformation->Type] : "END ",
+ EfiMemoryTypeInformation->NumberOfPages
+ );
+ }
+ }
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {
+ AsciiPrint ("FV HOB %08lx:%08lx\n", Hob.FirmwareVolume->BaseAddress, Hob.FirmwareVolume->Length);
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_CPU) {
+ AsciiPrint ("CPU HOB: Mem %x IO %x\n", Hob.Cpu->SizeOfMemorySpace, Hob.Cpu->SizeOfIoSpace);
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_POOL) {
+ AsciiPrint ("Mem Pool HOB:\n");
+/* Not in PI
+ } else if (Hob.Header->HobType == EFI_HOB_TYPE_CV) {
+ AsciiPrint ("CV HOB: %08lx:%08lx\n", Hob.CapsuleVolume->BaseAddress, Hob.CapsuleVolume->Length);
+ */
+ }
+
+ if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHobTemplate[] =
+{
+ {
+ "hob",
+ "; dump HOBs",
+ NULL,
+ EblHobCmd
+ }
+};
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializeHobCmd (
+ VOID
+ )
+{
+ if (FeaturePcdGet (PcdEmbeddedHobCmd)) {
+ EblAddCommands (mCmdHobTemplate, sizeof (mCmdHobTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+}
+
diff --git a/EmbeddedPkg/Ebl/HwDebug.c b/EmbeddedPkg/Ebl/HwDebug.c
new file mode 100644
index 0000000..6ffbaf1
--- /dev/null
+++ b/EmbeddedPkg/Ebl/HwDebug.c
@@ -0,0 +1,342 @@
+/** @file
+ Basic command line parser for EBL (Embedded Boot Loader)
+
+ 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.
+
+ Module Name: HwDebug.c
+
+ Commands useful for debugging hardware.
+
+**/
+
+#include "Ebl.h"
+
+
+/**
+ Dump memory
+
+ Argv[0] - "md"
+ Argv[1] - Hex Address to dump
+ Argv[2] - Number of hex bytes to dump (0x20 is default)
+ Argv[3] - [1|2|4|8] byte width of the dump
+
+ md 0x123445678 50 4 ; Dump 0x50 4 byte quantities starting at 0x123445678
+ md 0x123445678 40 ; Dump 0x40 1 byte quantities starting at 0x123445678
+ md 0x123445678 ; Dump 0x20 1 byte quantities starting at 0x123445678
+
+ @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
+EblMdCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ STATIC UINT8 *Address = NULL;
+ STATIC UINTN Length = 0x20;
+ STATIC UINTN Width = 1;
+
+ switch (Argc)
+ {
+ case 4:
+ Width = AsciiStrHexToUintn(Argv[3]);
+ case 3:
+ Length = AsciiStrHexToUintn(Argv[2]);
+ case 2:
+ Address = (UINT8 *)AsciiStrHexToUintn(Argv[1]);
+ default:
+ break;
+ }
+
+ OutputData(Address, Length, Width, (UINTN)Address);
+
+ Address += Length;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill Memory with data
+
+ Argv[0] - "mfill"
+ Argv[1] - Hex Address to fill
+ Argv[2] - Data to write (0x00 is default)
+ Argv[3] - Number of units to dump.
+ Argv[4] - [1|2|4|8] byte width of the dump
+
+ mf 0x123445678 aa 1 100 ; Start at 0x123445678 and write aa (1 byte) to the next 100 bytes
+ mf 0x123445678 aa 4 100 ; Start at 0x123445678 and write aa (4 byte) to the next 400 bytes
+ mf 0x123445678 aa ; Start at 0x123445678 and write aa (4 byte) to the next 1 byte
+ mf 0x123445678 ; Start at 0x123445678 and write 00 (4 byte) to the next 1 byte
+
+ @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
+EblMfillCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN Address;
+ UINTN EndAddress;
+ UINT32 Data;
+ UINTN Length;
+ UINTN Width;
+
+ if (Argc < 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Address = AsciiStrHexToUintn (Argv[1]);
+ Data = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 0;
+ Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 4;
+ Length = (Argc > 4) ? AsciiStrHexToUintn (Argv[4]) : 1;
+
+ for (EndAddress = Address + (Length * Width); Address < EndAddress; Address += Width) {
+ if (Width == 4) {
+ MmioWrite32 (Address, Data);
+ } else if (Width == 2) {
+ MmioWrite32 (Address, (UINT16)Data);
+ } else {
+ MmioWrite32 (Address, (UINT8)Data);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//
+// Strings for PCI Class code [2]
+//
+CHAR8 *gPciDevClass[] = {
+ "Old Device ",
+ "Mass storage ",
+ "Network ",
+ "Display ",
+ "Multimedia ",
+ "Memory controller ",
+ "Bridge device ",
+ "simple communications ",
+ "base system peripherals",
+ "Input devices ",
+ "Docking stations ",
+ "Processors ",
+ "serial bus ",
+};
+
+
+CHAR8 *gPciSerialClassCodes[] = {
+ "Mass storage ",
+ "Firewire ",
+ "ACCESS bus ",
+ "SSA ",
+ "USB "
+};
+
+
+/**
+ PCI Dump
+
+ Argv[0] - "pci"
+ Argv[1] - bus
+ Argv[2] - dev
+ Argv[3] - func
+
+ @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
+EblPciCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *Pci;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Seg;
+ UINTN Bus;
+ UINTN Dev;
+ UINTN Func;
+ UINTN BusArg;
+ UINTN DevArg;
+ UINTN FuncArg;
+ UINTN Index;
+ UINTN Count;
+ PCI_TYPE_GENERIC PciHeader;
+ PCI_TYPE_GENERIC *Header;
+ PCI_BRIDGE_CONTROL_REGISTER *Bridge;
+ PCI_DEVICE_HEADER_TYPE_REGION *Device;
+ PCI_DEVICE_INDEPENDENT_REGION *Hdr;
+ CHAR8 *Str;
+ UINTN ThisBus;
+
+
+ BusArg = (Argc > 1) ? AsciiStrDecimalToUintn (Argv[1]) : 0;
+ DevArg = (Argc > 2) ? AsciiStrDecimalToUintn (Argv[2]) : 0;
+ FuncArg = (Argc > 3) ? AsciiStrDecimalToUintn (Argv[3]) : 0;
+
+ Header = &PciHeader;
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ AsciiPrint ("No PCI devices found in the system\n");
+ return EFI_SUCCESS;
+ }
+
+ if (Argc == 1) {
+ // Dump all PCI devices
+ AsciiPrint ("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
+ AsciiPrint ("_____________________________________________________________");
+ for (ThisBus = 0; ThisBus <= PCI_MAX_BUS; ThisBus++) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
+ if (!EFI_ERROR (Status)) {
+ Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
+ if (ThisBus != Bus) {
+ continue;
+ }
+ AsciiPrint ("\n%03d.%02d.%02d", Bus, Dev, Func);
+ Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), &PciHeader);
+ if (!EFI_ERROR (Status)) {
+ Hdr = &PciHeader.Bridge.Hdr;
+
+ if (Hdr->ClassCode[2] < sizeof (gPciDevClass)/sizeof (VOID *)) {
+ Str = gPciDevClass[Hdr->ClassCode[2]];
+ if (Hdr->ClassCode[2] == PCI_CLASS_SERIAL) {
+ if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes)/sizeof (VOID *)) {
+ // print out Firewire or USB inplace of Serial Bus controllers
+ Str = gPciSerialClassCodes[Hdr->ClassCode[1]];
+ }
+ }
+ } else {
+ Str = "Unknown device ";
+ }
+ AsciiPrint (" 0x%04x 0x%04x %a 0x%02x", Hdr->VendorId, Hdr->DeviceId, Str, Hdr->ClassCode[1]);
+ }
+ if (Seg != 0) {
+ // Only print Segment if it is non zero. If you only have one PCI segment it is
+ // redundent to print it out
+ AsciiPrint (" Seg:%d", Seg);
+ }
+ }
+ }
+ }
+ AsciiPrint ("\n");
+ } else {
+ // Dump specific PCI device
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
+ if (!EFI_ERROR (Status)) {
+ Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
+ if ((Bus == BusArg) && (Dev == DevArg) && (Func == FuncArg)) {
+ // Only print Segment if it is non zero. If you only have one PCI segment it is
+ // redundent to print it out
+ if (Seg != 0) {
+ AsciiPrint ("Seg:%d ", Seg);
+ }
+ AsciiPrint ("Bus:%d Dev:%d Func:%d ", Bus, Dev, Func);
+
+ Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), Header);
+ if (!EFI_ERROR (Status)) {
+ Hdr = &PciHeader.Bridge.Hdr;
+ if (IS_PCI_BRIDGE (&PciHeader.Bridge)) {
+ Bridge = &PciHeader.Bridge.Bridge;
+ AsciiPrint (
+ "PCI Bridge. Bus Primary %d Secondary %d Subordinate %d\n",
+ Bridge->PrimaryBus, Bridge->SecondaryBus, Bridge->SubordinateBus
+ );
+ AsciiPrint (" Bar 0: 0x%08x Bar 1: 0x%08x\n", Bridge->Bar[0], Bridge->Bar[1]);
+ } else {
+ Device = &PciHeader.Device.Device;
+ AsciiPrint (
+ "VendorId: 0x%04x DeviceId: 0x%04x SubSusVendorId: 0x%04x SubSysDeviceId: 0x%04x\n",
+ Hdr->VendorId, Hdr->DeviceId, Device->SubsystemVendorID, Device->SubsystemID
+ );
+ AsciiPrint (" Class Code: 0x%02x 0x%02x 0x%02x\n", Hdr->ClassCode[2], Hdr->ClassCode[1], Hdr->ClassCode[0]);
+ for (Count = 0; Count < 6; Count++) {
+ AsciiPrint (" Bar %d: 0x%08x\n", Count, Device->Bar[Count]);
+ }
+ }
+ }
+
+ AsciiPrint ("\n");
+ break;
+ }
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdPciDebugTemplate[] = {
+ "pci",
+ " [bus] [dev] [func]; Dump PCI",
+ NULL,
+ EblPciCmd
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwDebugTemplate[] =
+{
+ {
+ "md",
+ " [Addr] [Len] [1|2|4]; Memory Dump from Addr Len bytes",
+ NULL,
+ EblMdCmd
+ },
+ {
+ "mfill",
+ " Addr Len [data] [1|2|4]; Memory Fill Addr Len*(1|2|4) bytes of data(0)",
+ NULL,
+ EblMfillCmd
+ },
+};
+
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializemdHwDebugCmds (
+ VOID
+ )
+{
+ if (FeaturePcdGet (PcdEmbeddedHwDebugCmd)) {
+ EblAddCommands (mCmdHwDebugTemplate, sizeof (mCmdHwDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+ if (FeaturePcdGet (PcdEmbeddedPciDebugCmd)) {
+ EblAddCommands (mCmdPciDebugTemplate, sizeof (mCmdPciDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+}
+
diff --git a/EmbeddedPkg/Ebl/HwIoDebug.c b/EmbeddedPkg/Ebl/HwIoDebug.c
new file mode 100644
index 0000000..2d23e7c
--- /dev/null
+++ b/EmbeddedPkg/Ebl/HwIoDebug.c
@@ -0,0 +1,153 @@
+/** @file
+ Hardware IO based debug commands
+
+ 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.
+
+ Commands useful for debugging hardware. IO commands seperated out as not all
+ processor architectures support the IO command.
+
+**/
+
+#include "Ebl.h"
+
+
+
+/**
+ Read from IO space
+
+ Argv[0] - "ioread"
+ Argv[1] - Hex IO address
+ Argv[2] - IO Width [1|2|4] with a default of 1
+
+ ior 0x3f8 4 ;Do a 32-bit IO Read from 0x3f8
+ ior 0x3f8 1 ;Do a 8-bit IO Read from 0x3f8
+
+ @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
+EblIoReadCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN Width;
+ UINTN Port;
+ UINTN Data;
+
+ if (Argc < 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Port = AsciiStrHexToUintn (Argv[1]);
+ Width = (Argc > 2) ? AsciiStrHexToUintn (Argv[2]) : 1;
+
+ if (Width == 1) {
+ Data = IoRead8 (Port);
+ } else if (Width == 2) {
+ Data = IoRead16 (Port);
+ } else if (Width == 4) {
+ Data = IoRead32 (Port);
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AsciiPrint ("0x%04x = 0x%x", Port, Data);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Write to IO space
+
+ Argv[0] - "iowrite"
+ Argv[1] - Hex IO address
+ Argv[2] - Hex data to write
+ Argv[3] - IO Width [1|2|4] with a default of 1
+
+ iow 0x3f8 af 4 ;Do a 32-bit IO write of af to 0x3f8
+ iow 0x3f8 af ;Do an 8-bit IO write of af to 0x3f8
+
+ @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
+EblIoWriteCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ UINTN Width;
+ UINTN Port;
+ UINTN Data;
+
+ if (Argc < 3) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Port = AsciiStrHexToUintn (Argv[1]);
+ Data = AsciiStrHexToUintn (Argv[2]);
+ Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 1;
+
+ if (Width == 1) {
+ IoWrite8 (Port, (UINT8)Data);
+ } else if (Width == 2) {
+ IoWrite16 (Port, (UINT16)Data);
+ } else if (Width == 4) {
+ IoWrite32 (Port, (UINT32)Data);
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwIoDebugTemplate[] =
+{
+ {
+ "ioread",
+ " Port [1|2|4]; IO read of width[1] byte(s) from Port",
+ NULL,
+ EblIoReadCmd
+ },
+ {
+ "iowrite",
+ " Port Data [1|2|4]; IO write Data of width[1] byte(s) to Port",
+ NULL,
+ EblIoWriteCmd
+ }
+};
+
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializemdHwIoDebugCmds (
+ VOID
+ )
+{
+ if (FeaturePcdGet (PcdEmbeddedIoEnable)) {
+ EblAddCommands (mCmdHwIoDebugTemplate, sizeof (mCmdHwIoDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+}
+
diff --git a/EmbeddedPkg/Ebl/Main.c b/EmbeddedPkg/Ebl/Main.c
new file mode 100644
index 0000000..5d1a379
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Main.c
@@ -0,0 +1,616 @@
+/** @file
+ Basic command line parser for EBL (Embedded Boot Loader)
+
+ 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"
+
+// Globals for command history processing
+INTN mCmdHistoryEnd = -1;
+INTN mCmdHistoryStart = -1;
+INTN mCmdHistoryCurrent = -1;
+CHAR8 mCmdHistory[MAX_CMD_HISTORY][MAX_CMD_LINE];
+CHAR8 *mCmdBlank = "";
+
+// Globals to remember current screen geometry
+UINTN gScreenColumns;
+UINTN gScreenRows;
+
+// Global to turn on/off breaking commands with prompts before they scroll the screen
+BOOLEAN gPageBreak = TRUE;
+
+VOID
+RingBufferIncrement (
+ IN INTN *Value
+ )
+{
+ *Value = *Value + 1;
+
+ if (*Value >= MAX_CMD_HISTORY) {
+ *Value = 0;
+ }
+}
+
+VOID
+RingBufferDecrement (
+ IN INTN *Value
+ )
+{
+ *Value = *Value - 1;
+
+ if (*Value < 0) {
+ *Value = MAX_CMD_HISTORY - 1;
+ }
+}
+
+/**
+ Save this command in the circular history buffer. Older commands are
+ overwritten with newer commands.
+
+ @param Cmd Command line to archive the history of.
+
+ @return None
+
+**/
+VOID
+SetCmdHistory (
+ IN CHAR8 *Cmd
+ )
+{
+ // Don't bother adding empty commands to the list
+ if (AsciiStrLen(Cmd) != 0) {
+
+ // First entry
+ if (mCmdHistoryStart == -1) {
+ mCmdHistoryStart = 0;
+ mCmdHistoryEnd = 0;
+ } else {
+ // Record the new command at the next index
+ RingBufferIncrement(&mCmdHistoryStart);
+
+ // If the next index runs into the end index, shuffle end back by one
+ if (mCmdHistoryStart == mCmdHistoryEnd) {
+ RingBufferIncrement(&mCmdHistoryEnd);
+ }
+ }
+
+ // Copy the new command line into the ring buffer
+ AsciiStrnCpy(&mCmdHistory[mCmdHistoryStart][0], Cmd, MAX_CMD_LINE);
+ }
+
+ // Reset the command history for the next up arrow press
+ mCmdHistoryCurrent = mCmdHistoryStart;
+}
+
+
+/**
+ Retreave data from the Command History buffer. Direction maps into up arrow
+ an down arrow on the command line
+
+ @param Direction Command forward or back
+
+ @return The Command history based on the Direction
+
+**/
+CHAR8 *
+GetCmdHistory (
+ IN UINT16 Direction
+ )
+{
+ CHAR8 *HistoricalCommand = NULL;
+
+ // No history yet?
+ if (mCmdHistoryCurrent == -1) {
+ HistoricalCommand = mCmdBlank;
+ goto Exit;
+ }
+
+ if (Direction == SCAN_UP) {
+ HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
+
+ // if we just echoed the last command, hang out there, don't wrap around
+ if (mCmdHistoryCurrent == mCmdHistoryEnd) {
+ goto Exit;
+ }
+
+ // otherwise, back up by one
+ RingBufferDecrement(&mCmdHistoryCurrent);
+
+ } else if (Direction == SCAN_DOWN) {
+
+ // if we last echoed the start command, put a blank prompt out
+ if (mCmdHistoryCurrent == mCmdHistoryStart) {
+ HistoricalCommand = mCmdBlank;
+ goto Exit;
+ }
+
+ // otherwise increment the current pointer and return that command
+ RingBufferIncrement(&mCmdHistoryCurrent);
+ RingBufferIncrement(&mCmdHistoryCurrent);
+
+ HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
+ RingBufferDecrement(&mCmdHistoryCurrent);
+ }
+
+Exit:
+ return HistoricalCommand;
+}
+
+
+/**
+ Parse the CmdLine and break it up into Argc (arg count) and Argv (array of
+ pointers to each argument). The Cmd buffer is altered and seperators are
+ converted to string terminators. This allows Argv to point into CmdLine.
+ A CmdLine can support multiple commands. The next command in the command line
+ is returned if it exists.
+
+ @param CmdLine String to parse for a set of commands
+ @param Argc Returns the number of arguments in the CmdLine current command
+ @param Argv Argc pointers to each string in CmdLine
+
+ @return Next Command in the command line or NULL if non exists
+**/
+CHAR8 *
+ParseArguments (
+ IN CHAR8 *CmdLine,
+ OUT UINTN *Argc,
+ OUT CHAR8 **Argv
+ )
+{
+ UINTN Arg;
+ CHAR8 *Char;
+ BOOLEAN LookingForArg;
+ BOOLEAN InQuote;
+
+ *Argc = 0;
+ if (AsciiStrLen (CmdLine) == 0) {
+ return NULL;
+ }
+
+ // Walk a single command line. A CMD_SEPERATOR allows mult commands on a single line
+ InQuote = FALSE;
+ LookingForArg = TRUE;
+ for (Char = CmdLine, Arg = 0; *Char != '\0'; Char++) {
+ if (!InQuote && *Char == CMD_SEPERATOR) {
+ break;
+ }
+
+ // Perform any text coversion here
+ if (*Char == '\t') {
+ // TAB to space
+ *Char = ' ';
+ }
+
+ if (LookingForArg) {
+ // Look for the beging of an Argv[] entry
+ if (*Char == '"') {
+ Argv[Arg++] = ++Char;
+ LookingForArg = FALSE;
+ InQuote = TRUE;
+ } else if (*Char != ' ') {
+ Argv[Arg++] = Char;
+ LookingForArg = FALSE;
+ }
+ } else {
+ // Looking for the terminator of an Argv[] entry
+ if ((InQuote && (*Char == '"')) || (!InQuote && (*Char == ' '))) {
+ *Char = '\0';
+ LookingForArg = TRUE;
+ }
+ }
+ }
+
+ *Argc = Arg;
+
+ if (*Char == CMD_SEPERATOR) {
+ // Replace the command delimeter with null and return pointer to next command line
+ *Char = '\0';
+ return ++Char;
+ }
+
+ return NULL;
+}
+
+
+/**
+ Return a keypress or optionally timeout if a timeout value was passed in.
+ An optional callback funciton is called evey second when waiting for a
+ timeout.
+
+ @param Key EFI Key information returned
+ @param TimeoutInSec Number of seconds to wait to timeout
+ @param CallBack Callback called every second during the timeout wait
+
+ @return EFI_SUCCESS Key was returned
+ @return EFI_TIMEOUT If the TimoutInSec expired
+
+**/
+EFI_STATUS
+EblGetCharKey (
+ IN OUT EFI_INPUT_KEY *Key,
+ IN UINTN TimeoutInSec,
+ IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN WaitCount;
+ UINTN WaitIndex;
+ EFI_EVENT WaitList[2];
+
+ WaitCount = 1;
+ WaitList[0] = gST->ConIn->WaitForKey;
+ if (TimeoutInSec != 0) {
+ // Create a time event for 1 sec duration if we have a timeout
+ gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[1]);
+ gBS->SetTimer (WaitList[1], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
+ WaitCount++;
+ }
+
+ for (;;) {
+ Status = gBS->WaitForEvent (WaitCount, WaitList, &WaitIndex);
+ ASSERT_EFI_ERROR (Status);
+
+ switch (WaitIndex) {
+ case 0:
+ // Key event signaled
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
+ if (!EFI_ERROR (Status)) {
+ if (WaitCount == 2) {
+ gBS->CloseEvent (WaitList[1]);
+ }
+ return EFI_SUCCESS;
+ }
+ break;
+
+ case 1:
+ // Periodic 1 sec timer signaled
+ TimeoutInSec--;
+ if (CallBack != NULL) {
+ // Call the users callback function if registered
+ CallBack (TimeoutInSec);
+ }
+ if (TimeoutInSec == 0) {
+ gBS->CloseEvent (WaitList[1]);
+ return EFI_TIMEOUT;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ }
+}
+
+
+/**
+ This routine is used prevent command output data from scrolling off the end
+ of the screen. The global gPageBreak is used to turn on or off this feature.
+ If the CurrentRow is near the end of the screen pause and print out a prompt
+ If the use hits Q to quit return TRUE else for any other key return FALSE.
+ PrefixNewline is used to figure out if a newline is needed before the prompt
+ string. This depends on the last print done before calling this function.
+ CurrentRow is updated by one on a call or set back to zero if a prompt is
+ needed.
+
+ @param CurrentRow Used to figure out if its the end of the page and updated
+ @param PrefixNewline Did previous print issue a newline
+
+ @return TRUE if Q was hit to quit, FALSE in all other cases.
+
+**/
+BOOLEAN
+EblAnyKeyToContinueQtoQuit (
+ IN UINTN *CurrentRow,
+ IN BOOLEAN PrefixNewline
+ )
+{
+ EFI_INPUT_KEY InputKey;
+
+ if (!gPageBreak) {
+ // global disable for this feature
+ return FALSE;
+ }
+
+ if (*CurrentRow >= (gScreenRows - 2)) {
+ if (PrefixNewline) {
+ AsciiPrint ("\n");
+ }
+ AsciiPrint ("Any key to continue (Q to quit): ");
+ EblGetCharKey (&InputKey, 0, NULL);
+ AsciiPrint ("\n");
+
+ // Time to promt to stop the screen. We have to leave space for the prompt string
+ *CurrentRow = 0;
+ if (InputKey.UnicodeChar == 'Q' || InputKey.UnicodeChar == 'q') {
+ return TRUE;
+ }
+ } else {
+ *CurrentRow += 1;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Set the text color of the EFI Console. If a zero is passed in reset to
+ default text/background color.
+
+ @param Attribute For text and background color
+
+**/
+VOID
+EblSetTextColor (
+ UINTN Attribute
+ )
+{
+ if (Attribute == 0) {
+ // Set the text color back to default
+ Attribute = (UINTN)PcdGet32 (PcdEmbeddedDefaultTextColor);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, Attribute);
+}
+
+
+/**
+ Collect the keyboard input for a cmd line. Carage Return, New Line, or ESC
+ terminates the command line. You can edit the command line via left arrow,
+ delete and backspace and they all back up and erase the command line.
+ No edit of commnad line is possible without deletion at this time!
+ The up arrow and down arrow fill Cmd with information from the history
+ buffer.
+
+ @param Cmd Command line to return
+ @param CmdMaxSize Maximum size of Cmd
+
+ @return The Status of EblGetCharKey()
+
+**/
+EFI_STATUS
+GetCmd (
+ IN OUT CHAR8 *Cmd,
+ IN UINTN CmdMaxSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+ CHAR8 Char;
+ CHAR8 *History;
+ EFI_INPUT_KEY Key;
+
+ for (Index = 0; Index < CmdMaxSize - 1;) {
+ Status = EblGetCharKey (&Key, 0, NULL);
+ if (EFI_ERROR (Status)) {
+ Cmd[Index] = '\0';
+ AsciiPrint ("\n");
+ return Status;
+ }
+
+ Char = (CHAR8)Key.UnicodeChar;
+ if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
+ Cmd[Index] = '\0';
+ if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
+ AsciiPrint ("\n\r");
+ }
+ return EFI_SUCCESS;
+ } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
+ if (Index != 0) {
+ Index--;
+ //
+ // Update the display
+ //
+ AsciiPrint ("\b \b");
+ }
+ } else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) {
+ History = GetCmdHistory (Key.ScanCode);
+ //
+ // Clear display line
+ //
+ for (Index2 = 0; Index2 < Index; Index2++) {
+ AsciiPrint ("\b \b");
+ }
+ AsciiPrint (History);
+ Index = AsciiStrLen (History);
+ AsciiStrnCpy (Cmd, History, CmdMaxSize);
+ } else {
+ Cmd[Index++] = Char;
+ if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
+ AsciiPrint ("%c", Char);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Print the boot up banner for the EBL.
+**/
+VOID
+EblPrintStartupBanner (
+ VOID
+ )
+{
+ AsciiPrint ("Embedded Boot Loader (");
+ EblSetTextColor (EFI_YELLOW);
+ AsciiPrint ("EBL");
+ EblSetTextColor (0);
+ AsciiPrint (") prototype. Built at %a on %a\n",__TIME__, __DATE__);
+ AsciiPrint ("THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN 'AS IS' BASIS,\nWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\n");
+ AsciiPrint ("Please send feedback to dev@edk2.tianocore.org\n");
+}
+
+
+/**
+ Print the prompt for the EBL.
+**/
+VOID
+EblPrompt (
+ VOID
+ )
+{
+ EblSetTextColor (EFI_YELLOW);
+ AsciiPrint ((CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt));
+ EblSetTextColor (0);
+ AsciiPrint ("%a", ">");
+}
+
+
+
+/**
+ Parse a command line and execute the commands. The ; seperator allows
+ multiple commands for each command line. Stop processing if one of the
+ commands returns an error.
+
+ @param CmdLine Command Line to process.
+ @param MaxCmdLineSize MaxSize of the Command line
+
+ @return EFI status of the Command
+
+**/
+EFI_STATUS
+ProcessCmdLine (
+ IN CHAR8 *CmdLine,
+ IN UINTN MaxCmdLineSize
+ )
+{
+ EFI_STATUS Status;
+ EBL_COMMAND_TABLE *Cmd;
+ CHAR8 *Ptr;
+ UINTN Argc;
+ CHAR8 *Argv[MAX_ARGS];
+
+ // Parse the command line. The loop processes commands seperated by ;
+ for (Ptr = CmdLine, Status = EFI_SUCCESS; Ptr != NULL;) {
+ Ptr = ParseArguments (Ptr, &Argc, Argv);
+ if (Argc != 0) {
+ Cmd = EblGetCommand (Argv[0]);
+ if (Cmd != NULL) {
+ // Execute the Command!
+ Status = Cmd->Command (Argc, Argv);
+ if (Status == EFI_ABORTED) {
+ // exit command so lets exit
+ break;
+ } else if (Status == EFI_TIMEOUT) {
+ // pause command got imput so don't process any more cmd on this cmd line
+ break;
+ } else if (EFI_ERROR (Status)) {
+ AsciiPrint ("%a returned %r error\n", Cmd->Name, Status);
+ // if any command fails stop processing CmdLine
+ break;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Embedded Boot Loader (EBL) - A simple EFI command line application for embedded
+ devices. PcdEmbeddedAutomaticBootCommand is a complied in commnad line that
+ gets executed automatically. The ; seperator allows multiple commands
+ for each command line.
+
+ @param ImageHandle EFI ImageHandle for this application.
+ @param SystemTable EFI system table
+
+ @return EFI status of the applicaiton
+
+**/
+EFI_STATUS
+EFIAPI
+EdkBootLoaderEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 CmdLine[MAX_CMD_LINE];
+ CHAR16 *CommandLineVariable = NULL;
+ CHAR16 *CommandLineVariableName = L"default-cmdline";
+ UINTN CommandLineVariableSize = 0;
+ EFI_GUID VendorGuid;
+
+ // Initialize tables of commnads
+ EblInitializeCmdTable ();
+ EblInitializeDeviceCmd ();
+ EblInitializemdHwDebugCmds ();
+ EblInitializemdHwIoDebugCmds ();
+ EblInitializeDirCmd ();
+ EblInitializeHobCmd ();
+ EblInitializeScriptCmd ();
+ EblInitializeExternalCmd ();
+ EblInitializeNetworkCmd();
+
+ if (FeaturePcdGet (PcdEmbeddedMacBoot)) {
+ // A MAC will boot in graphics mode, so turn it back to text here
+ // This protocol was removed from edk2. It is only an edk thing. We need to make our own copy.
+ // DisableQuietBoot ();
+
+ // Enable the biggest output screen size possible
+ gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1);
+
+ // Disable the 5 minute EFI watchdog time so we don't get automatically reset
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ }
+
+ // Save current screen mode
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows);
+
+ EblPrintStartupBanner ();
+
+ // Parse command line and handle commands seperated by ;
+ // The loop prints the prompt gets user input and saves history
+
+ // Look for a variable with a default command line, otherwise use the Pcd
+ ZeroMem(&VendorGuid, sizeof(EFI_GUID));
+
+ Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ CommandLineVariable = AllocatePool(CommandLineVariableSize);
+
+ Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
+ if (!EFI_ERROR(Status)) {
+ UnicodeStrToAsciiStr(CommandLineVariable, CmdLine);
+ }
+
+ FreePool(CommandLineVariable);
+ }
+
+ if (EFI_ERROR(Status)) {
+ AsciiStrCpy (CmdLine, (CHAR8 *)PcdGetPtr (PcdEmbeddedAutomaticBootCommand));
+ }
+
+ for (;;) {
+ Status = ProcessCmdLine (CmdLine, MAX_CMD_LINE);
+ if (Status == EFI_ABORTED) {
+ // if a command returns EFI_ABORTED then exit the EBL
+ EblShutdownExternalCmdTable ();
+ return EFI_SUCCESS;
+ }
+
+ // get the command line from the user
+ EblPrompt ();
+ GetCmd (CmdLine, MAX_CMD_LINE);
+ SetCmdHistory (CmdLine);
+ }
+}
+
+
diff --git a/EmbeddedPkg/Ebl/Network.c b/EmbeddedPkg/Ebl/Network.c
new file mode 100644
index 0000000..c566dda
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Network.c
@@ -0,0 +1,104 @@
+/** @file
+ EBL commands for Network Devices
+
+ 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_STATUS
+ParseIp (
+ IN CHAR8 *String,
+ OUT EFI_IP_ADDRESS *Address
+ )
+{
+ Address->v4.Addr[0] = AsciiStrDecimalToUintn(String);
+ String = AsciiStrStr(String, ".") + 1;
+ Address->v4.Addr[1] = AsciiStrDecimalToUintn(String);
+ String = AsciiStrStr(String, ".") + 1;
+ Address->v4.Addr[2] = AsciiStrDecimalToUintn(String);
+ String = AsciiStrStr(String, ".") + 1;
+ Address->v4.Addr[3] = AsciiStrDecimalToUintn(String);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EblIpCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status = EFI_INVALID_PARAMETER;
+ EFI_MAC_ADDRESS Mac;
+ EFI_IP_ADDRESS Ip;
+
+ if (Argc == 1) {
+ // Get current IP/MAC
+
+ // Get current MAC address
+ Status = EblGetCurrentMacAddress (&Mac);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ AsciiPrint ("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", Mac.Addr[0], Mac.Addr[1], Mac.Addr[2], Mac.Addr[3], Mac.Addr[4], Mac.Addr[5]);
+
+ // Get current IP address
+ Status = EblGetCurrentIpAddress (&Ip);
+ if (EFI_ERROR(Status)) {
+ AsciiPrint("IP Address is not configured.\n");
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ AsciiPrint("IP Address: %d.%d.%d.%d\n", Ip.v4.Addr[0], Ip.v4.Addr[1],Ip.v4.Addr[2], Ip.v4.Addr[3]);
+
+ } else if ((Argv[1][0] == 'r') && (Argc == 2)) {
+ // Get new address via dhcp
+ Status = EblPerformDHCP (TRUE);
+ } else if ((Argv[1][0] == 's') && (Argc == 3)) {
+ // Set static IP
+ Status = ParseIp (Argv[2], &Ip);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = EblSetStationIp (&Ip, NULL);
+ }
+
+Exit:
+ return Status;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdNetworkTemplate[] =
+{
+ {
+ "ip",
+ " ; print current ip address\n\r [r]; request DHCP address\n\r [s] ipaddr; set static IP address",
+ NULL,
+ EblIpCmd
+ }
+};
+
+
+/**
+ Initialize the commands in this in this file
+**/
+VOID
+EblInitializeNetworkCmd (
+ VOID
+ )
+{
+ EblAddCommands (mCmdNetworkTemplate, sizeof (mCmdNetworkTemplate)/sizeof (EBL_COMMAND_TABLE));
+}
+
diff --git a/EmbeddedPkg/Ebl/Script.c b/EmbeddedPkg/Ebl/Script.c
new file mode 100644
index 0000000..2229005
--- /dev/null
+++ b/EmbeddedPkg/Ebl/Script.c
@@ -0,0 +1,126 @@
+/** @file
+ Script command allows the execution of commands from a text file
+
+ 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.
+
+ Module Name: EfiDevice.c
+
+**/
+
+#include "Ebl.h"
+
+
+/**
+ Execute the passed in file like a series of commands. The ; can be used on
+ a single line to indicate multiple commands per line. The Ascii text file
+ can contain any number of lines. The following line termination forms are
+ supported:
+ LF : Unix, Mac OS X*, BeOS
+ CR+LF: MS-DOS*, Microsoft Windows*
+ CR : Commodore, Apple II, and realy Mac OS
+ LF+CR: for simplicity and completeness
+
+ Argv[0] - "script"
+ Argv[1] - Device Name:path for the file to load
+
+ script fv1:\script.txt
+
+ @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
+EblScriptCmd (
+ IN UINTN Argc,
+ IN CHAR8 **Argv
+ )
+{
+ EFI_STATUS Status;
+ EFI_OPEN_FILE *File;
+ VOID *Address;
+ UINTN Size;
+ CHAR8 *Ptr;
+ CHAR8 *ScanPtr;
+ UINTN CmdLineSize;
+
+
+
+ if (Argc < 2) {
+ // file name 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;
+ }
+
+ Status = EfiReadAllocatePool (File, &Address, &Size);
+ if (!EFI_ERROR (Status)) {
+ // Loop through each line in the text file
+ for (Ptr = (CHAR8 *)Address; (Ptr < (((CHAR8 *)Address) + Size)) && !EFI_ERROR (Status); Ptr += CmdLineSize) {
+ for (CmdLineSize = 0, ScanPtr = Ptr; ; CmdLineSize++, ScanPtr++) {
+ // look for the end of the line
+ if ((*ScanPtr == EBL_CR) || (*ScanPtr == EBL_LF)) {
+ // convert to NULL as this is what input routine would do
+ *ScanPtr = 0;
+ if ((*(ScanPtr + 1) == EBL_CR) || (*(ScanPtr + 1) == EBL_LF)) {
+ // if its a set get the 2nd EOL char
+ CmdLineSize++;
+ *(ScanPtr + 1) = 0;
+ }
+ CmdLineSize++;
+ break;
+ }
+
+ }
+
+ Status = ProcessCmdLine (Ptr, CmdLineSize);
+ }
+
+ FreePool (Address);
+ }
+
+ EfiClose (File);
+ return Status;
+}
+
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mScriptTemplate[] = {
+ {
+ "script",
+ " device:path; load an ascii file and execute it like commands",
+ NULL,
+ EblScriptCmd
+ }
+};
+
+
+/**
+ Initialize the commands in this in this file
+**/
+
+VOID
+EblInitializeScriptCmd (
+ VOID
+ )
+{
+ if (FeaturePcdGet (PcdEmbeddedScriptCmd)) {
+ EblAddCommands (mScriptTemplate, sizeof (mScriptTemplate)/sizeof (EBL_COMMAND_TABLE));
+ }
+}
+