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