]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Ebl/Command.c
EmbeddedPkg/Ebl: eliminate deprecated string function calls
[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
50c6a4d2 6 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
2ef2b01e 7\r
60274cca 8 This program and the accompanying materials\r
2ef2b01e
A
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
3402aac7 36 @return The uppercase value of Ascii character\r
2ef2b01e
A
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
7ca9e5a4 50 Case insensitive comparison of two Null-terminated Unicode strings with maximum\r
2ef2b01e
A
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
3402aac7
RC
59\r
60 @param FirstString Pointer to a Null-terminated ASCII string.\r
2ef2b01e
A
61 @param SecondString Pointer to a Null-terminated ASCII string.\r
62 @param Length Max length to compare.\r
3402aac7 63\r
2ef2b01e
A
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
3402aac7 89\r
2ef2b01e
A
90 return AsciiToUpper (*FirstString) - AsciiToUpper (*SecondString);\r
91}\r
92\r
93\r
94\r
95/**\r
3402aac7
RC
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
7ca9e5a4 98 new entry is inserted into its sorted position.\r
2ef2b01e 99\r
7ca9e5a4 100 @param Entry Command Entry to add to the CmdTable\r
2ef2b01e
A
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
3402aac7 128\r
2ef2b01e
A
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
3402aac7 139 Add an set of commands to the command table. Most commonly used on static\r
2ef2b01e
A
140 array of commands.\r
141\r
142 @param EntryArray Pointer to array of command entries\r
7ca9e5a4 143 @param ArrayCount Number of command entries to add\r
2ef2b01e
A
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
3402aac7 171 Return the best matching command for the passed in command name. The match\r
7ca9e5a4 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
2ef2b01e
A
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
a6d7123e 190 CHAR8 *Str;\r
2ef2b01e
A
191\r
192 Length = AsciiStrLen (CommandName);\r
a6d7123e 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
3402aac7 197 Length = (UINTN)(Str - CommandName);\r
a6d7123e 198 }\r
3402aac7 199\r
2ef2b01e
A
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
60428d00 224UINTN\r
225CountNewLines (\r
226 IN CHAR8 *Str\r
227 )\r
228{\r
229 UINTN Count;\r
3402aac7 230\r
60428d00 231 if (Str == NULL) {\r
232 return 0;\r
233 }\r
3402aac7 234\r
60428d00 235 for (Count = 0; *Str != '\0'; Str++) {\r
236 if (Str[Count] == '\n') {\r
237 Count++;\r
238 }\r
239 }\r
3402aac7 240\r
60428d00 241 return Count;\r
242}\r
243\r
2ef2b01e
A
244\r
245/**\r
3402aac7 246 List out help information on all the commands or print extended information\r
2ef2b01e
A
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
3402aac7 253 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 254 Argv[0] is the command name\r
2ef2b01e
A
255\r
256 @return EFI_SUCCESS\r
257\r
258**/\r
259EFI_STATUS\r
50c6a4d2 260EFIAPI\r
2ef2b01e
A
261EblHelpCmd (\r
262 IN UINTN Argc,\r
263 IN CHAR8 **Argv\r
264 )\r
265{\r
266 UINTN Index;\r
267 CHAR8 *Ptr;\r
60428d00 268 UINTN CurrentRow = 0;\r
2ef2b01e
A
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
60428d00 273 CurrentRow++;\r
2ef2b01e
A
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
60428d00 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
2ef2b01e
A
284 }\r
285 } else if (Argv[1] != NULL) {\r
3402aac7 286 // Print specific help\r
2ef2b01e
A
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
60428d00 291 // Handle multi line help summaries\r
292 CurrentRow += CountNewLines (Ptr);\r
2ef2b01e
A
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
7ca9e5a4 305 Exit the EBL. If the command processor sees EFI_ABORTED return status it will\r
2ef2b01e
A
306 exit the EBL.\r
307\r
308 Argv[0] - "exit"\r
309\r
310 @param Argc Number of command arguments in Argv\r
3402aac7 311 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 312 Argv[0] is the command name\r
2ef2b01e
A
313\r
314 @return EFI_ABORTED\r
315\r
316**/\r
317EFI_STATUS\r
50c6a4d2 318EFIAPI\r
2ef2b01e
A
319EblExitCmd (\r
320 IN UINTN Argc,\r
321 IN CHAR8 **Argv\r
322 )\r
323{\r
85e385f4 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
2ef2b01e 331\r
3402aac7 332 if (Argc > 1) {\r
2ef2b01e
A
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
3402aac7 339\r
85e385f4 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
3402aac7 354\r
85e385f4 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
2ef2b01e
A
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
3402aac7 381 //\r
2ef2b01e 382 CpuDeadLoop ();\r
3402aac7 383\r
2ef2b01e
A
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
3402aac7
RC
391 This AsciiPrint has to match the AsciiPrint in\r
392 EblPauseCmd.\r
2ef2b01e 393\r
7ca9e5a4 394 @param ElaspedTime Current timeout value remaining\r
2ef2b01e
A
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
3402aac7 416 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 417 Argv[0] is the command name\r
2ef2b01e
A
418\r
419 @return EFI_SUCCESS Timeout expired with no input\r
7ca9e5a4 420 @return EFI_TIMEOUT Stop processing other commands on the same command line\r
2ef2b01e
A
421\r
422**/\r
423EFI_STATUS\r
50c6a4d2 424EFIAPI\r
2ef2b01e
A
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
7ca9e5a4 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
2ef2b01e
A
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
3402aac7 452 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 453 Argv[0] is the command name\r
2ef2b01e
A
454\r
455 @return EFI_SUCCESS\r
456\r
457**/\r
458EFI_STATUS\r
50c6a4d2 459EFIAPI\r
2ef2b01e
A
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
3402aac7 479 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 480 Argv[0] is the command name\r
2ef2b01e
A
481\r
482 @return EFI_SUCCESS\r
483\r
484**/\r
485EFI_STATUS\r
50c6a4d2 486EFIAPI\r
2ef2b01e
A
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
3402aac7 505 }\r
2ef2b01e
A
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
3402aac7 520 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 521 Argv[0] is the command name\r
2ef2b01e
A
522\r
523 @return EFI_SUCCESS\r
524\r
525**/\r
526EFI_STATUS\r
50c6a4d2 527EFIAPI\r
2ef2b01e
A
528EblPageCmd (\r
529 IN UINTN Argc,\r
530 IN CHAR8 **Argv\r
531 )\r
532{\r
533 if (Argc <= 1) {\r
3402aac7 534 // toggle setting\r
2ef2b01e
A
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
50c6a4d2 552EFIAPI\r
2ef2b01e
A
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
0534bb8f 572 if (Character < ' ' || Character > '~') {\r
2ef2b01e 573 return '.';\r
0534bb8f 574 } else {\r
2ef2b01e
A
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
0534bb8f 587 if (Bytes >= 1) {\r
2ef2b01e 588 Result = *Address++;\r
0534bb8f 589 }\r
590 if (Bytes >= 2) {\r
2ef2b01e 591 Result = (Result << 8) + *Address++;\r
3402aac7 592 }\r
0534bb8f 593 if (Bytes >= 3) {\r
2ef2b01e 594 Result = (Result << 8) + *Address++;\r
0534bb8f 595 }\r
2ef2b01e
A
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
5140a6df 617 AsciiStrCpyS (Blanks, sizeof Blanks, mBlanks);\r
0534bb8f 618 for (EndAddress = Address + Length; Address < EndAddress; Offset += Line) {\r
2ef2b01e 619 AsciiPrint ("%08x: ", Offset);\r
0534bb8f 620 for (Line = 0; (Line < 0x10) && (Address < EndAddress);) {\r
2ef2b01e 621 Bytes = EndAddress - Address;\r
3402aac7 622\r
0534bb8f 623 switch (Width) {\r
2ef2b01e 624 case 4:\r
0534bb8f 625 if (Bytes >= 4) {\r
2ef2b01e
A
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
0534bb8f 631 } else {\r
2ef2b01e
A
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
0534bb8f 639 if (Bytes >= 2) {\r
2ef2b01e
A
640 AsciiPrint ("%04x ", *((UINT16 *)Address));\r
641 TextLine[Line++] = ConvertToTextLine(*Address++);\r
642 TextLine[Line++] = ConvertToTextLine(*Address++);\r
0534bb8f 643 } else {\r
2ef2b01e
A
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
91c38d4e
RC
655 default:\r
656 AsciiPrint ("Width must be 1, 2, or 4!\n");\r
657 return EFI_INVALID_PARAMETER;\r
2ef2b01e
A
658 }\r
659 }\r
660\r
661 // Pad spaces\r
0534bb8f 662 if (Line < 0x10) {\r
663 switch (Width) {\r
2ef2b01e
A
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
3402aac7 678\r
2ef2b01e
A
679 Blanks[Spaces] = ' ';\r
680 }\r
681\r
682 TextLine[Line] = 0;\r
683 AsciiPrint ("|%a|\n", TextLine);\r
684\r
0534bb8f 685 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {\r
2ef2b01e
A
686 return EFI_END_OF_FILE;\r
687 }\r
688 }\r
689\r
0534bb8f 690 if (Length % Width != 0) {\r
2ef2b01e
A
691 AsciiPrint ("%08x\n", Offset);\r
692 }\r
3402aac7 693\r
2ef2b01e
A
694 return EFI_SUCCESS;\r
695}\r
696\r
a6d7123e 697\r
698/**\r
699 See if command contains .# where # is a number. Return # as the Width\r
3402aac7
RC
700 or 1 as the default Width for commands.\r
701\r
a6d7123e 702 Example hexdump.4 returns a width of 4.\r
703\r
7ca9e5a4 704 @param Argv Argv[0] is the command name\r
a6d7123e 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
3402aac7 717\r
a6d7123e 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
2ef2b01e
A
733#define HEXDUMP_CHUNK 1024\r
734\r
a6d7123e 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
3402aac7
RC
739 Argv[0] - "hexdump"[.#] # is optional 1,2, or 4 for width\r
740 Argv[1] - Device or File to dump.\r
a6d7123e 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
3402aac7 745 @param Argv Array of strings that represent the parsed command line.\r
7ca9e5a4 746 Argv[0] is the command name\r
a6d7123e 747\r
748 @return EFI_SUCCESS\r
749\r
750**/\r
2ef2b01e 751EFI_STATUS\r
50c6a4d2 752EFIAPI\r
2ef2b01e
A
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
a6d7123e 761 UINTN Width;\r
2ef2b01e
A
762 UINTN Offset = 0;\r
763 EFI_STATUS Status;\r
764 UINTN Chunk = HEXDUMP_CHUNK;\r
765\r
a6d7123e 766 if ((Argc < 2) || (Argc > 4)) {\r
2ef2b01e
A
767 return EFI_INVALID_PARAMETER;\r
768 }\r
3402aac7 769\r
a6d7123e 770 Width = WidthFromCommandName (Argv[0], 1);\r
0534bb8f 771 if ((Width != 1) && (Width != 2) && (Width != 4)) {\r
2ef2b01e
A
772 return EFI_INVALID_PARAMETER;\r
773 }\r
774\r
0534bb8f 775 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
776 if (File == NULL) {\r
2ef2b01e
A
777 return EFI_NOT_FOUND;\r
778 }\r
779\r
0534bb8f 780 Location = AllocatePool (Chunk);\r
a6d7123e 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
3402aac7 790 }\r
2ef2b01e 791\r
a6d7123e 792 Status = EfiSeek (File, Offset, EfiSeekStart);\r
793 if (EFI_ERROR (Status)) {\r
794 goto Exit;\r
795 }\r
3402aac7 796\r
a6d7123e 797 for (; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk) {\r
2ef2b01e 798 Chunk = HEXDUMP_CHUNK;\r
0534bb8f 799 Status = EfiRead (File, Location, &Chunk);\r
a6d7123e 800 if (EFI_ERROR(Status)) {\r
2ef2b01e
A
801 AsciiPrint ("Error reading file content\n");\r
802 goto Exit;\r
803 }\r
804\r
0534bb8f 805 Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);\r
806 if (EFI_ERROR(Status)) {\r
2ef2b01e
A
807 if (Status == EFI_END_OF_FILE) {\r
808 Status = EFI_SUCCESS;\r
809 }\r
810 goto Exit;\r
811 }\r
812 }\r
3402aac7 813\r
2ef2b01e 814 // Any left over?\r
0534bb8f 815 if (Offset < Size) {\r
2ef2b01e 816 Chunk = Size - Offset;\r
0534bb8f 817 Status = EfiRead (File, Location, &Chunk);\r
818 if (EFI_ERROR(Status)) {\r
2ef2b01e
A
819 AsciiPrint ("Error reading file content\n");\r
820 goto Exit;\r
821 }\r
822\r
0534bb8f 823 Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);\r
824 if (EFI_ERROR(Status)) {\r
2ef2b01e
A
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
0534bb8f 833 EfiClose (File);\r
2ef2b01e 834\r
0534bb8f 835 FreePool (Location);\r
2ef2b01e
A
836\r
837 return EFI_SUCCESS;\r
838}\r
839\r
2ef2b01e
A
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
60428d00 887 "[.{1|2|4}] filename [Offset] [Size]; dump a file as hex .width",\r
2ef2b01e
A
888 NULL,\r
889 EblHexdumpCmd\r
0534bb8f 890 }\r
2ef2b01e
A
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
3402aac7 906\r
2ef2b01e
A
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