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