The EFIAPI function declaration is missing for several functions in the EmbeddedPkg/Ebl directory. A few function pointer struct members expect EFIAPI though and GCC46/X64 will fail to compile the directory without them. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Thomas Palmer <thomas.palmer@hpe.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18697 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			678 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			678 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Basic command line parser for EBL (Embedded Boot Loader)
 | |
| 
 | |
|   Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
 | |
|   Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | |
|   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 | |
| 
 | |
|   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 separators 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_SEPARATOR allows multiple commands on a single line
 | |
|   InQuote       = FALSE;
 | |
|   LookingForArg = TRUE;
 | |
|   for (Char = CmdLine, Arg = 0; *Char != '\0'; Char++) {
 | |
|     if (!InQuote && *Char == CMD_SEPARATOR) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     // Perform any text conversion here
 | |
|     if (*Char == '\t') {
 | |
|       // TAB to space
 | |
|       *Char = ' ';
 | |
|     }
 | |
| 
 | |
|     if (LookingForArg) {
 | |
|       // Look for the beginning 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 == ' ')) {
 | |
|         *Char = '\0';
 | |
|         LookingForArg = TRUE;
 | |
|       } else if (!InQuote && (*Char == '"') && (*(Char-1) != '\\')) {
 | |
|         InQuote = TRUE;
 | |
|       } else if (InQuote && (*Char == '"') && (*(Char-1) != '\\')) {
 | |
|         *Char = '\0';
 | |
|         InQuote = FALSE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *Argc = Arg;
 | |
| 
 | |
|   if (*Char == CMD_SEPARATOR) {
 | |
|     // Replace the command delimiter 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 function is called every 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
 | |
| EFIAPI
 | |
| 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
 | |
| EFIAPI
 | |
| 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. Carriage 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 command 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 edk2-devel@lists.sourceforge.net\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Send null requests to all removable media block IO devices so the a media add/remove/change
 | |
|   can be detected in real before we execute a command.
 | |
| 
 | |
|   This is mainly due to the fact that the FAT driver does not do this today so you can get stale
 | |
|   dir commands after an SD Card has been removed.
 | |
| **/
 | |
| VOID
 | |
| EblProbeRemovableMedia (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   UINTN         Max;
 | |
|   EFI_OPEN_FILE *File;
 | |
| 
 | |
|   //
 | |
|   // Probe for media insertion/removal in removable media devices
 | |
|   //
 | |
|   Max = EfiGetDeviceCounts (EfiOpenBlockIo);
 | |
|   if (Max != 0) {
 | |
|     for (Index = 0; Index < Max; Index++) {
 | |
|       File = EfiDeviceOpenByType (EfiOpenBlockIo, Index);
 | |
|       if (File != NULL) {
 | |
|         if (File->FsBlockIoMedia->RemovableMedia) {
 | |
|           // Probe to see if media is present (or not) or media changed
 | |
|           //  this causes the ReinstallProtocolInterface() to fire in the
 | |
|           //  block io driver to update the system about media change events
 | |
|           File->FsBlockIo->ReadBlocks (File->FsBlockIo, File->FsBlockIo->Media->MediaId, (EFI_LBA)0, 0, NULL);
 | |
|         }
 | |
|         EfiClose (File);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print the prompt for the EBL.
 | |
| **/
 | |
| VOID
 | |
| EblPrompt (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EblSetTextColor (EFI_YELLOW);
 | |
|   AsciiPrint ("%a %a",(CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt), EfiGetCwd ());
 | |
|   EblSetTextColor (0);
 | |
|   AsciiPrint ("%a", ">");
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Parse a command line and execute the commands. The ; separator 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 separated 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 input 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;
 | |
|         }
 | |
|       } else {
 | |
|         AsciiPrint ("The command '%a' is not supported.\n", Argv[0]);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Embedded Boot Loader (EBL) - A simple EFI command line application for embedded
 | |
|   devices. PcdEmbeddedAutomaticBootCommand is a complied in command line that
 | |
|   gets executed automatically. The ; separator allows multiple commands
 | |
|   for each command line.
 | |
| 
 | |
|   @param  ImageHandle   EFI ImageHandle for this application.
 | |
|   @param  SystemTable   EFI system table
 | |
| 
 | |
|   @return EFI status of the application
 | |
| 
 | |
| **/
 | |
| 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 commands
 | |
|   EblInitializeCmdTable ();
 | |
|   EblInitializeDeviceCmd ();
 | |
|   EblInitializemdHwDebugCmds ();
 | |
|   EblInitializemdHwIoDebugCmds ();
 | |
|   EblInitializeDirCmd ();
 | |
|   EblInitializeHobCmd ();
 | |
|   EblInitializeScriptCmd ();
 | |
|   EblInitializeExternalCmd ();
 | |
|   EblInitializeNetworkCmd();
 | |
|   EblInitializeVariableCmds ();
 | |
| 
 | |
|   if (gST->ConOut == NULL) {
 | |
|     DEBUG((EFI_D_ERROR,"Error: No Console Output\n"));
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   // Disable the 5 minute EFI watchdog time so we don't get automatically reset
 | |
|   gBS->SetWatchdogTimer (0, 0, 0, NULL);
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   }
 | |
| 
 | |
|   // Save current screen mode
 | |
|   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows);
 | |
| 
 | |
|   EblPrintStartupBanner ();
 | |
| 
 | |
|   // Parse command line and handle commands separated 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);
 | |
| 
 | |
|     if (FeaturePcdGet (PcdEmbeddedProbeRemovable)) {
 | |
|       // Probe removable media devices to see if media has been inserted or removed.
 | |
|       EblProbeRemovableMedia ();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 |