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
This commit is contained in:
AJFISH
2009-12-06 01:57:05 +00:00
parent f7753a96ba
commit 2ef2b01e07
294 changed files with 47954 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
/** @file
%CommandName% for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: CmdTemplate.c
Search/Replace %CommandName% with the name of your new command
**/
#include "Ebl.h"
/**
Fill Me In
Argv[0] - "%CommandName%"
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
Ebl%CommandName%Cmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
return EFI_SUCCESS;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmd%CommandName%Template[] =
{
{
"%CommandName%",
" [show args] ; explain args and command",
NULL,
Ebl%CommandName%Cmd
}
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitialize%CommandName%Cmd (
VOID
)
{
EblAddCommands (mCmd%CommandName%Template, sizeof (mCmd%CommandName%Template)/sizeof (EBL_COMMAND_TABLE));
}

978
EmbeddedPkg/Ebl/Command.c Normal file
View File

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

305
EmbeddedPkg/Ebl/Dir.c Normal file
View File

@@ -0,0 +1,305 @@
/** @file
Dir for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: CmdTemplate.c
Search/Replace Dir with the name of your new command
**/
#include "Ebl.h"
GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *gFvFileType[] = {
"All",
"Raw",
"Freeform",
"SEC",
"PeiCore",
"DxeCore",
"PEIM",
"Driver",
"Combo Driver",
"Application",
"NULL",
"FV"
};
/**
Perform a dir on a device. The device must support Simple File System Protocol
or the FV protocol.
Argv[0] - "dir"
Argv[1] - Device Name:path. Path is optional
Argv[2] - Optional filename to match on. A leading * means match substring
Argv[3] - Optional FV file type
dir fs1:\efi ; perform a dir on fs1: device in the efi directory
dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but
only print out files that contain the string *.efi
dir fv1:\ ; perform a dir on fv1: device in the efi directory
NOTE: fv devices do not contian subdirs
dir fv1:\ * PEIM ; will match all files of type SEC
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblDirCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
EFI_STATUS Status;
EFI_OPEN_FILE *File;
EFI_FILE_INFO *DirInfo;
UINTN ReadSize;
UINTN CurrentRow;
CHAR16 *MatchSubString;
EFI_STATUS GetNextFileStatus;
UINTN Key;
EFI_FV_FILETYPE SearchType;
EFI_FV_FILETYPE Type;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINTN Size;
EFI_GUID NameGuid;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
UINT32 AuthenticationStatus;
VOID *Section;
UINTN SectionSize;
EFI_FV_FILETYPE Index;
UINTN Length;
UINTN BestMatchCount;
CHAR16 UnicodeFileName[MAX_CMD_LINE];
if (Argc <= 1) {
// CWD not currently supported
return EFI_SUCCESS;
}
File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
if (File == NULL) {
return EFI_SUCCESS;
}
if (File->Type == EfiOpenFirmwareVolume) {
// FV Dir
SearchType = EFI_FV_FILETYPE_ALL;
UnicodeFileName[0] = '\0';
MatchSubString = &UnicodeFileName[0];
if (Argc > 2) {
AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
if (UnicodeFileName[0] == '*') {
// Handle *Name substring matching
MatchSubString = &UnicodeFileName[1];
}
// Handle file type matchs
if (Argc > 3) {
// match a specific file type, always last argument
Length = AsciiStrLen (Argv[3]);
for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) {
if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) {
// exact match
SearchType = Index;
break;
}
if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) {
// partial match, so keep looking to make sure there is only one partial match
BestMatchCount++;
SearchType = Index;
}
}
if (BestMatchCount > 1) {
SearchType = EFI_FV_FILETYPE_ALL;
}
}
}
Fv = File->Fv;
Key = 0;
CurrentRow = 0;
do {
Type = SearchType;
GetNextFileStatus = Fv->GetNextFile (
Fv,
&Key,
&Type,
&NameGuid,
&Attributes,
&Size
);
if (!EFI_ERROR (GetNextFileStatus)) {
// Calculate size of entire file
Section = NULL;
Size = 0;
Status = Fv->ReadFile (
Fv,
&NameGuid,
Section,
&Size,
&Type,
&Attributes,
&AuthenticationStatus
);
if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) {
// EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid
Size = 0;
}
// read the UI seciton to do a name match.
Section = NULL;
Status = Fv->ReadSection (
Fv,
&NameGuid,
EFI_SECTION_USER_INTERFACE,
0,
&Section,
&SectionSize,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
if (StrStr (Section, MatchSubString) != NULL) {
AsciiPrint (" %g %s %a %,d\n", &NameGuid, Section, gFvFileType[Type], Size);
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
break;
}
}
FreePool (Section);
} else {
if (*MatchSubString == '\0') {
AsciiPrint (" %g %a %,d\n", &NameGuid, gFvFileType[Type], Size);
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
break;
}
}
}
}
} while (!EFI_ERROR (GetNextFileStatus));
} else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) {
// Simple File System DIR
if (File->FsFileInfo == NULL) {
return EFI_SUCCESS;
}
if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
return EFI_SUCCESS;
}
// Handle *Name substring matching
MatchSubString = NULL;
UnicodeFileName[0] = '\0';
if (Argc > 2) {
AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
if (UnicodeFileName[0] == '*') {
MatchSubString = &UnicodeFileName[1];
}
}
File->FsFileHandle->SetPosition (File->FsFileHandle, 0);
for (CurrentRow = 0;;) {
// First read gets the size
DirInfo = NULL;
ReadSize = 0;
Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
if (Status == EFI_BUFFER_TOO_SMALL) {
// Allocate the buffer for the real read
DirInfo = AllocatePool (ReadSize);
if (DirInfo == NULL) {
goto Done;
}
// Read the data
Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
if ((EFI_ERROR (Status)) || (ReadSize == 0)) {
break;
}
} else {
break;
}
if (MatchSubString != NULL) {
if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) {
// does not match *name argument, so skip
continue;
}
} else if (UnicodeFileName[0] != '\0') {
// is not an exact match for name argument, so skip
if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) {
continue;
}
}
if (DirInfo->Attribute & EFI_FILE_DIRECTORY) {
AsciiPrint (" <DIR> %s\n", &DirInfo->FileName[0]);
} else {
AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]);
}
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
break;
}
FreePool (DirInfo);
}
Done:
if (DirInfo != NULL) {
FreePool (DirInfo);
}
}
EfiClose (File);
return EFI_SUCCESS;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =
{
{
"dir",
" dirdev [*match]; directory listing of dirdev. opt match a substring",
NULL,
EblDirCmd
}
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitializeDirCmd (
VOID
)
{
if (FeaturePcdGet (PcdEmbeddedDirCmd)) {
EblAddCommands (mCmdDirTemplate, sizeof (mCmdDirTemplate)/sizeof (EBL_COMMAND_TABLE));
}
}

194
EmbeddedPkg/Ebl/Ebl.h Normal file
View File

@@ -0,0 +1,194 @@
/** @file
Include flie for basic command line parser for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EBL_H__
#define __EBL_H__
#include <PiDxe.h>
#include <Protocol/BlockIo.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/LoadFile.h>
#include <Protocol/FirmwareVolumeBlock.h>
#include <Protocol/PxeBaseCode.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/EblAddCommand.h>
#include <Protocol/PciIo.h>
#include <Protocol/DevicePath.h>
#include <Guid/FileInfo.h>
#include <Guid/DxeServices.h>
#include <Guid/MemoryTypeInformation.h>
#include <Guid/MemoryAllocationHob.h>
#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DevicePathLib.h>
#include <Library/PrintLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/EfiFileLib.h>
#include <Library/HobLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Library/EblCmdLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiLib.h>
#include <Library/EblNetworkLib.h>
#include <IndustryStandard/Pci.h>
//
// Prompt for the command line
//
#define CMD_SEPERATOR ';'
#define EBL_MAX_COMMAND_COUNT 0x100
#define MAX_CMD_HISTORY 16
#define MAX_CMD_LINE 256
#define MAX_ARGS 32
#define EBL_CR 0x0a
#define EBL_LF 0x0d
#define EFI_SET_TIMER_TO_SECOND 10000000
EBL_COMMAND_TABLE *
EblGetCommand (
IN CHAR8 *CommandName
);
EFI_STATUS
EblPathToDevice (
IN CHAR8 *Path,
OUT EFI_HANDLE *DeviceHandle,
OUT EFI_DEVICE_PATH_PROTOCOL **PathDevicePath,
OUT VOID **Buffer,
OUT UINTN *BufferSize
);
BOOLEAN
EblAnyKeyToContinueQtoQuit (
IN UINTN *CurrentRow,
IN BOOLEAN PrefixNewline
);
VOID
EblUpdateDeviceLists (
VOID
);
VOID
EblInitializeCmdTable (
VOID
);
VOID
EblShutdownExternalCmdTable (
VOID
);
VOID
EblSetTextColor (
UINTN Attribute
);
EFI_STATUS
EblGetCharKey (
IN OUT EFI_INPUT_KEY *Key,
IN UINTN TimoutInSec,
IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
);
// BugBug: Move me to a library
INTN
EFIAPI
AsciiStrniCmp (
IN CONST CHAR8 *FirstString,
IN CONST CHAR8 *SecondString,
IN UINTN Length
);
VOID
EblInitializeDeviceCmd (
VOID
);
VOID
EblInitializemdHwDebugCmds (
VOID
);
VOID
EblInitializeDirCmd (
VOID
);
VOID
EblInitializeHobCmd (
VOID
);
VOID
EblInitializemdHwIoDebugCmds (
VOID
);
VOID
EblInitializeScriptCmd (
VOID
);
VOID
EblInitializeNetworkCmd (
VOID
);
CHAR8 *
ParseArguments (
IN CHAR8 *CmdLine,
OUT UINTN *Argc,
OUT CHAR8 **Argv
);
EFI_STATUS
ProcessCmdLine (
IN CHAR8 *CmdLine,
IN UINTN MaxCmdLineSize
);
EFI_STATUS
OutputData (
IN UINT8 *Address,
IN UINTN Length,
IN UINTN Width,
IN UINTN Offset
);
extern UINTN gScreenColumns;
extern UINTN gScreenRows;
extern BOOLEAN gPageBreak;
extern CHAR8 *gMemMapType[];
#endif

110
EmbeddedPkg/Ebl/Ebl.inf Normal file
View File

@@ -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

969
EmbeddedPkg/Ebl/EfiDevice.c Normal file
View File

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

232
EmbeddedPkg/Ebl/Hob.c Normal file
View File

@@ -0,0 +1,232 @@
/** @file
Hob command for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: Hob.c
Search/Replace Dir with the name of your new command
Boot Mode:
==========
BOOT_WITH_FULL_CONFIGURATION 0x00
BOOT_WITH_MINIMAL_CONFIGURATION 0x01
BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02
BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03
BOOT_WITH_DEFAULT_SETTINGS 0x04
BOOT_ON_S4_RESUME 0x05
BOOT_ON_S5_RESUME 0x06
BOOT_ON_S2_RESUME 0x10
BOOT_ON_S3_RESUME 0x11
BOOT_ON_FLASH_UPDATE 0x12
BOOT_IN_RECOVERY_MODE 0x20
BOOT_IN_RECOVERY_MODE_MASK 0x40
BOOT_SPECIAL_MASK 0x80
Mem Alloc HOB Type:
===================
typedef enum {
EfiReservedMemoryType = 0x00
EfiLoaderCode = 0x01
EfiLoaderData = 0x02
EfiBootServicesCode = 0x03
EfiBootServicesData = 0x04
EfiRuntimeServicesCode = 0x05
EfiRuntimeServicesData = 0x06
EfiConventionalMemory = 0x07
EfiUnusableMemory = 0x08
EfiACPIReclaimMemory = 0x09
EfiACPIMemoryNVS = 0x0a
EfiMemoryMappedIO = 0x0b
EfiMemoryMappedIOPortSpace = 0x0c
EfiPalCode = 0x0d
EfiMaxMemoryType = 0x0e
} EFI_MEMORY_TYPE;
Resource Hob Tye:
=================
EFI_RESOURCE_SYSTEM_MEMORY 0
EFI_RESOURCE_MEMORY_MAPPED_IO 1
EFI_RESOURCE_IO 2
EFI_RESOURCE_FIRMWARE_DEVICE 3
EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 4
EFI_RESOURCE_MEMORY_RESERVED 5
EFI_RESOURCE_IO_RESERVED 6
EFI_RESOURCE_MAX_MEMORY_TYPE 7
Resource Hob Attribute (last thing printed):
============================================
EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
**/
#include "Ebl.h"
// BugBug: Autogen does not allow this to be included currently
//#include <EdkModulePkg/Include/EdkDxe.h>
GLOBAL_REMOVE_IF_UNREFERENCED char *mHobResourceType[] = {
"Memory ",
"MMIO ",
"IO ",
"Firmware ",
"MMIO Port ",
"Reserved ",
"IO Reserved",
"Illegal "
};
/**
Dump out the HOBs in the system. HOBs are defined in the PI specificaiton
and they are used to hand off information from PEI to DXE.
Argv[0] - "hob"
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblHobCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
UINTN CurrentRow;
EFI_PEI_HOB_POINTERS Hob;
EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
UINTN Index;
CurrentRow = 0;
for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
AsciiPrint ("PHIT HOB Ver %x Boot Mode %02x Top %lx Bottom %lx\n",
Hob.HandoffInformationTable->Version,
Hob.HandoffInformationTable->BootMode,
Hob.HandoffInformationTable->EfiMemoryTop,
Hob.HandoffInformationTable->EfiMemoryBottom
);
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
return EFI_SUCCESS;
}
AsciiPrint (" Free Top %lx Free Bottom %lx End Of HOB %lx\n",
Hob.HandoffInformationTable->EfiFreeMemoryTop,
Hob.HandoffInformationTable->EfiFreeMemoryBottom,
Hob.HandoffInformationTable->EfiEndOfHobList
);
} else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
// mod(%) on array index is just to prevent buffer overrun
AsciiPrint ("Mem Alloc HOB %a %g %08lx:%lx\n",
(Hob.MemoryAllocation->AllocDescriptor.MemoryType < EfiMaxMemoryType) ? gMemMapType[Hob.MemoryAllocation->AllocDescriptor.MemoryType] : "ILLEGAL TYPE",
&Hob.MemoryAllocation->AllocDescriptor.Name,
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
Hob.MemoryAllocation->AllocDescriptor.MemoryLength
);
if (CompareGuid (&gEfiHobMemoryAllocModuleGuid, &Hob.MemoryAllocation->AllocDescriptor.Name)) {
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
return EFI_SUCCESS;
}
AsciiPrint (" Module Name %g EntryPoint %lx\n", &Hob.MemoryAllocationModule->ModuleName, Hob.MemoryAllocationModule->EntryPoint);
}
} else if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
AsciiPrint ("Resource HOB %a %g %08lx:%lx\n Attributes: %08x\n",
(Hob.ResourceDescriptor->ResourceType < EFI_RESOURCE_MAX_MEMORY_TYPE) ? mHobResourceType[Hob.ResourceDescriptor->ResourceType] : mHobResourceType[EFI_RESOURCE_MAX_MEMORY_TYPE],
&Hob.ResourceDescriptor->Owner,
Hob.ResourceDescriptor->PhysicalStart,
Hob.ResourceDescriptor->ResourceLength,
Hob.ResourceDescriptor->ResourceAttribute
);
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
return EFI_SUCCESS;
}
} else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {
AsciiPrint ("GUID HOB %g\n", &Hob.Guid->Name);
if (CompareGuid (&gEfiMemoryTypeInformationGuid, &Hob.Guid->Name)) {
EfiMemoryTypeInformation = GET_GUID_HOB_DATA (Hob.Guid);
for (Index = 0; Index < (GET_GUID_HOB_DATA_SIZE (Hob.Guid)/sizeof (EFI_MEMORY_TYPE_INFORMATION)); Index++, EfiMemoryTypeInformation++) {
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
return EFI_SUCCESS;
}
AsciiPrint (" %a 0x%08x\n",
(EfiMemoryTypeInformation->Type < EfiMaxMemoryType) ? gMemMapType[EfiMemoryTypeInformation->Type] : "END ",
EfiMemoryTypeInformation->NumberOfPages
);
}
}
} else if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {
AsciiPrint ("FV HOB %08lx:%08lx\n", Hob.FirmwareVolume->BaseAddress, Hob.FirmwareVolume->Length);
} else if (Hob.Header->HobType == EFI_HOB_TYPE_CPU) {
AsciiPrint ("CPU HOB: Mem %x IO %x\n", Hob.Cpu->SizeOfMemorySpace, Hob.Cpu->SizeOfIoSpace);
} else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_POOL) {
AsciiPrint ("Mem Pool HOB:\n");
/* Not in PI
} else if (Hob.Header->HobType == EFI_HOB_TYPE_CV) {
AsciiPrint ("CV HOB: %08lx:%08lx\n", Hob.CapsuleVolume->BaseAddress, Hob.CapsuleVolume->Length);
*/
}
if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
break;
}
}
return EFI_SUCCESS;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHobTemplate[] =
{
{
"hob",
"; dump HOBs",
NULL,
EblHobCmd
}
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitializeHobCmd (
VOID
)
{
if (FeaturePcdGet (PcdEmbeddedHobCmd)) {
EblAddCommands (mCmdHobTemplate, sizeof (mCmdHobTemplate)/sizeof (EBL_COMMAND_TABLE));
}
}

342
EmbeddedPkg/Ebl/HwDebug.c Normal file
View File

@@ -0,0 +1,342 @@
/** @file
Basic command line parser for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: HwDebug.c
Commands useful for debugging hardware.
**/
#include "Ebl.h"
/**
Dump memory
Argv[0] - "md"
Argv[1] - Hex Address to dump
Argv[2] - Number of hex bytes to dump (0x20 is default)
Argv[3] - [1|2|4|8] byte width of the dump
md 0x123445678 50 4 ; Dump 0x50 4 byte quantities starting at 0x123445678
md 0x123445678 40 ; Dump 0x40 1 byte quantities starting at 0x123445678
md 0x123445678 ; Dump 0x20 1 byte quantities starting at 0x123445678
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblMdCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
STATIC UINT8 *Address = NULL;
STATIC UINTN Length = 0x20;
STATIC UINTN Width = 1;
switch (Argc)
{
case 4:
Width = AsciiStrHexToUintn(Argv[3]);
case 3:
Length = AsciiStrHexToUintn(Argv[2]);
case 2:
Address = (UINT8 *)AsciiStrHexToUintn(Argv[1]);
default:
break;
}
OutputData(Address, Length, Width, (UINTN)Address);
Address += Length;
return EFI_SUCCESS;
}
/**
Fill Memory with data
Argv[0] - "mfill"
Argv[1] - Hex Address to fill
Argv[2] - Data to write (0x00 is default)
Argv[3] - Number of units to dump.
Argv[4] - [1|2|4|8] byte width of the dump
mf 0x123445678 aa 1 100 ; Start at 0x123445678 and write aa (1 byte) to the next 100 bytes
mf 0x123445678 aa 4 100 ; Start at 0x123445678 and write aa (4 byte) to the next 400 bytes
mf 0x123445678 aa ; Start at 0x123445678 and write aa (4 byte) to the next 1 byte
mf 0x123445678 ; Start at 0x123445678 and write 00 (4 byte) to the next 1 byte
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblMfillCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
UINTN Address;
UINTN EndAddress;
UINT32 Data;
UINTN Length;
UINTN Width;
if (Argc < 2) {
return EFI_INVALID_PARAMETER;
}
Address = AsciiStrHexToUintn (Argv[1]);
Data = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 0;
Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 4;
Length = (Argc > 4) ? AsciiStrHexToUintn (Argv[4]) : 1;
for (EndAddress = Address + (Length * Width); Address < EndAddress; Address += Width) {
if (Width == 4) {
MmioWrite32 (Address, Data);
} else if (Width == 2) {
MmioWrite32 (Address, (UINT16)Data);
} else {
MmioWrite32 (Address, (UINT8)Data);
}
}
return EFI_SUCCESS;
}
//
// Strings for PCI Class code [2]
//
CHAR8 *gPciDevClass[] = {
"Old Device ",
"Mass storage ",
"Network ",
"Display ",
"Multimedia ",
"Memory controller ",
"Bridge device ",
"simple communications ",
"base system peripherals",
"Input devices ",
"Docking stations ",
"Processors ",
"serial bus ",
};
CHAR8 *gPciSerialClassCodes[] = {
"Mass storage ",
"Firewire ",
"ACCESS bus ",
"SSA ",
"USB "
};
/**
PCI Dump
Argv[0] - "pci"
Argv[1] - bus
Argv[2] - dev
Argv[3] - func
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblPciCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *Pci;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Seg;
UINTN Bus;
UINTN Dev;
UINTN Func;
UINTN BusArg;
UINTN DevArg;
UINTN FuncArg;
UINTN Index;
UINTN Count;
PCI_TYPE_GENERIC PciHeader;
PCI_TYPE_GENERIC *Header;
PCI_BRIDGE_CONTROL_REGISTER *Bridge;
PCI_DEVICE_HEADER_TYPE_REGION *Device;
PCI_DEVICE_INDEPENDENT_REGION *Hdr;
CHAR8 *Str;
UINTN ThisBus;
BusArg = (Argc > 1) ? AsciiStrDecimalToUintn (Argv[1]) : 0;
DevArg = (Argc > 2) ? AsciiStrDecimalToUintn (Argv[2]) : 0;
FuncArg = (Argc > 3) ? AsciiStrDecimalToUintn (Argv[3]) : 0;
Header = &PciHeader;
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
AsciiPrint ("No PCI devices found in the system\n");
return EFI_SUCCESS;
}
if (Argc == 1) {
// Dump all PCI devices
AsciiPrint ("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
AsciiPrint ("_____________________________________________________________");
for (ThisBus = 0; ThisBus <= PCI_MAX_BUS; ThisBus++) {
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
if (!EFI_ERROR (Status)) {
Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
if (ThisBus != Bus) {
continue;
}
AsciiPrint ("\n%03d.%02d.%02d", Bus, Dev, Func);
Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), &PciHeader);
if (!EFI_ERROR (Status)) {
Hdr = &PciHeader.Bridge.Hdr;
if (Hdr->ClassCode[2] < sizeof (gPciDevClass)/sizeof (VOID *)) {
Str = gPciDevClass[Hdr->ClassCode[2]];
if (Hdr->ClassCode[2] == PCI_CLASS_SERIAL) {
if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes)/sizeof (VOID *)) {
// print out Firewire or USB inplace of Serial Bus controllers
Str = gPciSerialClassCodes[Hdr->ClassCode[1]];
}
}
} else {
Str = "Unknown device ";
}
AsciiPrint (" 0x%04x 0x%04x %a 0x%02x", Hdr->VendorId, Hdr->DeviceId, Str, Hdr->ClassCode[1]);
}
if (Seg != 0) {
// Only print Segment if it is non zero. If you only have one PCI segment it is
// redundent to print it out
AsciiPrint (" Seg:%d", Seg);
}
}
}
}
AsciiPrint ("\n");
} else {
// Dump specific PCI device
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
if (!EFI_ERROR (Status)) {
Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
if ((Bus == BusArg) && (Dev == DevArg) && (Func == FuncArg)) {
// Only print Segment if it is non zero. If you only have one PCI segment it is
// redundent to print it out
if (Seg != 0) {
AsciiPrint ("Seg:%d ", Seg);
}
AsciiPrint ("Bus:%d Dev:%d Func:%d ", Bus, Dev, Func);
Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), Header);
if (!EFI_ERROR (Status)) {
Hdr = &PciHeader.Bridge.Hdr;
if (IS_PCI_BRIDGE (&PciHeader.Bridge)) {
Bridge = &PciHeader.Bridge.Bridge;
AsciiPrint (
"PCI Bridge. Bus Primary %d Secondary %d Subordinate %d\n",
Bridge->PrimaryBus, Bridge->SecondaryBus, Bridge->SubordinateBus
);
AsciiPrint (" Bar 0: 0x%08x Bar 1: 0x%08x\n", Bridge->Bar[0], Bridge->Bar[1]);
} else {
Device = &PciHeader.Device.Device;
AsciiPrint (
"VendorId: 0x%04x DeviceId: 0x%04x SubSusVendorId: 0x%04x SubSysDeviceId: 0x%04x\n",
Hdr->VendorId, Hdr->DeviceId, Device->SubsystemVendorID, Device->SubsystemID
);
AsciiPrint (" Class Code: 0x%02x 0x%02x 0x%02x\n", Hdr->ClassCode[2], Hdr->ClassCode[1], Hdr->ClassCode[0]);
for (Count = 0; Count < 6; Count++) {
AsciiPrint (" Bar %d: 0x%08x\n", Count, Device->Bar[Count]);
}
}
}
AsciiPrint ("\n");
break;
}
}
}
}
FreePool (HandleBuffer);
return EFI_SUCCESS;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdPciDebugTemplate[] = {
"pci",
" [bus] [dev] [func]; Dump PCI",
NULL,
EblPciCmd
};
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwDebugTemplate[] =
{
{
"md",
" [Addr] [Len] [1|2|4]; Memory Dump from Addr Len bytes",
NULL,
EblMdCmd
},
{
"mfill",
" Addr Len [data] [1|2|4]; Memory Fill Addr Len*(1|2|4) bytes of data(0)",
NULL,
EblMfillCmd
},
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitializemdHwDebugCmds (
VOID
)
{
if (FeaturePcdGet (PcdEmbeddedHwDebugCmd)) {
EblAddCommands (mCmdHwDebugTemplate, sizeof (mCmdHwDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
}
if (FeaturePcdGet (PcdEmbeddedPciDebugCmd)) {
EblAddCommands (mCmdPciDebugTemplate, sizeof (mCmdPciDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
}
}

153
EmbeddedPkg/Ebl/HwIoDebug.c Normal file
View File

@@ -0,0 +1,153 @@
/** @file
Hardware IO based debug commands
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Commands useful for debugging hardware. IO commands seperated out as not all
processor architectures support the IO command.
**/
#include "Ebl.h"
/**
Read from IO space
Argv[0] - "ioread"
Argv[1] - Hex IO address
Argv[2] - IO Width [1|2|4] with a default of 1
ior 0x3f8 4 ;Do a 32-bit IO Read from 0x3f8
ior 0x3f8 1 ;Do a 8-bit IO Read from 0x3f8
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblIoReadCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
UINTN Width;
UINTN Port;
UINTN Data;
if (Argc < 2) {
return EFI_INVALID_PARAMETER;
}
Port = AsciiStrHexToUintn (Argv[1]);
Width = (Argc > 2) ? AsciiStrHexToUintn (Argv[2]) : 1;
if (Width == 1) {
Data = IoRead8 (Port);
} else if (Width == 2) {
Data = IoRead16 (Port);
} else if (Width == 4) {
Data = IoRead32 (Port);
} else {
return EFI_INVALID_PARAMETER;
}
AsciiPrint ("0x%04x = 0x%x", Port, Data);
return EFI_SUCCESS;
}
/**
Write to IO space
Argv[0] - "iowrite"
Argv[1] - Hex IO address
Argv[2] - Hex data to write
Argv[3] - IO Width [1|2|4] with a default of 1
iow 0x3f8 af 4 ;Do a 32-bit IO write of af to 0x3f8
iow 0x3f8 af ;Do an 8-bit IO write of af to 0x3f8
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblIoWriteCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
UINTN Width;
UINTN Port;
UINTN Data;
if (Argc < 3) {
return EFI_INVALID_PARAMETER;
}
Port = AsciiStrHexToUintn (Argv[1]);
Data = AsciiStrHexToUintn (Argv[2]);
Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 1;
if (Width == 1) {
IoWrite8 (Port, (UINT8)Data);
} else if (Width == 2) {
IoWrite16 (Port, (UINT16)Data);
} else if (Width == 4) {
IoWrite32 (Port, (UINT32)Data);
} else {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwIoDebugTemplate[] =
{
{
"ioread",
" Port [1|2|4]; IO read of width[1] byte(s) from Port",
NULL,
EblIoReadCmd
},
{
"iowrite",
" Port Data [1|2|4]; IO write Data of width[1] byte(s) to Port",
NULL,
EblIoWriteCmd
}
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitializemdHwIoDebugCmds (
VOID
)
{
if (FeaturePcdGet (PcdEmbeddedIoEnable)) {
EblAddCommands (mCmdHwIoDebugTemplate, sizeof (mCmdHwIoDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
}
}

616
EmbeddedPkg/Ebl/Main.c Normal file
View File

@@ -0,0 +1,616 @@
/** @file
Basic command line parser for EBL (Embedded Boot Loader)
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ebl.h"
// Globals for command history processing
INTN mCmdHistoryEnd = -1;
INTN mCmdHistoryStart = -1;
INTN mCmdHistoryCurrent = -1;
CHAR8 mCmdHistory[MAX_CMD_HISTORY][MAX_CMD_LINE];
CHAR8 *mCmdBlank = "";
// Globals to remember current screen geometry
UINTN gScreenColumns;
UINTN gScreenRows;
// Global to turn on/off breaking commands with prompts before they scroll the screen
BOOLEAN gPageBreak = TRUE;
VOID
RingBufferIncrement (
IN INTN *Value
)
{
*Value = *Value + 1;
if (*Value >= MAX_CMD_HISTORY) {
*Value = 0;
}
}
VOID
RingBufferDecrement (
IN INTN *Value
)
{
*Value = *Value - 1;
if (*Value < 0) {
*Value = MAX_CMD_HISTORY - 1;
}
}
/**
Save this command in the circular history buffer. Older commands are
overwritten with newer commands.
@param Cmd Command line to archive the history of.
@return None
**/
VOID
SetCmdHistory (
IN CHAR8 *Cmd
)
{
// Don't bother adding empty commands to the list
if (AsciiStrLen(Cmd) != 0) {
// First entry
if (mCmdHistoryStart == -1) {
mCmdHistoryStart = 0;
mCmdHistoryEnd = 0;
} else {
// Record the new command at the next index
RingBufferIncrement(&mCmdHistoryStart);
// If the next index runs into the end index, shuffle end back by one
if (mCmdHistoryStart == mCmdHistoryEnd) {
RingBufferIncrement(&mCmdHistoryEnd);
}
}
// Copy the new command line into the ring buffer
AsciiStrnCpy(&mCmdHistory[mCmdHistoryStart][0], Cmd, MAX_CMD_LINE);
}
// Reset the command history for the next up arrow press
mCmdHistoryCurrent = mCmdHistoryStart;
}
/**
Retreave data from the Command History buffer. Direction maps into up arrow
an down arrow on the command line
@param Direction Command forward or back
@return The Command history based on the Direction
**/
CHAR8 *
GetCmdHistory (
IN UINT16 Direction
)
{
CHAR8 *HistoricalCommand = NULL;
// No history yet?
if (mCmdHistoryCurrent == -1) {
HistoricalCommand = mCmdBlank;
goto Exit;
}
if (Direction == SCAN_UP) {
HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
// if we just echoed the last command, hang out there, don't wrap around
if (mCmdHistoryCurrent == mCmdHistoryEnd) {
goto Exit;
}
// otherwise, back up by one
RingBufferDecrement(&mCmdHistoryCurrent);
} else if (Direction == SCAN_DOWN) {
// if we last echoed the start command, put a blank prompt out
if (mCmdHistoryCurrent == mCmdHistoryStart) {
HistoricalCommand = mCmdBlank;
goto Exit;
}
// otherwise increment the current pointer and return that command
RingBufferIncrement(&mCmdHistoryCurrent);
RingBufferIncrement(&mCmdHistoryCurrent);
HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
RingBufferDecrement(&mCmdHistoryCurrent);
}
Exit:
return HistoricalCommand;
}
/**
Parse the CmdLine and break it up into Argc (arg count) and Argv (array of
pointers to each argument). The Cmd buffer is altered and seperators are
converted to string terminators. This allows Argv to point into CmdLine.
A CmdLine can support multiple commands. The next command in the command line
is returned if it exists.
@param CmdLine String to parse for a set of commands
@param Argc Returns the number of arguments in the CmdLine current command
@param Argv Argc pointers to each string in CmdLine
@return Next Command in the command line or NULL if non exists
**/
CHAR8 *
ParseArguments (
IN CHAR8 *CmdLine,
OUT UINTN *Argc,
OUT CHAR8 **Argv
)
{
UINTN Arg;
CHAR8 *Char;
BOOLEAN LookingForArg;
BOOLEAN InQuote;
*Argc = 0;
if (AsciiStrLen (CmdLine) == 0) {
return NULL;
}
// Walk a single command line. A CMD_SEPERATOR allows mult commands on a single line
InQuote = FALSE;
LookingForArg = TRUE;
for (Char = CmdLine, Arg = 0; *Char != '\0'; Char++) {
if (!InQuote && *Char == CMD_SEPERATOR) {
break;
}
// Perform any text coversion here
if (*Char == '\t') {
// TAB to space
*Char = ' ';
}
if (LookingForArg) {
// Look for the beging of an Argv[] entry
if (*Char == '"') {
Argv[Arg++] = ++Char;
LookingForArg = FALSE;
InQuote = TRUE;
} else if (*Char != ' ') {
Argv[Arg++] = Char;
LookingForArg = FALSE;
}
} else {
// Looking for the terminator of an Argv[] entry
if ((InQuote && (*Char == '"')) || (!InQuote && (*Char == ' '))) {
*Char = '\0';
LookingForArg = TRUE;
}
}
}
*Argc = Arg;
if (*Char == CMD_SEPERATOR) {
// Replace the command delimeter with null and return pointer to next command line
*Char = '\0';
return ++Char;
}
return NULL;
}
/**
Return a keypress or optionally timeout if a timeout value was passed in.
An optional callback funciton is called evey second when waiting for a
timeout.
@param Key EFI Key information returned
@param TimeoutInSec Number of seconds to wait to timeout
@param CallBack Callback called every second during the timeout wait
@return EFI_SUCCESS Key was returned
@return EFI_TIMEOUT If the TimoutInSec expired
**/
EFI_STATUS
EblGetCharKey (
IN OUT EFI_INPUT_KEY *Key,
IN UINTN TimeoutInSec,
IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
)
{
EFI_STATUS Status;
UINTN WaitCount;
UINTN WaitIndex;
EFI_EVENT WaitList[2];
WaitCount = 1;
WaitList[0] = gST->ConIn->WaitForKey;
if (TimeoutInSec != 0) {
// Create a time event for 1 sec duration if we have a timeout
gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[1]);
gBS->SetTimer (WaitList[1], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
WaitCount++;
}
for (;;) {
Status = gBS->WaitForEvent (WaitCount, WaitList, &WaitIndex);
ASSERT_EFI_ERROR (Status);
switch (WaitIndex) {
case 0:
// Key event signaled
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
if (!EFI_ERROR (Status)) {
if (WaitCount == 2) {
gBS->CloseEvent (WaitList[1]);
}
return EFI_SUCCESS;
}
break;
case 1:
// Periodic 1 sec timer signaled
TimeoutInSec--;
if (CallBack != NULL) {
// Call the users callback function if registered
CallBack (TimeoutInSec);
}
if (TimeoutInSec == 0) {
gBS->CloseEvent (WaitList[1]);
return EFI_TIMEOUT;
}
break;
default:
ASSERT (FALSE);
}
}
}
/**
This routine is used prevent command output data from scrolling off the end
of the screen. The global gPageBreak is used to turn on or off this feature.
If the CurrentRow is near the end of the screen pause and print out a prompt
If the use hits Q to quit return TRUE else for any other key return FALSE.
PrefixNewline is used to figure out if a newline is needed before the prompt
string. This depends on the last print done before calling this function.
CurrentRow is updated by one on a call or set back to zero if a prompt is
needed.
@param CurrentRow Used to figure out if its the end of the page and updated
@param PrefixNewline Did previous print issue a newline
@return TRUE if Q was hit to quit, FALSE in all other cases.
**/
BOOLEAN
EblAnyKeyToContinueQtoQuit (
IN UINTN *CurrentRow,
IN BOOLEAN PrefixNewline
)
{
EFI_INPUT_KEY InputKey;
if (!gPageBreak) {
// global disable for this feature
return FALSE;
}
if (*CurrentRow >= (gScreenRows - 2)) {
if (PrefixNewline) {
AsciiPrint ("\n");
}
AsciiPrint ("Any key to continue (Q to quit): ");
EblGetCharKey (&InputKey, 0, NULL);
AsciiPrint ("\n");
// Time to promt to stop the screen. We have to leave space for the prompt string
*CurrentRow = 0;
if (InputKey.UnicodeChar == 'Q' || InputKey.UnicodeChar == 'q') {
return TRUE;
}
} else {
*CurrentRow += 1;
}
return FALSE;
}
/**
Set the text color of the EFI Console. If a zero is passed in reset to
default text/background color.
@param Attribute For text and background color
**/
VOID
EblSetTextColor (
UINTN Attribute
)
{
if (Attribute == 0) {
// Set the text color back to default
Attribute = (UINTN)PcdGet32 (PcdEmbeddedDefaultTextColor);
}
gST->ConOut->SetAttribute (gST->ConOut, Attribute);
}
/**
Collect the keyboard input for a cmd line. Carage Return, New Line, or ESC
terminates the command line. You can edit the command line via left arrow,
delete and backspace and they all back up and erase the command line.
No edit of commnad line is possible without deletion at this time!
The up arrow and down arrow fill Cmd with information from the history
buffer.
@param Cmd Command line to return
@param CmdMaxSize Maximum size of Cmd
@return The Status of EblGetCharKey()
**/
EFI_STATUS
GetCmd (
IN OUT CHAR8 *Cmd,
IN UINTN CmdMaxSize
)
{
EFI_STATUS Status;
UINTN Index;
UINTN Index2;
CHAR8 Char;
CHAR8 *History;
EFI_INPUT_KEY Key;
for (Index = 0; Index < CmdMaxSize - 1;) {
Status = EblGetCharKey (&Key, 0, NULL);
if (EFI_ERROR (Status)) {
Cmd[Index] = '\0';
AsciiPrint ("\n");
return Status;
}
Char = (CHAR8)Key.UnicodeChar;
if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
Cmd[Index] = '\0';
if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
AsciiPrint ("\n\r");
}
return EFI_SUCCESS;
} else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
if (Index != 0) {
Index--;
//
// Update the display
//
AsciiPrint ("\b \b");
}
} else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) {
History = GetCmdHistory (Key.ScanCode);
//
// Clear display line
//
for (Index2 = 0; Index2 < Index; Index2++) {
AsciiPrint ("\b \b");
}
AsciiPrint (History);
Index = AsciiStrLen (History);
AsciiStrnCpy (Cmd, History, CmdMaxSize);
} else {
Cmd[Index++] = Char;
if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
AsciiPrint ("%c", Char);
}
}
}
return EFI_SUCCESS;
}
/**
Print the boot up banner for the EBL.
**/
VOID
EblPrintStartupBanner (
VOID
)
{
AsciiPrint ("Embedded Boot Loader (");
EblSetTextColor (EFI_YELLOW);
AsciiPrint ("EBL");
EblSetTextColor (0);
AsciiPrint (") prototype. Built at %a on %a\n",__TIME__, __DATE__);
AsciiPrint ("THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN 'AS IS' BASIS,\nWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\n");
AsciiPrint ("Please send feedback to dev@edk2.tianocore.org\n");
}
/**
Print the prompt for the EBL.
**/
VOID
EblPrompt (
VOID
)
{
EblSetTextColor (EFI_YELLOW);
AsciiPrint ((CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt));
EblSetTextColor (0);
AsciiPrint ("%a", ">");
}
/**
Parse a command line and execute the commands. The ; seperator allows
multiple commands for each command line. Stop processing if one of the
commands returns an error.
@param CmdLine Command Line to process.
@param MaxCmdLineSize MaxSize of the Command line
@return EFI status of the Command
**/
EFI_STATUS
ProcessCmdLine (
IN CHAR8 *CmdLine,
IN UINTN MaxCmdLineSize
)
{
EFI_STATUS Status;
EBL_COMMAND_TABLE *Cmd;
CHAR8 *Ptr;
UINTN Argc;
CHAR8 *Argv[MAX_ARGS];
// Parse the command line. The loop processes commands seperated by ;
for (Ptr = CmdLine, Status = EFI_SUCCESS; Ptr != NULL;) {
Ptr = ParseArguments (Ptr, &Argc, Argv);
if (Argc != 0) {
Cmd = EblGetCommand (Argv[0]);
if (Cmd != NULL) {
// Execute the Command!
Status = Cmd->Command (Argc, Argv);
if (Status == EFI_ABORTED) {
// exit command so lets exit
break;
} else if (Status == EFI_TIMEOUT) {
// pause command got imput so don't process any more cmd on this cmd line
break;
} else if (EFI_ERROR (Status)) {
AsciiPrint ("%a returned %r error\n", Cmd->Name, Status);
// if any command fails stop processing CmdLine
break;
}
}
}
}
return Status;
}
/**
Embedded Boot Loader (EBL) - A simple EFI command line application for embedded
devices. PcdEmbeddedAutomaticBootCommand is a complied in commnad line that
gets executed automatically. The ; seperator allows multiple commands
for each command line.
@param ImageHandle EFI ImageHandle for this application.
@param SystemTable EFI system table
@return EFI status of the applicaiton
**/
EFI_STATUS
EFIAPI
EdkBootLoaderEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
CHAR8 CmdLine[MAX_CMD_LINE];
CHAR16 *CommandLineVariable = NULL;
CHAR16 *CommandLineVariableName = L"default-cmdline";
UINTN CommandLineVariableSize = 0;
EFI_GUID VendorGuid;
// Initialize tables of commnads
EblInitializeCmdTable ();
EblInitializeDeviceCmd ();
EblInitializemdHwDebugCmds ();
EblInitializemdHwIoDebugCmds ();
EblInitializeDirCmd ();
EblInitializeHobCmd ();
EblInitializeScriptCmd ();
EblInitializeExternalCmd ();
EblInitializeNetworkCmd();
if (FeaturePcdGet (PcdEmbeddedMacBoot)) {
// A MAC will boot in graphics mode, so turn it back to text here
// This protocol was removed from edk2. It is only an edk thing. We need to make our own copy.
// DisableQuietBoot ();
// Enable the biggest output screen size possible
gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1);
// Disable the 5 minute EFI watchdog time so we don't get automatically reset
gBS->SetWatchdogTimer (0, 0, 0, NULL);
}
// Save current screen mode
gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows);
EblPrintStartupBanner ();
// Parse command line and handle commands seperated by ;
// The loop prints the prompt gets user input and saves history
// Look for a variable with a default command line, otherwise use the Pcd
ZeroMem(&VendorGuid, sizeof(EFI_GUID));
Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
if (Status == EFI_BUFFER_TOO_SMALL) {
CommandLineVariable = AllocatePool(CommandLineVariableSize);
Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
if (!EFI_ERROR(Status)) {
UnicodeStrToAsciiStr(CommandLineVariable, CmdLine);
}
FreePool(CommandLineVariable);
}
if (EFI_ERROR(Status)) {
AsciiStrCpy (CmdLine, (CHAR8 *)PcdGetPtr (PcdEmbeddedAutomaticBootCommand));
}
for (;;) {
Status = ProcessCmdLine (CmdLine, MAX_CMD_LINE);
if (Status == EFI_ABORTED) {
// if a command returns EFI_ABORTED then exit the EBL
EblShutdownExternalCmdTable ();
return EFI_SUCCESS;
}
// get the command line from the user
EblPrompt ();
GetCmd (CmdLine, MAX_CMD_LINE);
SetCmdHistory (CmdLine);
}
}

