Updated to support passing PE/COFF and LZMA decompress up via HOBS. Currently turned...
[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<BR>
5 Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
6
7 All rights reserved. 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
190 Length = AsciiStrLen (CommandName);
191 for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) {
192 if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) {
193 // match a command exactly
194 return mCmdTable[Index];
195 }
196
197 if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) {
198 // partial match, so keep looking to make sure there is only one partial match
199 BestMatchCount++;
200 Match = mCmdTable[Index];
201 }
202 }
203
204 if (BestMatchCount == 1) {
205 return Match;
206 }
207
208 //
209 // We had no matches or too many matches
210 //
211 return NULL;
212 }
213
214
215
216 /**
217 List out help information on all the commands or print extended information
218 about a specific passed in command.
219
220 Argv[0] - "help"
221 Argv[1] - Command to display help about
222
223 @param Argc Number of command arguments in Argv
224 @param Argv Array of strings that represent the parsed command line.
225 Argv[0] is the comamnd name
226
227 @return EFI_SUCCESS
228
229 **/
230 EFI_STATUS
231 EblHelpCmd (
232 IN UINTN Argc,
233 IN CHAR8 **Argv
234 )
235 {
236 UINTN Index;
237 CHAR8 *Ptr;
238 UINTN CurrentRow;
239
240 if (Argc == 1) {
241 // Print all the commands
242 AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n");
243 for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) {
244 EblSetTextColor (EFI_YELLOW);
245 AsciiPrint (" %a", mCmdTable[Index]->Name);
246 EblSetTextColor (0);
247 AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary);
248 }
249 } else if (Argv[1] != NULL) {
250 // Print specific help
251 for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) {
252 if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) {
253 Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help;
254 AsciiPrint ("%a%a\n", Argv[1], Ptr);
255 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
256 break;
257 }
258 }
259 }
260 }
261
262 return EFI_SUCCESS;
263 }
264
265
266 /**
267 Exit the EBL. If the commnad processor sees EFI_ABORTED return status it will
268 exit the EBL.
269
270 Argv[0] - "exit"
271
272 @param Argc Number of command arguments in Argv
273 @param Argv Array of strings that represent the parsed command line.
274 Argv[0] is the comamnd name
275
276 @return EFI_ABORTED
277
278 **/
279 EFI_STATUS
280 EblExitCmd (
281 IN UINTN Argc,
282 IN CHAR8 **Argv
283 )
284 {
285 EFI_STATUS Status;
286 UINTN MemoryMapSize;
287 EFI_MEMORY_DESCRIPTOR *MemoryMap;
288 UINTN MapKey;
289 UINTN DescriptorSize;
290 UINTN DescriptorVersion;
291 UINTN Pages;
292
293 if (Argc > 1) {
294 if (AsciiStriCmp (Argv[1], "efi") != 0) {
295 return EFI_ABORTED;
296 }
297 } else if (Argc == 1) {
298 return EFI_ABORTED;
299 }
300
301 MemoryMap = NULL;
302 MemoryMapSize = 0;
303 do {
304 Status = gBS->GetMemoryMap (
305 &MemoryMapSize,
306 MemoryMap,
307 &MapKey,
308 &DescriptorSize,
309 &DescriptorVersion
310 );
311 if (Status == EFI_BUFFER_TOO_SMALL) {
312
313 Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
314 MemoryMap = AllocatePages (Pages);
315
316 //
317 // Get System MemoryMap
318 //
319 Status = gBS->GetMemoryMap (
320 &MemoryMapSize,
321 MemoryMap,
322 &MapKey,
323 &DescriptorSize,
324 &DescriptorVersion
325 );
326 // Don't do anything between the GetMemoryMap() and ExitBootServices()
327 if (!EFI_ERROR (Status)) {
328 Status = gBS->ExitBootServices (gImageHandle, MapKey);
329 if (EFI_ERROR (Status)) {
330 FreePages (MemoryMap, Pages);
331 MemoryMap = NULL;
332 MemoryMapSize = 0;
333 }
334 }
335 }
336 } while (EFI_ERROR (Status));
337
338 //
339 // At this point it is very dangerous to do things EFI as most of EFI is now gone.
340 // This command is useful if you are working with a debugger as it will shutdown
341 // DMA and other things that could break a soft resets.
342 //
343 CpuDeadLoop ();
344
345 // Should never get here, but makes the compiler happy
346 return EFI_ABORTED;
347 }
348
349
350 /**
351 Update the screen by decrementing the timeout value.
352 This AsciiPrint has to match the AsciiPrint in
353 EblPauseCmd.
354
355 @param ElaspedTime Current timout value remaining
356
357 **/
358 VOID
359 EFIAPI
360 EblPauseCallback (
361 IN UINTN ElapsedTime
362 )
363 {
364 AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime);
365 }
366
367 /**
368 Pause until a key is pressed and abort the remaining commands on the command
369 line. If no key is pressed continue processing the command line. This command
370 allows the user to stop an operation from happening and return control to the
371 command prompt.
372
373 Argv[0] - "pause"
374 Argv[1] - timeout value is decimal seconds
375
376 @param Argc Number of command arguments in Argv
377 @param Argv Array of strings that represent the parsed command line.
378 Argv[0] is the comamnd name
379
380 @return EFI_SUCCESS Timeout expired with no input
381 @return EFI_TIMEOUT Stop procesing other commands on the same command line
382
383 **/
384 EFI_STATUS
385 EblPauseCmd (
386 IN UINTN Argc,
387 IN CHAR8 **Argv
388 )
389 {
390 EFI_STATUS Status;
391 UINTN Delay;
392 EFI_INPUT_KEY Key;
393
394 Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
395
396 AsciiPrint ("Hit any key to break. You have %3d seconds", Delay);
397 Status = EblGetCharKey (&Key, Delay, EblPauseCallback);
398 AsciiPrint ("\n");
399
400 // If we timeout then the pause succeded thus return success
401 // If we get a key return timout to stop other commnad on this cmd line
402 return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;;
403 }
404
405
406 /**
407 On a debug build issue a software breakpoint to enter the debugger
408
409 Argv[0] - "break"
410
411 @param Argc Number of command arguments in Argv
412 @param Argv Array of strings that represent the parsed command line.
413 Argv[0] is the comamnd name
414
415 @return EFI_SUCCESS
416
417 **/
418 EFI_STATUS
419 EblBreakPointCmd (
420 IN UINTN Argc,
421 IN CHAR8 **Argv
422 )
423 {
424 CpuBreakpoint ();
425 return EFI_SUCCESS;
426 }
427
428
429 /**
430 Reset the system. If no Argument do a Cold reset. If argument use that reset type
431 (W)arm = Warm Reset
432 (S)hutdown = Shutdown Reset
433
434 Argv[0] - "reset"
435 Argv[1] - warm or shutdown reset type
436
437 @param Argc Number of command arguments in Argv
438 @param Argv Array of strings that represent the parsed command line.
439 Argv[0] is the comamnd name
440
441 @return EFI_SUCCESS
442
443 **/
444 EFI_STATUS
445 EblResetCmd (
446 IN UINTN Argc,
447 IN CHAR8 **Argv
448 )
449 {
450 EFI_RESET_TYPE ResetType;
451
452 ResetType = EfiResetCold;
453 if (Argc > 1) {
454 switch (*Argv[1]) {
455 case 'W':
456 case 'w':
457 ResetType = EfiResetWarm;
458 break;
459 case 'S':
460 case 's':
461 ResetType = EfiResetShutdown;
462 }
463 }
464
465 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
466 return EFI_SUCCESS;
467 }
468
469
470 /**
471 Toggle page break global. This turns on and off prompting to Quit or hit any
472 key to continue when a command is about to scroll the screen with its output
473
474 Argv[0] - "page"
475 Argv[1] - on or off
476
477 @param Argc Number of command arguments in Argv
478 @param Argv Array of strings that represent the parsed command line.
479 Argv[0] is the comamnd name
480
481 @return EFI_SUCCESS
482
483 **/
484 EFI_STATUS
485 EblPageCmd (
486 IN UINTN Argc,
487 IN CHAR8 **Argv
488 )
489 {
490 if (Argc <= 1) {
491 // toggle setting
492 gPageBreak = (gPageBreak) ? FALSE : TRUE;
493 } else {
494 // use argv to set the value
495 if ((Argv[1][0] == 'o') || (Argv[1][0] == 'O')) {
496 if ((Argv[1][1] == 'n') || (Argv[1][1] == 'N')) {
497 gPageBreak = TRUE;
498 } else if ((Argv[1][1] == 'f') || (Argv[1][1] == 'F')) {
499 gPageBreak = FALSE;
500 } else {
501 return EFI_INVALID_PARAMETER;
502 }
503 }
504 }
505 return EFI_SUCCESS;
506 }
507
508 EFI_STATUS
509 EblSleepCmd (
510 IN UINTN Argc,
511 IN CHAR8 **Argv
512 )
513 {
514 UINTN Delay;
515
516 Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);
517
518 gBS->Stall (Delay * 1000000);
519
520 return EFI_SUCCESS;
521 }
522
523 CHAR8
524 ConvertToTextLine (
525 IN CHAR8 Character
526 )
527 {
528 if (Character < ' ' || Character > '~')
529 {
530 return '.';
531 }
532 else
533 {
534 return Character;
535 }
536 }
537
538 UINTN
539 GetBytes (
540 IN UINT8 *Address,
541 IN UINTN Bytes
542 )
543 {
544 UINTN Result = 0;
545
546 if (Bytes >= 1)
547 Result = *Address++;
548
549 if (Bytes >= 2)
550 Result = (Result << 8) + *Address++;
551
552 if (Bytes >= 3)
553 Result = (Result << 8) + *Address++;
554
555 return Result;
556 }
557
558 CHAR8 mBlanks[] = " ";
559
560 EFI_STATUS
561 OutputData (
562 IN UINT8 *Address,
563 IN UINTN Length,
564 IN UINTN Width,
565 IN UINTN Offset
566 )
567 {
568 UINT8 *EndAddress;
569 UINTN Line;
570 CHAR8 TextLine[0x11];
571 UINTN CurrentRow = 0;
572 UINTN Bytes;
573 UINTN Spaces = 0;
574 CHAR8 Blanks[80];
575
576 AsciiStrCpy (Blanks, mBlanks);
577 for (EndAddress = Address + Length; Address < EndAddress; Offset += Line)
578 {
579 AsciiPrint ("%08x: ", Offset);
580 for (Line = 0; (Line < 0x10) && (Address < EndAddress);)
581 {
582 Bytes = EndAddress - Address;
583
584 switch (Width)
585 {
586 case 4:
587 if (Bytes >= 4)
588 {
589 AsciiPrint ("%08x ", *((UINT32 *)Address));
590 TextLine[Line++] = ConvertToTextLine(*Address++);
591 TextLine[Line++] = ConvertToTextLine(*Address++);
592 TextLine[Line++] = ConvertToTextLine(*Address++);
593 TextLine[Line++] = ConvertToTextLine(*Address++);
594 }
595 else
596 {
597 AsciiPrint ("%08x ", GetBytes(Address, Bytes));
598 Address += Bytes;
599 Line += Bytes;
600 }
601 break;
602
603 case 2:
604 if (Bytes >= 2)
605 {
606 AsciiPrint ("%04x ", *((UINT16 *)Address));
607 TextLine[Line++] = ConvertToTextLine(*Address++);
608 TextLine[Line++] = ConvertToTextLine(*Address++);
609 }
610 else
611 {
612 AsciiPrint ("%04x ", GetBytes(Address, Bytes));
613 Address += Bytes;
614 Line += Bytes;
615 }
616 break;
617
618 case 1:
619 AsciiPrint ("%02x ", *((UINT8 *)Address));
620 TextLine[Line++] = ConvertToTextLine(*Address++);
621 break;
622
623 default:
624 AsciiPrint ("Width must be 1, 2, or 4!\n");
625 return EFI_INVALID_PARAMETER;
626 }
627 }
628
629 // Pad spaces
630 if (Line < 0x10)
631 {
632 switch (Width)
633 {
634 case 4:
635 Spaces = 9 * ((0x10 - Line)/4);
636 break;
637 case 2:
638 Spaces = 5 * ((0x10 - Line)/2);
639 break;
640 case 1:
641 Spaces = 3 * (0x10 - Line);
642 break;
643 }
644
645 Blanks[Spaces] = '\0';
646
647 AsciiPrint(Blanks);
648
649 Blanks[Spaces] = ' ';
650 }
651
652 TextLine[Line] = 0;
653 AsciiPrint ("|%a|\n", TextLine);
654
655 if (EblAnyKeyToContinueQtoQuit(&CurrentRow, FALSE))
656 {
657 return EFI_END_OF_FILE;
658 }
659 }
660
661 if (Length % Width != 0)
662 {
663 AsciiPrint ("%08x\n", Offset);
664 }
665
666 return EFI_SUCCESS;
667 }
668
669 #define HEXDUMP_CHUNK 1024
670
671 EFI_STATUS
672 EblHexdumpCmd (
673 IN UINTN Argc,
674 IN CHAR8 **Argv
675 )
676 {
677 EFI_OPEN_FILE *File;
678 VOID *Location;
679 UINTN Size;
680 UINTN Width = 1;
681 UINTN Offset = 0;
682 EFI_STATUS Status;
683 UINTN Chunk = HEXDUMP_CHUNK;
684
685 if ((Argc < 2) || (Argc > 3))
686 {
687 return EFI_INVALID_PARAMETER;
688 }
689
690 if (Argc == 3)
691 {
692 Width = AsciiStrDecimalToUintn(Argv[2]);
693 }
694
695 if ((Width != 1) && (Width != 2) && (Width != 4))
696 {
697 return EFI_INVALID_PARAMETER;
698 }
699
700 File = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
701 if (File == NULL)
702 {
703 return EFI_NOT_FOUND;
704 }
705
706 Location = AllocatePool(Chunk);
707 Size = EfiTell(File, NULL);
708
709 for (Offset = 0; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk)
710 {
711 Chunk = HEXDUMP_CHUNK;
712
713 Status = EfiRead(File, Location, &Chunk);
714 if (EFI_ERROR(Status))
715 {
716 AsciiPrint ("Error reading file content\n");
717 goto Exit;
718 }
719
720 Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);
721 if (EFI_ERROR(Status))
722 {
723 if (Status == EFI_END_OF_FILE) {
724 Status = EFI_SUCCESS;
725 }
726 goto Exit;
727 }
728 }
729
730 // Any left over?
731 if (Offset < Size)
732 {
733 Chunk = Size - Offset;
734 Status = EfiRead(File, Location, &Chunk);
735 if (EFI_ERROR(Status))
736 {
737 AsciiPrint ("Error reading file content\n");
738 goto Exit;
739 }
740
741 Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset);
742 if (EFI_ERROR(Status))
743 {
744 if (Status == EFI_END_OF_FILE) {
745 Status = EFI_SUCCESS;
746 }
747 goto Exit;
748 }
749 }
750
751 Exit:
752 EfiClose(File);
753
754 FreePool(Location);
755
756 return EFI_SUCCESS;
757 }
758
759 #define USE_DISKIO 1
760
761 EFI_STATUS
762 EblDiskIoCmd (
763 IN UINTN Argc,
764 IN CHAR8 **Argv
765 )
766 {
767 EFI_STATUS Status;
768 UINTN Offset;
769 UINT8 *EndOffset;
770 UINTN Length;
771 UINTN Line;
772 UINT8 *Buffer;
773 UINT8 *BufferOffset;
774 CHAR8 TextLine[0x11];
775 #if USE_DISKIO
776 EFI_DISK_IO_PROTOCOL *DiskIo;
777 #else
778 EFI_BLOCK_IO_PROTOCOL *BlockIo;
779 UINTN Lba;
780 #endif
781
782 if (AsciiStrCmp(Argv[1], "r") == 0)
783 {
784 Offset = AsciiStrHexToUintn(Argv[2]);
785 Length = AsciiStrHexToUintn(Argv[3]);
786
787 #if USE_DISKIO
788 Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);
789 if (EFI_ERROR(Status))
790 {
791 AsciiPrint("Did not locate DiskIO\n");
792 return Status;
793 }
794
795 Buffer = AllocatePool(Length);
796 BufferOffset = Buffer;
797
798 Status = DiskIo->ReadDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);
799 if (EFI_ERROR(Status))
800 {
801 AsciiPrint("DiskIO read failed\n");
802 gBS->FreePool(Buffer);
803 return Status;
804 }
805 #else
806 Status = gBS->LocateProtocol(&gEfiBlockIoProtocolGuid, NULL, (VOID **)&BlockIo);
807 if (EFI_ERROR(Status))
808 {
809 AsciiPrint("Did not locate BlockIo\n");
810 return Status;
811 }
812
813 Length = BlockIo->Media->BlockSize;
814 Buffer = AllocatePool(Length);
815 BufferOffset = Buffer;
816 Lba = Offset/BlockIo->Media->BlockSize;
817
818 Status = BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, Lba, Length, Buffer);
819 if (EFI_ERROR(Status))
820 {
821 AsciiPrint("BlockIo read failed\n");
822 gBS->FreePool(Buffer);
823 return Status;
824 }
825
826 // Whack offset to what we actually read from
827 Offset = Lba * BlockIo->Media->BlockSize;
828
829 Length = 0x100;
830 #endif
831
832 for (EndOffset = BufferOffset + Length; BufferOffset < EndOffset; Offset += 0x10)
833 {
834 AsciiPrint ("%08x: ", Offset);
835
836 for (Line = 0; Line < 0x10; Line++)
837 {
838 AsciiPrint ("%02x ", *BufferOffset);
839
840 if (*BufferOffset < ' ' || *BufferOffset > '~')
841 TextLine[Line] = '.';
842 else
843 TextLine[Line] = *BufferOffset;
844
845 BufferOffset++;
846 }
847
848 TextLine[Line] = '\0';
849 AsciiPrint ("|%a|\n", TextLine);
850 }
851
852 gBS->FreePool(Buffer);
853
854 return EFI_SUCCESS;
855 }
856 else if (AsciiStrCmp(Argv[1], "w") == 0)
857 {
858 Offset = AsciiStrHexToUintn(Argv[2]);
859 Length = AsciiStrHexToUintn(Argv[3]);
860 Buffer = (UINT8 *)AsciiStrHexToUintn(Argv[4]);
861
862 #if USE_DISKIO
863 Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);
864 if (EFI_ERROR(Status))
865 {
866 AsciiPrint("Did not locate DiskIO\n");
867 return Status;
868 }
869
870 Status = DiskIo->WriteDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer);
871 if (EFI_ERROR(Status))
872 {
873 AsciiPrint("DiskIO write failed\n");
874 return Status;
875 }
876
877 #else
878 #endif
879
880 return EFI_SUCCESS;
881 }
882 else
883 {
884 return EFI_INVALID_PARAMETER;
885 }
886 }
887
888 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdTemplate[] =
889 {
890 {
891 "reset",
892 " [type]; Reset system. type = [warm] [shutdown] default is cold reset",
893 NULL,
894 EblResetCmd
895 },
896 {
897 "exit",
898 "; Exit EBL",
899 NULL,
900 EblExitCmd
901 },
902 {
903 "help",
904 " [cmd]; Help on cmd or a list of all commands if cmd is ommited",
905 NULL,
906 EblHelpCmd
907 },
908 {
909 "break",
910 "; Generate debugging breakpoint",
911 NULL,
912 EblBreakPointCmd
913 },
914 {
915 "page",
916 " [on|off]]; toggle promting on command output larger than screen",
917 NULL,
918 EblPageCmd
919 },
920 {
921 "pause",
922 " [sec]; Pause for sec[10] seconds. ",
923 NULL,
924 EblPauseCmd
925 },
926 {
927 "sleep",
928 " [sec]; Sleep for sec[10] seconds. ",
929 NULL,
930 EblSleepCmd
931 },
932 {
933 "hexdump",
934 " filename ; dump a file as hex bytes",
935 NULL,
936 EblHexdumpCmd
937 },
938 {
939 "diskio",
940 " [r|w] offset [length [dataptr]]; do a DiskIO read or write ",
941 NULL,
942 EblDiskIoCmd
943 }
944 };
945
946
947 EFI_HANDLE gExternalCmdHandle = NULL;
948
949 /**
950 Initialize the commands in this in this file
951 **/
952 VOID
953 EblInitializeCmdTable (
954 VOID
955 )
956 {
957
958 EblAddCommands (mCmdTemplate, sizeof (mCmdTemplate)/sizeof (EBL_COMMAND_TABLE));
959
960 gBS->InstallProtocolInterface (
961 &gExternalCmdHandle,
962 &gEfiEblAddCommandProtocolGuid,
963 EFI_NATIVE_INTERFACE,
964 &gEblAddCommand
965 );
966
967 }
968
969
970 VOID
971 EblShutdownExternalCmdTable (
972 VOID
973 )
974 {
975 gBS->UninstallProtocolInterface (gExternalCmdHandle, &gEfiEblAddCommandProtocolGuid, &gEblAddCommand);
976 }
977
978