73122e68a36f7633d56ad107ead500f1eaefa4fd
[mirror_edk2.git] / EmbeddedPkg / Ebl / Command.c
1 /** @file
2 Basic commands and command processing infrastructure for EBL
3
4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Ebl.h"
18 #include <Protocol/DiskIo.h>
19 #include <Protocol/BlockIo.h>
20
21 UINTN mCmdTableMaxIndex = EBL_MAX_COMMAND_COUNT;
22 UINTN mCmdTableNextFreeIndex = 0;
23 EBL_COMMAND_TABLE *mCmdTable[EBL_MAX_COMMAND_COUNT];
24
25 /**
26 Converts a lowercase Ascii character to upper one
27
28 If Chr is lowercase Ascii character, then converts it to upper one.
29
30 If Value >= 0xA0, then ASSERT().
31 If (Value & 0x0F) >= 0x0A, then ASSERT().
32
33 @param chr one Ascii character
34
35 @return The uppercase value of Ascii character
36
37 **/
38 STATIC
39 CHAR8
40 AsciiToUpper (
41 IN CHAR8 Chr
42 )
43 {
44 return (UINT8) ((Chr >= 'a' && Chr <= 'z') ? Chr - ('a' - 'A') : Chr);
45 }
46
47
48 /**
49 Case insensitve comparison of two Null-terminated Unicode strings with maximum
50 lengths, and returns the difference between the first mismatched Unicode
51 characters.
52 This function compares the Null-terminated Unicode string FirstString to the
53 Null-terminated Unicode string SecondString. At most, Length Unicode
54 characters will be compared. If Length is 0, then 0 is returned. If
55 FirstString is identical to SecondString, then 0 is returned. Otherwise, the
56 value returned is the first mismatched Unicode character in SecondString
57 subtracted from the first mismatched Unicode character in FirstString.
58
59 @param FirstString Pointer to a Null-terminated ASCII string.
60 @param SecondString Pointer to a Null-terminated ASCII string.
61 @param Length Max length to compare.
62
63 @retval 0 FirstString is identical to SecondString using case insensitive
64 comparisons.
65 @retval !=0 FirstString is not identical to SecondString using case
66 insensitive comparisons.
67
68 **/
69 INTN
70 EFIAPI
71 AsciiStrniCmp (
72 IN CONST CHAR8 *FirstString,
73 IN CONST CHAR8 *SecondString,
74 IN UINTN Length
75 )
76 {
77 if (Length == 0) {
78 return 0;
79 }
80
81 while ((AsciiToUpper (*FirstString) != '\0') &&
82 (AsciiToUpper (*FirstString) == AsciiToUpper (*SecondString)) &&
83 (Length > 1)) {
84 FirstString++;
85 SecondString++;
86 Length--;
87 }
88
89 return AsciiToUpper (*FirstString) - AsciiToUpper (*SecondString);
90 }
91
92
93
94 /**
95 Add a command to the mCmdTable. If there is no free space in the command
96 table ASSERT. The mCmdTable is maintained in alphabetical order and the
97 new entry is inserted into its sorted possition.
98
99 @param Entry Commnad Entry to add to the CmdTable
100
101 **/
102 VOID
103 EFIAPI
104 EblAddCommand (
105 IN const EBL_COMMAND_TABLE *Entry
106 )
107 {
108 UINTN Count;
109
110 if (mCmdTableNextFreeIndex == EBL_MAX_COMMAND_COUNT) {
111 //
112 // Ran out of space to store commands. Increase EBL_MAX_COMMAND_COUNT
113 //
114 ASSERT (FALSE);
115 return;
116 }
117
118 //
119 // Add command and Insertion sort array in the process
120 //
121 mCmdTable[mCmdTableNextFreeIndex] = (EBL_COMMAND_TABLE *)Entry;
122 if (mCmdTableNextFreeIndex != 0) {
123 for (Count = mCmdTableNextFreeIndex; Count > 0; Count--) {
124 if (AsciiStriCmp (mCmdTable[Count - 1]->Name, Entry->Name) <= 0) {
125 break;
126 }
127
128 mCmdTable[Count] = mCmdTable[Count - 1];
129 }
130 mCmdTable[Count] = (EBL_COMMAND_TABLE *)Entry;
131 }
132
133 mCmdTableNextFreeIndex++;
134 }
135
136
137 /**
138 Add an set of commands to the command table. Most commonly used on static
139 array of commands.
140
141 @param EntryArray Pointer to array of command entries
142 @param ArrayCount Number of commnad entries to add
143
144 **/
145 VOID
146 EFIAPI
147 EblAddCommands (
148 IN const EBL_COMMAND_TABLE *EntryArray,
149 IN UINTN ArrayCount
150 )
151 {
152 UINTN Index;
153
154 for (Index = 0; Index < ArrayCount; Index++) {
155 EblAddCommand (&EntryArray[Index]);
156 }
157 }
158
159
160 EBL_ADD_COMMAND_PROTOCOL gEblAddCommand = {
161 EblAddCommand,
162 EblAddCommands,
163 EblGetCharKey,
164 EblAnyKeyToContinueQtoQuit
165 };
166
167
168
169 /**
170 Return the best matching command for the passed in command name. The match
171 does not have to be exact, it just needs to be unqiue. This enables commands
172 to be shortend to the smallest set of starting characters that is unique.
173
174 @param CommandName Name of command to search for
175
176 @return NULL CommandName did not match or was not unique
177 Other Pointer to EBL_COMMAND_TABLE entry for CommandName
178
179 **/
180 EBL_COMMAND_TABLE *
181 EblGetCommand (
182 IN CHAR8 *CommandName
183 )
184 {
185 UINTN Index;
186 UINTN BestMatchCount;
187 UINTN Length;
188 EBL_COMMAND_TABLE *Match;
189 CHAR8 *Str;
190
191 Length = AsciiStrLen (CommandName);
192 Str = AsciiStrStr (CommandName, ".");
193 if (Str != NULL) {
194 // If the command includes a trailing . command extension skip it for the match.
195 // Example: hexdump.4
196 Length = (UINTN)(Str - CommandName);
197 }
198
199 for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) {
200 if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) {
201 // match a command exactly
202 return mCmdTable[Index];
203 }
204
205 if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) {
206 // partial match, so keep looking to make sure there is only one partial match
207 BestMatchCount++;
208 Match = mCmdTable[Index];
209 }
210 }
211
212 if (BestMatchCount == 1) {
213 return Match;
214 }
215
216 //
217 // We had no matches or too many matches
218 //
219 return NULL;
220 }
221
222
223 UINTN
224 CountNewLines (
225 IN CHAR8 *Str
226 )
227 {
228 UINTN Count;
229
230 if (Str == NULL) {
231 return 0;
232 }
233
234 for (Count = 0; *Str != '\0'; Str++) {
235 if (Str[Count] == '\n') {
236 Count++;
237 }
238 }
239
240 return Count;
241 }
242
243
244 /**
245 List out help information on all the commands or print extended information
246 about a specific passed in command.
247
248 Argv[0] - "help"
249 Argv[1] - Command to display help about
250
251 @param Argc Number of command arguments in Argv
252 @param Argv Array of strings that represent the parsed command line.
253 Argv[0] is the comamnd name
254
255 @return EFI_SUCCESS
256
257 **/
258 EFI_STATUS
259 EblHelpCmd (
260 IN UINTN Argc,
261 IN CHAR8 **Argv
262 )
263 {
264 UINTN Index;
265 CHAR8 *Ptr;
266 UINTN CurrentRow = 0;
267
268 if (Argc == 1) {
269 // Print all the commands
270 AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n");
271 CurrentRow++;
272 for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) {
273 EblSetTextColor (EFI_YELLOW);
274 AsciiPrint (" %a", mCmdTable[Index]->Name);
275 EblSetTextColor (0);
276 AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary);
277 // Handle multi line help summaries
278 CurrentRow += CountNewLines (mCmdTable[Index]->HelpSummary);
279 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
280 break;
281 }
282 }
283 } else if (Argv[1] != NULL) {
284 // Print specific help
285 for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) {
286 if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) {
287 Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help;
288 AsciiPrint ("%a%a\n", Argv[1], Ptr);
289 // Handle multi line help summaries
290 CurrentRow += CountNewLines (Ptr);
291 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
292 break;
293 }
294 }
295 }
296 }
297
298 return EFI_SUCCESS;
299 }
300
301
302 /**
303 Exit the EBL. If the commnad processor sees EFI_ABORTED return status it will
304 exit the EBL.
305
306 Argv[0] - "exit"
307
308 @param Argc Number of command arguments in Argv
309 @param Argv Array of strings that represent the parsed command line.
310 Argv[0] is the comamnd name
311
312 @return EFI_ABORTED
313
314 **/
315 EFI_STATUS
316 EblExitCmd (
317 IN UINTN Argc,
318 IN CHAR8 **Argv
319 )
320 {
321 EFI_STATUS Status;
322 UINTN MemoryMapSize;
323 EFI_MEMORY_DESCRIPTOR *MemoryMap;
324 UINTN MapKey;
325 UINTN DescriptorSize;
326 UINT32 DescriptorVersion;
327 UINTN Pages;
328
329 if (Argc > 1) {
330 if (AsciiStriCmp (Argv[1], "efi") != 0) {
331 return EFI_ABORTED;
332 }
333 } else if (Argc == 1) {
334 return EFI_ABORTED;
335 }
336
337 MemoryMap = NULL;
338 MemoryMapSize = 0;
339 do {
340 Status = gBS->GetMemoryMap (
341 &MemoryMapSize,
342 MemoryMap,
343 &MapKey,
344 &DescriptorSize,
345 &DescriptorVersion
346 );
347 if (Status == EFI_BUFFER_TOO_SMALL) {
348
349 Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
350 MemoryMap = AllocatePages (Pages);
351
352 //
353 // Get System MemoryMap
354 //
355 Status = gBS->GetMemoryMap (
356 &MemoryMapSize,
357 MemoryMap,
358 &MapKey,
359 &DescriptorSize,
360 &DescriptorVersion
361 );
362 // Don't do anything between the GetMemoryMap() and ExitBootServices()
363 if (!EFI_ERROR (Status)) {
364 Status = gBS->ExitBootServices (gImageHandle, MapKey);
365 if (EFI_ERROR (Status)) {
366 FreePages (MemoryMap, Pages);
367 MemoryMap = NULL;
368 MemoryMapSize = 0;
369 }
370 }
371 }
372 } while (EFI_ERROR (Status));
373
374 //
375 // At this point it is very dangerous to do things EFI as most of EFI is now gone.
376 // This command is useful if you are working with a debugger as it will shutdown
377 // DMA and other things that could break a soft resets.
378 //
379 CpuDeadLoop ();
380
381 // Should never get here, but makes the compiler happy
382 return EFI_ABORTED;
383 }
384
385
386 /**
387 Update the screen by decrementing the timeout value.
388 This AsciiPrint has to match the AsciiPrint in
389 EblPauseCmd.
390
391 @param ElaspedTime Current timout value remaining
392
393 **/
394 VOID
395 EFIAPI
396 EblPauseCallback (
397 IN UINTN ElapsedTime
398 )
399 {
400 AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime);
401 }
402
403 /**
404 Pause until a key is pressed and abort the remaining commands on the command
405 line. If no key is pressed continue processing the command line. This command
406 allows the user to stop an operation from happening and return control to the
407 command prompt.
408
409 Argv[0] - "pause"
410 Argv[1] - timeout value is decimal seconds
411
412 @param Argc Number of command arguments in Argv
413 @param Argv Array of strings that represent the parsed command line.
414 Argv[0] is the comamnd name
415
416 @return EFI_SUCCESS Timeout expired with no input
417 @return EFI_TIMEOUT Stop procesing other commands on the same command line
418
419 **/
420 EFI_STATUS
421 EblPauseCmd (
422 IN UINTN Argc,
423 IN CHAR8 **Argv
424 )
425 {
426 EFI_STATUS Status;
427 UINTN Delay;
428 EFI_INPUT_KEY Key;
429
430 Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
431
432 AsciiPrint ("Hit any key to break. You have %3d seconds", Delay);
433 Status = EblGetCharKey (&Key, Delay, EblPauseCallback);
434 AsciiPrint ("\n");
435
436 // If we timeout then the pause succeded thus return success
437 // If we get a key return timout to stop other commnad on this cmd line
438 return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;;
439 }
440
441
442 /**
443 On a debug build issue a software breakpoint to enter the debugger
444
445 Argv[0] - "break"
446
447 @param Argc Number of command arguments in Argv
448 @param Argv Array of strings that represent the parsed command line.
449 Argv[0] is the comamnd name
450
451 @return EFI_SUCCESS
452
453 **/
454 EFI_STATUS
455 EblBreakPointCmd (
456 IN UINTN Argc,
457 IN CHAR8 **Argv
458 )
459 {
460 CpuBreakpoint ();
461 return EFI_SUCCESS;
462 }
463
464
465 /**
466 Reset the system. If no Argument do a Cold reset. If argument use that reset type
467 (W)arm = Warm Reset
468 (S)hutdown = Shutdown Reset
469
470 Argv[0] - "reset"
471 Argv[1] - warm or shutdown reset type
472
473 @param Argc Number of command arguments in Argv
474 @param Argv Array of strings that represent the parsed command line.
475 Argv[0] is the comamnd name
476
477 @return EFI_SUCCESS
478
479 **/
480 EFI_STATUS
481 EblResetCmd (
482 IN UINTN Argc,
483 IN CHAR8 **Argv
484 )
485 {
486 EFI_RESET_TYPE ResetType;
487
488 ResetType = EfiResetCold;
489 if (Argc > 1) {
490 switch (*Argv[1]) {
491 case 'W':
492 case 'w':
493 ResetType = EfiResetWarm;
494 break;
495 case 'S':
496 case 's':
497 ResetType = EfiResetShutdown;
498 }
499 }
500
501 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
502 return EFI_SUCCESS;
503 }
504
505
506 /**
507 Toggle page break global. This turns on and off prompting to Quit or hit any
508 key to continue when a command is about to scroll the screen with its output
509
510 Argv[0] - "page"
511 Argv[1] - on or off
512
513 @param Argc Number of command arguments in Argv
514 @param Argv Array of strings that represent the parsed command line.
515 Argv[0] is the comamnd name
516
517 @return EFI_SUCCESS
518
519 **/
520 EFI_STATUS
521 EblPageCmd (
522 IN UINTN Argc,
523 IN CHAR8 **Argv
524 )
525 {
526 if (Argc <= 1) {
527 // toggle setting
528 gPageBreak = (gPageBreak) ? FALSE : TRUE;
529 } else {
530 // use argv to set the value
531 if ((Argv[1][0] == 'o') || (Argv[1][0] == 'O')) {
532 if ((Argv[1][1] == 'n') || (Argv[1][1] == 'N')) {
533 gPageBreak = TRUE;
534 } else if ((Argv[1][1] == 'f') || (Argv[1][1] == 'F')) {
535 gPageBreak = FALSE;
536 } else {
537 return EFI_INVALID_PARAMETER;
538 }
539 }
540 }
541 return EFI_SUCCESS;
542 }
543
544 EFI_STATUS
545 EblSleepCmd (
546 IN UINTN Argc,
547 IN CHAR8 **Argv
548 )
549 {
550 UINTN Delay;
551
552 Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
553
554 gBS->Stall (Delay * 1000000);
555
556 return EFI_SUCCESS;
557 }
558
559 CHAR8
560 ConvertToTextLine (
561 IN CHAR8 Character
562 )
563 {
564 if (Character < ' ' || Character > '~') {
565 return '.';
566 } else {
567 return Character;
568 }
569 }
570
571 UINTN
572 GetBytes (
573 IN UINT8 *Address,
574 IN UINTN Bytes
575 )
576 {
577 UINTN Result = 0;
578
579 if (Bytes >= 1) {
580 Result = *Address++;
581 }
582 if (Bytes >= 2) {
583 Result = (Result << 8) + *Address++;
584 }
585 if (Bytes >= 3) {
586 Result = (Result << 8) + *Address++;
587 }
588 return Result;
589 }
590
591 CHAR8 mBlanks[] = " ";
592
593 EFI_STATUS
594 OutputData (
595 IN UINT8 *Address,
596 IN UINTN Length,
597 IN UINTN Width,
598 IN UINTN Offset
599 )
600 {
601 UINT8 *EndAddress;
602 UINTN Line;
603 CHAR8 TextLine[0x11];
604 UINTN CurrentRow = 0;
605 UINTN Bytes;
606 UINTN Spaces = 0;
607 CHAR8 Blanks[80];
608
609 AsciiStrCpy (Blanks, mBlanks);
610 for (EndAddress = Address + Length; Address < EndAddress; Offset += Line) {
611 AsciiPrint ("%08x: ", Offset);
612 for (Line = 0; (Line < 0x10) && (Address < EndAddress);) {
613 Bytes = EndAddress - Address;
614
615 switch (Width) {
616 case 4:
617 if (Bytes >= 4) {
618 AsciiPrint ("%08x ", *((UINT32 *)Address));
619 TextLine[Line++] = ConvertToTextLine(*Address++);
620 TextLine[Line++] = ConvertToTextLine(*Address++);
621 TextLine[Line++] = ConvertToTextLine(*Address++);
622 TextLine[Line++] = ConvertToTextLine(*Address++);
623 } else {
624 AsciiPrint ("%08x ", GetBytes(Address, Bytes));
625 Address += Bytes;
626 Line += Bytes;
627 }
628 break;
629
630 case 2:
631 if (Bytes >= 2) {
632 AsciiPrint ("%04x ", *((UINT16 *)Address));
633 TextLine[Line++] = ConvertToTextLine(*Address++);
634 TextLine[Line++] = ConvertToTextLine(*Address++);
635 } else {
636 AsciiPrint ("%04x ", GetBytes(Address, Bytes));
637 Address += Bytes;
638 Line += Bytes;
639 }
640 break;
641
642 case 1:
643 AsciiPrint ("%02x ", *((UINT8 *)Address));
644 TextLine[Line++] = ConvertToTextLine(*Address++);
645 break;
646
647 default:
648 AsciiPrint ("Width must be 1, 2, or 4!\n");
649 return EFI_INVALID_PARAMETER;
650 }
651 }
652
653 // Pad spaces
654 if (Line < 0x10) {
655 switch (Width) {
656 case 4:
657 Spaces = 9 * ((0x10 - Line)/4);
658 break;
659 case 2:
660 Spaces = 5 * ((0x10 - Line)/2);
661 break;
662 case 1:
663 Spaces = 3 * (0x10 - Line);
664 break;
665 }
666
667 Blanks[Spaces] = '\0';
668
669 AsciiPrint(Blanks);
670
671 Blanks[Spaces] = ' ';
672 }
673
674 TextLine[Line] = 0;
675 AsciiPrint ("|%a|\n", TextLine);
676
677 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
678 return EFI_END_OF_FILE;
679 }
680 }
681
682 if (Length % Width != 0) {
683 AsciiPrint ("%08x\n", Offset);
684 }
685
686 return EFI_SUCCESS;
687 }
688
689
690 /**
691 See if command contains .# where # is a number. Return # as the Width
692 or 1 as the default Width for commands.
693
694 Example hexdump.4 returns a width of 4.
695
696 @param Argv Argv[0] is the comamnd name
697
698 @return Width of command
699
700 **/
701 UINTN
702 WidthFromCommandName (
703 IN CHAR8 *Argv,
704 IN UINTN Default
705 )
706 {
707 CHAR8 *Str;
708 UINTN Width;
709
710 //Hexdump.2 HexDump.4 mean use a different width
711 Str = AsciiStrStr (Argv, ".");
712 if (Str != NULL) {
713 Width = AsciiStrDecimalToUintn (Str + 1);
714 if (Width == 0) {
715 Width = Default;
716 }
717 } else {
718 // Default answer
719 return Default;
720 }
721
722 return Width;
723 }
724
725 #define HEXDUMP_CHUNK 1024
726
727 /**
728 Toggle page break global. This turns on and off prompting to Quit or hit any
729 key to continue when a command is about to scroll the screen with its output
730
731 Argv[0] - "hexdump"[.#] # is optional 1,2, or 4 for width
732 Argv[1] - Device or File to dump.
733 Argv[2] - Optional offset to start dumping
734 Argv[3] - Optional number of bytes to dump
735
736 @param Argc Number of command arguments in Argv
737 @param Argv Array of strings that represent the parsed command line.
738 Argv[0] is the comamnd name
739
740 @return EFI_SUCCESS
741
742 **/
743 EFI_STATUS
744 EblHexdumpCmd (
745 IN UINTN Argc,
746 IN CHAR8 **Argv
747 )
748 {
749 EFI_OPEN_FILE *File;
750 VOID *Location;
751 UINTN Size;
752 UINTN Width;
753 UINTN Offset = 0;
754 EFI_STATUS Status;
755 UINTN Chunk = HEXDUMP_CHUNK;
756
757 if ((Argc < 2) || (Argc > 4)) {
758 return EFI_INVALID_PARAMETER;
759 }
760
761 Width = WidthFromCommandName (Argv[0], 1);
762 if ((Width != 1) && (Width != 2) && (Width != 4)) {
763 return EFI_INVALID_PARAMETER;
764 }
765
766 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
767 if (File == NULL) {
768 return EFI_NOT_FOUND;
769 }
770
771 Location = AllocatePool (Chunk);
772 Size = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : EfiTell (File, NULL);
773
774 Offset = 0;
775 if (Argc > 2) {
776 Offset = AsciiStrHexToUintn (Argv[2]);
777 if (Offset > 0) {
778 // Make sure size includes the part of the file we have skipped
779 Size += Offset;
780 }
781 }
782
783 Status = EfiSeek (File, Offset, EfiSeekStart);
784 if (EFI_ERROR (Status)) {
785 goto Exit;
786 }
787
788 for (; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk) {
789 Chunk = HEXDUMP_CHUNK;
790 Status = EfiRead (File, Location, &Chunk);
791 if (EFI_ERROR(Status)) {
792 AsciiPrint ("Error reading file content\n");
793 goto Exit;
794 }
795
796 Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);
797 if (EFI_ERROR(Status)) {
798 if (Status == EFI_END_OF_FILE) {
799 Status = EFI_SUCCESS;
800 }
801 goto Exit;
802 }
803 }
804
805 // Any left over?
806 if (Offset < Size) {
807 Chunk = Size - Offset;
808 Status = EfiRead (File, Location, &Chunk);
809 if (EFI_ERROR(Status)) {
810 AsciiPrint ("Error reading file content\n");
811 goto Exit;
812 }
813
814 Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);
815 if (EFI_ERROR(Status)) {
816 if (Status == EFI_END_OF_FILE) {
817 Status = EFI_SUCCESS;
818 }
819 goto Exit;
820 }
821 }
822
823 Exit:
824 EfiClose (File);
825
826 FreePool (Location);
827
828 return EFI_SUCCESS;
829 }
830
831
832 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdTemplate[] =
833 {
834 {
835 "reset",
836 " [type]; Reset system. type = [warm] [shutdown] default is cold reset",
837 NULL,
838 EblResetCmd
839 },
840 {
841 "exit",
842 "; Exit EBL",
843 NULL,
844 EblExitCmd
845 },
846 {
847 "help",
848 " [cmd]; Help on cmd or a list of all commands if cmd is ommited",
849 NULL,
850 EblHelpCmd
851 },
852 {
853 "break",
854 "; Generate debugging breakpoint",
855 NULL,
856 EblBreakPointCmd
857 },
858 {
859 "page",
860 " [on|off]]; toggle promting on command output larger than screen",
861 NULL,
862 EblPageCmd
863 },
864 {
865 "pause",
866 " [sec]; Pause for sec[10] seconds. ",
867 NULL,
868 EblPauseCmd
869 },
870 {
871 "sleep",
872 " [sec]; Sleep for sec[10] seconds. ",
873 NULL,
874 EblSleepCmd
875 },
876 {
877 "hexdump",
878 "[.{1|2|4}] filename [Offset] [Size]; dump a file as hex .width",
879 NULL,
880 EblHexdumpCmd
881 }
882 };
883
884
885 EFI_HANDLE gExternalCmdHandle = NULL;
886
887 /**
888 Initialize the commands in this in this file
889 **/
890 VOID
891 EblInitializeCmdTable (
892 VOID
893 )
894 {
895
896 EblAddCommands (mCmdTemplate, sizeof (mCmdTemplate)/sizeof (EBL_COMMAND_TABLE));
897
898 gBS->InstallProtocolInterface (
899 &gExternalCmdHandle,
900 &gEfiEblAddCommandProtocolGuid,
901 EFI_NATIVE_INTERFACE,
902 &gEblAddCommand
903 );
904
905 }
906
907
908 VOID
909 EblShutdownExternalCmdTable (
910 VOID
911 )
912 {
913 gBS->UninstallProtocolInterface (gExternalCmdHandle, &gEfiEblAddCommandProtocolGuid, &gEblAddCommand);
914 }
915
916