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