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 926