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