From 2ef2b01e07c02db339f34004445734a2dbdd80e1 Mon Sep 17 00:00:00 2001 From: AJFISH Date: Sun, 6 Dec 2009 01:57:05 +0000 Subject: 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 --- EmbeddedPkg/Ebl/CmdTemplate.c | 65 +++ EmbeddedPkg/Ebl/Command.c | 978 ++++++++++++++++++++++++++++++++++++++++++ EmbeddedPkg/Ebl/Dir.c | 305 +++++++++++++ EmbeddedPkg/Ebl/Ebl.h | 194 +++++++++ EmbeddedPkg/Ebl/Ebl.inf | 110 +++++ EmbeddedPkg/Ebl/EfiDevice.c | 969 +++++++++++++++++++++++++++++++++++++++++ EmbeddedPkg/Ebl/Hob.c | 232 ++++++++++ EmbeddedPkg/Ebl/HwDebug.c | 342 +++++++++++++++ EmbeddedPkg/Ebl/HwIoDebug.c | 153 +++++++ EmbeddedPkg/Ebl/Main.c | 616 ++++++++++++++++++++++++++ EmbeddedPkg/Ebl/Network.c | 104 +++++ EmbeddedPkg/Ebl/Script.c | 126 ++++++ 12 files changed, 4194 insertions(+) create mode 100644 EmbeddedPkg/Ebl/CmdTemplate.c create mode 100644 EmbeddedPkg/Ebl/Command.c create mode 100644 EmbeddedPkg/Ebl/Dir.c create mode 100644 EmbeddedPkg/Ebl/Ebl.h create mode 100644 EmbeddedPkg/Ebl/Ebl.inf create mode 100644 EmbeddedPkg/Ebl/EfiDevice.c create mode 100644 EmbeddedPkg/Ebl/Hob.c create mode 100644 EmbeddedPkg/Ebl/HwDebug.c create mode 100644 EmbeddedPkg/Ebl/HwIoDebug.c create mode 100644 EmbeddedPkg/Ebl/Main.c create mode 100644 EmbeddedPkg/Ebl/Network.c create mode 100644 EmbeddedPkg/Ebl/Script.c (limited to 'EmbeddedPkg/Ebl') 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
+ 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
+ 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 +#include + +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
+ 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 (" %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
+ 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. + +**/ + +#ifndef __EBL_H__ +#define __EBL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// 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
+ 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
+ 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 + +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
+ 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
+ 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
+ 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
+ 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)); + } +} + -- cgit v1.1