104
EmbeddedPkg/Ebl/Network.c Normal file
View File

@@ -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));
}

126
EmbeddedPkg/Ebl/Script.c Normal file
View File

@@ -0,0 +1,126 @@
/** @file
Script command allows the execution of commands from a text file
Copyright (c) 2007, Intel Corporation<BR>
Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: EfiDevice.c
**/
#include "Ebl.h"
/**
Execute the passed in file like a series of commands. The ; can be used on
a single line to indicate multiple commands per line. The Ascii text file
can contain any number of lines. The following line termination forms are
supported:
LF : Unix, Mac OS X*, BeOS
CR+LF: MS-DOS*, Microsoft Windows*
CR : Commodore, Apple II, and realy Mac OS
LF+CR: for simplicity and completeness
Argv[0] - "script"
Argv[1] - Device Name:path for the file to load
script fv1:\script.txt
@param Argc Number of command arguments in Argv
@param Argv Array of strings that represent the parsed command line.
Argv[0] is the comamnd name
@return EFI_SUCCESS
**/
EFI_STATUS
EblScriptCmd (
IN UINTN Argc,
IN CHAR8 **Argv
)
{
EFI_STATUS Status;
EFI_OPEN_FILE *File;
VOID *Address;
UINTN Size;
CHAR8 *Ptr;
CHAR8 *ScanPtr;
UINTN CmdLineSize;
if (Argc < 2) {
// file name required
return EFI_SUCCESS;
}
File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
if (File == NULL) {
AsciiPrint (" %a is not a valid path\n", Argv[1]);
return EFI_SUCCESS;
}
Status = EfiReadAllocatePool (File, &Address, &Size);
if (!EFI_ERROR (Status)) {
// Loop through each line in the text file
for (Ptr = (CHAR8 *)Address; (Ptr < (((CHAR8 *)Address) + Size)) && !EFI_ERROR (Status); Ptr += CmdLineSize) {
for (CmdLineSize = 0, ScanPtr = Ptr; ; CmdLineSize++, ScanPtr++) {
// look for the end of the line
if ((*ScanPtr == EBL_CR) || (*ScanPtr == EBL_LF)) {
// convert to NULL as this is what input routine would do
*ScanPtr = 0;
if ((*(ScanPtr + 1) == EBL_CR) || (*(ScanPtr + 1) == EBL_LF)) {
// if its a set get the 2nd EOL char
CmdLineSize++;
*(ScanPtr + 1) = 0;
}
CmdLineSize++;
break;
}
}
Status = ProcessCmdLine (Ptr, CmdLineSize);
}
FreePool (Address);
}
EfiClose (File);
return Status;
}
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mScriptTemplate[] = {
{
"script",
" device:path; load an ascii file and execute it like commands",
NULL,
EblScriptCmd
}
};
/**
Initialize the commands in this in this file
**/
VOID
EblInitializeScriptCmd (
VOID
)
{
if (FeaturePcdGet (PcdEmbeddedScriptCmd)) {
EblAddCommands (mScriptTemplate, sizeof (mScriptTemplate)/sizeof (EBL_COMMAND_TABLE));
}
}