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