blob: 18b2878f69a14d19c18094a2eb0ae33a99c65458 [file] [log] [blame]
AJFISH2ef2b012009-12-06 01:57:05 +00001/** @file
2 Basic command line parser for EBL (Embedded Boot Loader)
3
hhtian60274cc2010-04-29 12:40:51 +00004 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Thomas Palmer50c6a4d2015-10-29 12:59:06 +00006 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
AJFISH2ef2b012009-12-06 01:57:05 +00007
hhtian60274cc2010-04-29 12:40:51 +00008 This program and the accompanying materials
AJFISH2ef2b012009-12-06 01:57:05 +00009 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16
17**/
18
19#include "Ebl.h"
20
21// Globals for command history processing
22INTN mCmdHistoryEnd = -1;
23INTN mCmdHistoryStart = -1;
24INTN mCmdHistoryCurrent = -1;
25CHAR8 mCmdHistory[MAX_CMD_HISTORY][MAX_CMD_LINE];
26CHAR8 *mCmdBlank = "";
27
28// Globals to remember current screen geometry
29UINTN gScreenColumns;
30UINTN gScreenRows;
31
32// Global to turn on/off breaking commands with prompts before they scroll the screen
33BOOLEAN gPageBreak = TRUE;
34
Ronald Cron3402aac2014-08-19 13:29:52 +000035VOID
AJFISH2ef2b012009-12-06 01:57:05 +000036RingBufferIncrement (
37 IN INTN *Value
38 )
39{
40 *Value = *Value + 1;
Ronald Cron3402aac2014-08-19 13:29:52 +000041
AJFISH2ef2b012009-12-06 01:57:05 +000042 if (*Value >= MAX_CMD_HISTORY) {
43 *Value = 0;
44 }
45}
46
47VOID
48RingBufferDecrement (
49 IN INTN *Value
50 )
51{
52 *Value = *Value - 1;
Ronald Cron3402aac2014-08-19 13:29:52 +000053
AJFISH2ef2b012009-12-06 01:57:05 +000054 if (*Value < 0) {
55 *Value = MAX_CMD_HISTORY - 1;
56 }
57}
58
59/**
Ronald Cron3402aac2014-08-19 13:29:52 +000060 Save this command in the circular history buffer. Older commands are
AJFISH2ef2b012009-12-06 01:57:05 +000061 overwritten with newer commands.
62
63 @param Cmd Command line to archive the history of.
64
65 @return None
66
67**/
68VOID
69SetCmdHistory (
70 IN CHAR8 *Cmd
71 )
72{
73 // Don't bother adding empty commands to the list
74 if (AsciiStrLen(Cmd) != 0) {
Ronald Cron3402aac2014-08-19 13:29:52 +000075
AJFISH2ef2b012009-12-06 01:57:05 +000076 // First entry
77 if (mCmdHistoryStart == -1) {
78 mCmdHistoryStart = 0;
79 mCmdHistoryEnd = 0;
80 } else {
81 // Record the new command at the next index
82 RingBufferIncrement(&mCmdHistoryStart);
Ronald Cron3402aac2014-08-19 13:29:52 +000083
AJFISH2ef2b012009-12-06 01:57:05 +000084 // If the next index runs into the end index, shuffle end back by one
85 if (mCmdHistoryStart == mCmdHistoryEnd) {
86 RingBufferIncrement(&mCmdHistoryEnd);
87 }
88 }
Ronald Cron3402aac2014-08-19 13:29:52 +000089
AJFISH2ef2b012009-12-06 01:57:05 +000090 // Copy the new command line into the ring buffer
91 AsciiStrnCpy(&mCmdHistory[mCmdHistoryStart][0], Cmd, MAX_CMD_LINE);
92 }
Ronald Cron3402aac2014-08-19 13:29:52 +000093
AJFISH2ef2b012009-12-06 01:57:05 +000094 // Reset the command history for the next up arrow press
Ronald Cron3402aac2014-08-19 13:29:52 +000095 mCmdHistoryCurrent = mCmdHistoryStart;
AJFISH2ef2b012009-12-06 01:57:05 +000096}
97
98
99/**
100 Retreave data from the Command History buffer. Direction maps into up arrow
101 an down arrow on the command line
102
103 @param Direction Command forward or back
104
105 @return The Command history based on the Direction
106
107**/
108CHAR8 *
109GetCmdHistory (
110 IN UINT16 Direction
111 )
112{
113 CHAR8 *HistoricalCommand = NULL;
Ronald Cron3402aac2014-08-19 13:29:52 +0000114
AJFISH2ef2b012009-12-06 01:57:05 +0000115 // No history yet?
116 if (mCmdHistoryCurrent == -1) {
117 HistoricalCommand = mCmdBlank;
118 goto Exit;
119 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000120
AJFISH2ef2b012009-12-06 01:57:05 +0000121 if (Direction == SCAN_UP) {
122 HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
Ronald Cron3402aac2014-08-19 13:29:52 +0000123
AJFISH2ef2b012009-12-06 01:57:05 +0000124 // if we just echoed the last command, hang out there, don't wrap around
125 if (mCmdHistoryCurrent == mCmdHistoryEnd) {
126 goto Exit;
127 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000128
AJFISH2ef2b012009-12-06 01:57:05 +0000129 // otherwise, back up by one
130 RingBufferDecrement(&mCmdHistoryCurrent);
Ronald Cron3402aac2014-08-19 13:29:52 +0000131
AJFISH2ef2b012009-12-06 01:57:05 +0000132 } else if (Direction == SCAN_DOWN) {
Ronald Cron3402aac2014-08-19 13:29:52 +0000133
AJFISH2ef2b012009-12-06 01:57:05 +0000134 // if we last echoed the start command, put a blank prompt out
135 if (mCmdHistoryCurrent == mCmdHistoryStart) {
136 HistoricalCommand = mCmdBlank;
137 goto Exit;
138 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000139
AJFISH2ef2b012009-12-06 01:57:05 +0000140 // otherwise increment the current pointer and return that command
141 RingBufferIncrement(&mCmdHistoryCurrent);
142 RingBufferIncrement(&mCmdHistoryCurrent);
Ronald Cron3402aac2014-08-19 13:29:52 +0000143
AJFISH2ef2b012009-12-06 01:57:05 +0000144 HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0];
145 RingBufferDecrement(&mCmdHistoryCurrent);
146 }
147
Ronald Cron3402aac2014-08-19 13:29:52 +0000148Exit:
AJFISH2ef2b012009-12-06 01:57:05 +0000149 return HistoricalCommand;
150}
151
152
153/**
154 Parse the CmdLine and break it up into Argc (arg count) and Argv (array of
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000155 pointers to each argument). The Cmd buffer is altered and separators are
AJFISH2ef2b012009-12-06 01:57:05 +0000156 converted to string terminators. This allows Argv to point into CmdLine.
157 A CmdLine can support multiple commands. The next command in the command line
158 is returned if it exists.
159
160 @param CmdLine String to parse for a set of commands
161 @param Argc Returns the number of arguments in the CmdLine current command
162 @param Argv Argc pointers to each string in CmdLine
163
164 @return Next Command in the command line or NULL if non exists
165**/
166CHAR8 *
167ParseArguments (
168 IN CHAR8 *CmdLine,
169 OUT UINTN *Argc,
170 OUT CHAR8 **Argv
171 )
172{
173 UINTN Arg;
174 CHAR8 *Char;
175 BOOLEAN LookingForArg;
176 BOOLEAN InQuote;
177
178 *Argc = 0;
179 if (AsciiStrLen (CmdLine) == 0) {
180 return NULL;
181 }
182
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000183 // Walk a single command line. A CMD_SEPARATOR allows multiple commands on a single line
AJFISH2ef2b012009-12-06 01:57:05 +0000184 InQuote = FALSE;
185 LookingForArg = TRUE;
186 for (Char = CmdLine, Arg = 0; *Char != '\0'; Char++) {
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000187 if (!InQuote && *Char == CMD_SEPARATOR) {
AJFISH2ef2b012009-12-06 01:57:05 +0000188 break;
189 }
190
andrewfishfb334ef2011-02-01 05:37:22 +0000191 // Perform any text conversion here
AJFISH2ef2b012009-12-06 01:57:05 +0000192 if (*Char == '\t') {
193 // TAB to space
194 *Char = ' ';
195 }
196
197 if (LookingForArg) {
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000198 // Look for the beginning of an Argv[] entry
AJFISH2ef2b012009-12-06 01:57:05 +0000199 if (*Char == '"') {
200 Argv[Arg++] = ++Char;
201 LookingForArg = FALSE;
202 InQuote = TRUE;
203 } else if (*Char != ' ') {
204 Argv[Arg++] = Char;
205 LookingForArg = FALSE;
Ronald Cron3402aac2014-08-19 13:29:52 +0000206 }
AJFISH2ef2b012009-12-06 01:57:05 +0000207 } else {
208 // Looking for the terminator of an Argv[] entry
andrewfishfb334ef2011-02-01 05:37:22 +0000209 if (!InQuote && (*Char == ' ')) {
AJFISH2ef2b012009-12-06 01:57:05 +0000210 *Char = '\0';
211 LookingForArg = TRUE;
andrewfishfb334ef2011-02-01 05:37:22 +0000212 } else if (!InQuote && (*Char == '"') && (*(Char-1) != '\\')) {
213 InQuote = TRUE;
214 } else if (InQuote && (*Char == '"') && (*(Char-1) != '\\')) {
215 *Char = '\0';
216 InQuote = FALSE;
AJFISH2ef2b012009-12-06 01:57:05 +0000217 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000218 }
AJFISH2ef2b012009-12-06 01:57:05 +0000219 }
220
221 *Argc = Arg;
222
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000223 if (*Char == CMD_SEPARATOR) {
224 // Replace the command delimiter with null and return pointer to next command line
AJFISH2ef2b012009-12-06 01:57:05 +0000225 *Char = '\0';
226 return ++Char;
227 }
228
229 return NULL;
230}
231
232
233/**
234 Return a keypress or optionally timeout if a timeout value was passed in.
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000235 An optional callback function is called every second when waiting for a
AJFISH2ef2b012009-12-06 01:57:05 +0000236 timeout.
237
238 @param Key EFI Key information returned
239 @param TimeoutInSec Number of seconds to wait to timeout
Ronald Cron3402aac2014-08-19 13:29:52 +0000240 @param CallBack Callback called every second during the timeout wait
AJFISH2ef2b012009-12-06 01:57:05 +0000241
242 @return EFI_SUCCESS Key was returned
243 @return EFI_TIMEOUT If the TimoutInSec expired
244
245**/
246EFI_STATUS
Thomas Palmer50c6a4d2015-10-29 12:59:06 +0000247EFIAPI
AJFISH2ef2b012009-12-06 01:57:05 +0000248EblGetCharKey (
249 IN OUT EFI_INPUT_KEY *Key,
250 IN UINTN TimeoutInSec,
251 IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL
252 )
253{
254 EFI_STATUS Status;
255 UINTN WaitCount;
256 UINTN WaitIndex;
257 EFI_EVENT WaitList[2];
258
259 WaitCount = 1;
260 WaitList[0] = gST->ConIn->WaitForKey;
261 if (TimeoutInSec != 0) {
262 // Create a time event for 1 sec duration if we have a timeout
263 gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[1]);
264 gBS->SetTimer (WaitList[1], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
265 WaitCount++;
266 }
267
268 for (;;) {
269 Status = gBS->WaitForEvent (WaitCount, WaitList, &WaitIndex);
270 ASSERT_EFI_ERROR (Status);
271
272 switch (WaitIndex) {
273 case 0:
274 // Key event signaled
275 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
276 if (!EFI_ERROR (Status)) {
277 if (WaitCount == 2) {
278 gBS->CloseEvent (WaitList[1]);
279 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000280 return EFI_SUCCESS;
AJFISH2ef2b012009-12-06 01:57:05 +0000281 }
282 break;
283
284 case 1:
Ronald Cron3402aac2014-08-19 13:29:52 +0000285 // Periodic 1 sec timer signaled
AJFISH2ef2b012009-12-06 01:57:05 +0000286 TimeoutInSec--;
287 if (CallBack != NULL) {
Ronald Cron3402aac2014-08-19 13:29:52 +0000288 // Call the users callback function if registered
AJFISH2ef2b012009-12-06 01:57:05 +0000289 CallBack (TimeoutInSec);
290 }
291 if (TimeoutInSec == 0) {
292 gBS->CloseEvent (WaitList[1]);
293 return EFI_TIMEOUT;
294 }
295 break;
296 default:
297 ASSERT (FALSE);
298 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000299 }
AJFISH2ef2b012009-12-06 01:57:05 +0000300}
301
302
303/**
304 This routine is used prevent command output data from scrolling off the end
305 of the screen. The global gPageBreak is used to turn on or off this feature.
306 If the CurrentRow is near the end of the screen pause and print out a prompt
307 If the use hits Q to quit return TRUE else for any other key return FALSE.
308 PrefixNewline is used to figure out if a newline is needed before the prompt
309 string. This depends on the last print done before calling this function.
Ronald Cron3402aac2014-08-19 13:29:52 +0000310 CurrentRow is updated by one on a call or set back to zero if a prompt is
AJFISH2ef2b012009-12-06 01:57:05 +0000311 needed.
312
313 @param CurrentRow Used to figure out if its the end of the page and updated
314 @param PrefixNewline Did previous print issue a newline
315
316 @return TRUE if Q was hit to quit, FALSE in all other cases.
317
318**/
319BOOLEAN
Thomas Palmer50c6a4d2015-10-29 12:59:06 +0000320EFIAPI
AJFISH2ef2b012009-12-06 01:57:05 +0000321EblAnyKeyToContinueQtoQuit (
322 IN UINTN *CurrentRow,
323 IN BOOLEAN PrefixNewline
324 )
325{
326 EFI_INPUT_KEY InputKey;
327
328 if (!gPageBreak) {
329 // global disable for this feature
330 return FALSE;
331 }
332
333 if (*CurrentRow >= (gScreenRows - 2)) {
334 if (PrefixNewline) {
335 AsciiPrint ("\n");
336 }
337 AsciiPrint ("Any key to continue (Q to quit): ");
338 EblGetCharKey (&InputKey, 0, NULL);
339 AsciiPrint ("\n");
340
341 // Time to promt to stop the screen. We have to leave space for the prompt string
342 *CurrentRow = 0;
343 if (InputKey.UnicodeChar == 'Q' || InputKey.UnicodeChar == 'q') {
344 return TRUE;
345 }
346 } else {
347 *CurrentRow += 1;
348 }
349
350 return FALSE;
351}
352
353
354/**
Ronald Cron3402aac2014-08-19 13:29:52 +0000355 Set the text color of the EFI Console. If a zero is passed in reset to
AJFISH2ef2b012009-12-06 01:57:05 +0000356 default text/background color.
357
358 @param Attribute For text and background color
359
360**/
361VOID
362EblSetTextColor (
363 UINTN Attribute
364 )
365{
366 if (Attribute == 0) {
367 // Set the text color back to default
368 Attribute = (UINTN)PcdGet32 (PcdEmbeddedDefaultTextColor);
369 }
370
371 gST->ConOut->SetAttribute (gST->ConOut, Attribute);
372}
373
374
375/**
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000376 Collect the keyboard input for a cmd line. Carriage Return, New Line, or ESC
AJFISH2ef2b012009-12-06 01:57:05 +0000377 terminates the command line. You can edit the command line via left arrow,
Ronald Cron3402aac2014-08-19 13:29:52 +0000378 delete and backspace and they all back up and erase the command line.
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000379 No edit of command line is possible without deletion at this time!
Ronald Cron3402aac2014-08-19 13:29:52 +0000380 The up arrow and down arrow fill Cmd with information from the history
AJFISH2ef2b012009-12-06 01:57:05 +0000381 buffer.
382
Ronald Cron3402aac2014-08-19 13:29:52 +0000383 @param Cmd Command line to return
AJFISH2ef2b012009-12-06 01:57:05 +0000384 @param CmdMaxSize Maximum size of Cmd
385
386 @return The Status of EblGetCharKey()
387
388**/
389EFI_STATUS
390GetCmd (
391 IN OUT CHAR8 *Cmd,
392 IN UINTN CmdMaxSize
393 )
394{
395 EFI_STATUS Status;
396 UINTN Index;
397 UINTN Index2;
398 CHAR8 Char;
399 CHAR8 *History;
400 EFI_INPUT_KEY Key;
401
402 for (Index = 0; Index < CmdMaxSize - 1;) {
403 Status = EblGetCharKey (&Key, 0, NULL);
404 if (EFI_ERROR (Status)) {
405 Cmd[Index] = '\0';
406 AsciiPrint ("\n");
407 return Status;
408 }
409
410 Char = (CHAR8)Key.UnicodeChar;
411 if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
412 Cmd[Index] = '\0';
413 if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
414 AsciiPrint ("\n\r");
415 }
416 return EFI_SUCCESS;
417 } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
418 if (Index != 0) {
419 Index--;
420 //
421 // Update the display
422 //
423 AsciiPrint ("\b \b");
424 }
425 } else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) {
426 History = GetCmdHistory (Key.ScanCode);
427 //
428 // Clear display line
429 //
430 for (Index2 = 0; Index2 < Index; Index2++) {
431 AsciiPrint ("\b \b");
432 }
433 AsciiPrint (History);
434 Index = AsciiStrLen (History);
435 AsciiStrnCpy (Cmd, History, CmdMaxSize);
436 } else {
437 Cmd[Index++] = Char;
438 if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
439 AsciiPrint ("%c", Char);
440 }
441 }
442 }
443
444 return EFI_SUCCESS;
445}
446
447
448/**
449 Print the boot up banner for the EBL.
450**/
451VOID
452EblPrintStartupBanner (
453 VOID
454 )
455{
456 AsciiPrint ("Embedded Boot Loader (");
457 EblSetTextColor (EFI_YELLOW);
458 AsciiPrint ("EBL");
459 EblSetTextColor (0);
460 AsciiPrint (") prototype. Built at %a on %a\n",__TIME__, __DATE__);
461 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");
andrewfishfc35d132010-01-31 01:46:17 +0000462 AsciiPrint ("Please send feedback to edk2-devel@lists.sourceforge.net\n");
AJFISH2ef2b012009-12-06 01:57:05 +0000463}
464
465
466/**
andrewfish884366c2010-05-11 00:09:48 +0000467 Send null requests to all removable media block IO devices so the a media add/remove/change
Ronald Cron3402aac2014-08-19 13:29:52 +0000468 can be detected in real before we execute a command.
andrewfish884366c2010-05-11 00:09:48 +0000469
Ronald Cron3402aac2014-08-19 13:29:52 +0000470 This is mainly due to the fact that the FAT driver does not do this today so you can get stale
andrewfish884366c2010-05-11 00:09:48 +0000471 dir commands after an SD Card has been removed.
472**/
473VOID
474EblProbeRemovableMedia (
475 VOID
476 )
477{
478 UINTN Index;
479 UINTN Max;
480 EFI_OPEN_FILE *File;
481
482 //
483 // Probe for media insertion/removal in removable media devices
484 //
485 Max = EfiGetDeviceCounts (EfiOpenBlockIo);
486 if (Max != 0) {
487 for (Index = 0; Index < Max; Index++) {
488 File = EfiDeviceOpenByType (EfiOpenBlockIo, Index);
489 if (File != NULL) {
490 if (File->FsBlockIoMedia->RemovableMedia) {
491 // Probe to see if media is present (or not) or media changed
492 // this causes the ReinstallProtocolInterface() to fire in the
493 // block io driver to update the system about media change events
494 File->FsBlockIo->ReadBlocks (File->FsBlockIo, File->FsBlockIo->Media->MediaId, (EFI_LBA)0, 0, NULL);
495 }
496 EfiClose (File);
497 }
498 }
499 }
500}
501
502
503
504
505/**
AJFISH2ef2b012009-12-06 01:57:05 +0000506 Print the prompt for the EBL.
507**/
508VOID
509EblPrompt (
510 VOID
511 )
512{
513 EblSetTextColor (EFI_YELLOW);
oliviermartine6b3b502011-06-11 11:28:59 +0000514 AsciiPrint ("%a %a",(CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt), EfiGetCwd ());
AJFISH2ef2b012009-12-06 01:57:05 +0000515 EblSetTextColor (0);
516 AsciiPrint ("%a", ">");
517}
518
519
520
521/**
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000522 Parse a command line and execute the commands. The ; separator allows
AJFISH2ef2b012009-12-06 01:57:05 +0000523 multiple commands for each command line. Stop processing if one of the
524 commands returns an error.
525
526 @param CmdLine Command Line to process.
Ronald Cron3402aac2014-08-19 13:29:52 +0000527 @param MaxCmdLineSize MaxSize of the Command line
AJFISH2ef2b012009-12-06 01:57:05 +0000528
529 @return EFI status of the Command
530
531**/
532EFI_STATUS
533ProcessCmdLine (
534 IN CHAR8 *CmdLine,
535 IN UINTN MaxCmdLineSize
536 )
537{
538 EFI_STATUS Status;
539 EBL_COMMAND_TABLE *Cmd;
540 CHAR8 *Ptr;
541 UINTN Argc;
542 CHAR8 *Argv[MAX_ARGS];
543
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000544 // Parse the command line. The loop processes commands separated by ;
AJFISH2ef2b012009-12-06 01:57:05 +0000545 for (Ptr = CmdLine, Status = EFI_SUCCESS; Ptr != NULL;) {
546 Ptr = ParseArguments (Ptr, &Argc, Argv);
547 if (Argc != 0) {
548 Cmd = EblGetCommand (Argv[0]);
549 if (Cmd != NULL) {
550 // Execute the Command!
551 Status = Cmd->Command (Argc, Argv);
552 if (Status == EFI_ABORTED) {
553 // exit command so lets exit
554 break;
555 } else if (Status == EFI_TIMEOUT) {
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000556 // pause command got input so don't process any more cmd on this cmd line
AJFISH2ef2b012009-12-06 01:57:05 +0000557 break;
558 } else if (EFI_ERROR (Status)) {
559 AsciiPrint ("%a returned %r error\n", Cmd->Name, Status);
560 // if any command fails stop processing CmdLine
561 break;
562 }
oliviermartin58174492012-05-02 20:19:52 +0000563 } else {
564 AsciiPrint ("The command '%a' is not supported.\n", Argv[0]);
Ronald Cron3402aac2014-08-19 13:29:52 +0000565 }
566 }
AJFISH2ef2b012009-12-06 01:57:05 +0000567 }
568
569 return Status;
570}
Ronald Cron3402aac2014-08-19 13:29:52 +0000571
AJFISH2ef2b012009-12-06 01:57:05 +0000572
573
574/**
Ronald Cron3402aac2014-08-19 13:29:52 +0000575 Embedded Boot Loader (EBL) - A simple EFI command line application for embedded
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000576 devices. PcdEmbeddedAutomaticBootCommand is a complied in command line that
577 gets executed automatically. The ; separator allows multiple commands
AJFISH2ef2b012009-12-06 01:57:05 +0000578 for each command line.
579
580 @param ImageHandle EFI ImageHandle for this application.
581 @param SystemTable EFI system table
582
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000583 @return EFI status of the application
AJFISH2ef2b012009-12-06 01:57:05 +0000584
585**/
586EFI_STATUS
587EFIAPI
588EdkBootLoaderEntry (
589 IN EFI_HANDLE ImageHandle,
590 IN EFI_SYSTEM_TABLE *SystemTable
Ronald Cron3402aac2014-08-19 13:29:52 +0000591 )
AJFISH2ef2b012009-12-06 01:57:05 +0000592{
593 EFI_STATUS Status;
594 CHAR8 CmdLine[MAX_CMD_LINE];
595 CHAR16 *CommandLineVariable = NULL;
596 CHAR16 *CommandLineVariableName = L"default-cmdline";
597 UINTN CommandLineVariableSize = 0;
598 EFI_GUID VendorGuid;
599
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000600 // Initialize tables of commands
AJFISH2ef2b012009-12-06 01:57:05 +0000601 EblInitializeCmdTable ();
602 EblInitializeDeviceCmd ();
603 EblInitializemdHwDebugCmds ();
604 EblInitializemdHwIoDebugCmds ();
605 EblInitializeDirCmd ();
606 EblInitializeHobCmd ();
607 EblInitializeScriptCmd ();
608 EblInitializeExternalCmd ();
609 EblInitializeNetworkCmd();
andrewfishfb334ef2011-02-01 05:37:22 +0000610 EblInitializeVariableCmds ();
Ronald Cron3402aac2014-08-19 13:29:52 +0000611
oliviermartind60b4c42011-07-01 14:37:16 +0000612 if (gST->ConOut == NULL) {
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000613 DEBUG((EFI_D_ERROR,"Error: No Console Output\n"));
oliviermartind60b4c42011-07-01 14:37:16 +0000614 return EFI_NOT_READY;
615 }
616
andrewfish16ccac42010-02-10 00:46:41 +0000617 // Disable the 5 minute EFI watchdog time so we don't get automatically reset
618 gBS->SetWatchdogTimer (0, 0, 0, NULL);
619
AJFISH2ef2b012009-12-06 01:57:05 +0000620 if (FeaturePcdGet (PcdEmbeddedMacBoot)) {
621 // A MAC will boot in graphics mode, so turn it back to text here
622 // This protocol was removed from edk2. It is only an edk thing. We need to make our own copy.
623 // DisableQuietBoot ();
624
625 // Enable the biggest output screen size possible
626 gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1);
627
AJFISH2ef2b012009-12-06 01:57:05 +0000628 }
629
630 // Save current screen mode
631 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows);
632
633 EblPrintStartupBanner ();
Ronald Cron3402aac2014-08-19 13:29:52 +0000634
oliviermartin7ca9e5a2011-08-08 18:29:14 +0000635 // Parse command line and handle commands separated by ;
AJFISH2ef2b012009-12-06 01:57:05 +0000636 // The loop prints the prompt gets user input and saves history
Ronald Cron3402aac2014-08-19 13:29:52 +0000637
AJFISH2ef2b012009-12-06 01:57:05 +0000638 // Look for a variable with a default command line, otherwise use the Pcd
639 ZeroMem(&VendorGuid, sizeof(EFI_GUID));
640
641 Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
642 if (Status == EFI_BUFFER_TOO_SMALL) {
643 CommandLineVariable = AllocatePool(CommandLineVariableSize);
Ronald Cron3402aac2014-08-19 13:29:52 +0000644
AJFISH2ef2b012009-12-06 01:57:05 +0000645 Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable);
646 if (!EFI_ERROR(Status)) {
647 UnicodeStrToAsciiStr(CommandLineVariable, CmdLine);
648 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000649
AJFISH2ef2b012009-12-06 01:57:05 +0000650 FreePool(CommandLineVariable);
651 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000652
AJFISH2ef2b012009-12-06 01:57:05 +0000653 if (EFI_ERROR(Status)) {
654 AsciiStrCpy (CmdLine, (CHAR8 *)PcdGetPtr (PcdEmbeddedAutomaticBootCommand));
655 }
Ronald Cron3402aac2014-08-19 13:29:52 +0000656
AJFISH2ef2b012009-12-06 01:57:05 +0000657 for (;;) {
658 Status = ProcessCmdLine (CmdLine, MAX_CMD_LINE);
659 if (Status == EFI_ABORTED) {
660 // if a command returns EFI_ABORTED then exit the EBL
661 EblShutdownExternalCmdTable ();
662 return EFI_SUCCESS;
663 }
664
665 // get the command line from the user
666 EblPrompt ();
667 GetCmd (CmdLine, MAX_CMD_LINE);
668 SetCmdHistory (CmdLine);
andrewfish884366c2010-05-11 00:09:48 +0000669
670 if (FeaturePcdGet (PcdEmbeddedProbeRemovable)) {
671 // Probe removable media devices to see if media has been inserted or removed.
672 EblProbeRemovableMedia ();
673 }
AJFISH2ef2b012009-12-06 01:57:05 +0000674 }
675}
676
677