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:
616
EmbeddedPkg/Ebl/Main.c
Normal file
616
EmbeddedPkg/Ebl/Main.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user