]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ConsoleLogger.c
ShellPkg: Fix ARM build errors.
[mirror_edk2.git] / ShellPkg / Application / Shell / ConsoleLogger.c
1 /** @file
2 Provides interface to shell console logger.
3
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13
14 #include "Shell.h"
15
16 /**
17 Install our intermediate ConOut into the system table to
18 keep a log of all the info that is displayed to the user.
19
20 @param[in] ScreensToSave Sets how many screen-worths of data to save.
21 @param[out] ConsoleInfo The object to pass into later functions.
22
23 @retval EFI_SUCCESS The operation was successful.
24 @return other The operation failed.
25
26 @sa ConsoleLoggerResetBuffers
27 @sa InstallProtocolInterface
28 **/
29 EFI_STATUS
30 EFIAPI
31 ConsoleLoggerInstall(
32 IN CONST UINTN ScreensToSave,
33 OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo
34 )
35 {
36 EFI_STATUS Status;
37 ASSERT(ConsoleInfo != NULL);
38
39 (*ConsoleInfo) = AllocateZeroPool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA));
40 if ((*ConsoleInfo) == NULL) {
41 return (EFI_OUT_OF_RESOURCES);
42 }
43
44 (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE;
45 (*ConsoleInfo)->OldConOut = gST->ConOut;
46 (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle;
47 (*ConsoleInfo)->Buffer = NULL;
48 (*ConsoleInfo)->BufferSize = 0;
49 (*ConsoleInfo)->OriginalStartRow = 0;
50 (*ConsoleInfo)->CurrentStartRow = 0;
51 (*ConsoleInfo)->RowsPerScreen = 0;
52 (*ConsoleInfo)->ColsPerScreen = 0;
53 (*ConsoleInfo)->Attributes = NULL;
54 (*ConsoleInfo)->AttribSize = 0;
55 (*ConsoleInfo)->ScreenCount = ScreensToSave;
56 (*ConsoleInfo)->HistoryMode.MaxMode = 1;
57 (*ConsoleInfo)->HistoryMode.Mode = 0;
58 (*ConsoleInfo)->HistoryMode.Attribute = 0;
59 (*ConsoleInfo)->HistoryMode.CursorColumn = 0;
60 (*ConsoleInfo)->HistoryMode.CursorRow = 0;
61 (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE;
62 (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset;
63 (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString;
64 (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString;
65 (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode;
66 (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode;
67 (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute;
68 (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen;
69 (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition;
70 (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor;
71 (*ConsoleInfo)->OurConOut.Mode = gST->ConOut->Mode;
72 (*ConsoleInfo)->Enabled = TRUE;
73
74 Status = ConsoleLoggerResetBuffers(*ConsoleInfo);
75 if (EFI_ERROR(Status)) {
76 SHELL_FREE_NON_NULL((*ConsoleInfo));
77 *ConsoleInfo = NULL;
78 return (Status);
79 }
80
81 Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut));
82 if (EFI_ERROR(Status)) {
83 SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer);
84 SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes);
85 SHELL_FREE_NON_NULL((*ConsoleInfo));
86 *ConsoleInfo = NULL;
87 return (Status);
88 }
89
90 gST->ConsoleOutHandle = gImageHandle;
91 gST->ConOut = &(*ConsoleInfo)->OurConOut;
92
93 return (Status);
94 }
95
96 /**
97 Return the system to the state it was before InstallConsoleLogger
98 was installed.
99
100 @param[in] ConsoleInfo The object from the install function.
101
102 @retval EFI_SUCCESS The operation was successful
103 @return other The operation failed. This was from UninstallProtocolInterface.
104 **/
105 EFI_STATUS
106 EFIAPI
107 ConsoleLoggerUninstall(
108 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
109 )
110 {
111 ASSERT(ConsoleInfo != NULL);
112 ASSERT(ConsoleInfo->OldConOut != NULL);
113
114 if (ConsoleInfo->Buffer != NULL) {
115 FreePool(ConsoleInfo->Buffer);
116 DEBUG_CODE(ConsoleInfo->Buffer = NULL;);
117 DEBUG_CODE(ConsoleInfo->BufferSize = 0;);
118 }
119 if (ConsoleInfo->Attributes != NULL) {
120 FreePool(ConsoleInfo->Attributes);
121 DEBUG_CODE(ConsoleInfo->Attributes = NULL;);
122 DEBUG_CODE(ConsoleInfo->AttribSize = 0;);
123 }
124
125 gST->ConsoleOutHandle = ConsoleInfo->OldConHandle;
126 gST->ConOut = ConsoleInfo->OldConOut;
127
128 return (gBS->UninstallProtocolInterface(gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID*)&ConsoleInfo->OurConOut));
129 }
130
131 /**
132 Displays previously logged output back to the screen.
133
134 This will scroll the screen forwards and backwards through the log of previous
135 output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
136 is (UINTN)(-1) then the size of the screen will be scrolled.
137
138 @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
139 If FALSE then the log will be displayed backwards (scroll to older).
140 @param[in] Rows Determines how many rows the log should scroll.
141 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
142 **/
143 EFI_STATUS
144 EFIAPI
145 ConsoleLoggerDisplayHistory(
146 IN CONST BOOLEAN Forward,
147 IN CONST UINTN Rows,
148 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
149 )
150 {
151 UINTN RowChange;
152
153 ASSERT(ConsoleInfo != NULL);
154
155 //
156 // Calculate the row number change
157 //
158 switch (Rows) {
159 case ((UINTN)(-1)):
160 RowChange = ConsoleInfo->RowsPerScreen;
161 break;
162 case (0):
163 RowChange = ConsoleInfo->RowsPerScreen / 2;
164 break;
165 default:
166 RowChange = Rows;
167 break;
168 }
169
170 //
171 // Do the math for direction
172 //
173 if (Forward) {
174 if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) {
175 RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow;
176 }
177 } else {
178 if (ConsoleInfo->CurrentStartRow < RowChange) {
179 RowChange = ConsoleInfo->CurrentStartRow;
180 }
181 }
182
183 //
184 // If we are already at one end or the other
185 //
186 if (RowChange == 0) {
187 return (EFI_SUCCESS);
188 }
189
190 //
191 // Clear the screen
192 //
193 ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut);
194
195 //
196 // Set the new start row
197 //
198 if (Forward) {
199 ConsoleInfo->CurrentStartRow += RowChange;
200 } else {
201 ConsoleInfo->CurrentStartRow -= RowChange;
202 }
203
204 //
205 // Change the screen
206 //
207 return (UpdateDisplayFromHistory(ConsoleInfo));
208 }
209
210 /**
211 Function to return to normal output whent he scrolling is complete.
212 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
213
214 @retval EFI_SUCCESS The operation was successful.
215 @return other The operation failed. See UpdateDisplayFromHistory.
216
217 @sa UpdateDisplayFromHistory
218 **/
219 EFI_STATUS
220 EFIAPI
221 ConsoleLoggerStopHistory(
222 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
223 )
224 {
225 ASSERT(ConsoleInfo != NULL);
226 if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
227 return (EFI_SUCCESS);
228 }
229 ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow;
230 return (UpdateDisplayFromHistory(ConsoleInfo));
231 }
232
233 /**
234 Updates the hidden ConOut to be displaying the correct stuff.
235 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
236
237 @retval EFI_SUCCESS The operation was successful.
238 @return other The operation failed.
239 **/
240 EFI_STATUS
241 EFIAPI
242 UpdateDisplayFromHistory(
243 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
244 )
245 {
246 EFI_STATUS Status;
247 EFI_STATUS RetVal;
248 CHAR16 *Screen;
249 INT32 *Attributes;
250 UINTN CurrentRow;
251 CHAR16 TempCharHolder;
252 UINTN Column;
253 INT32 CurrentAttrib;
254 UINTN CurrentColumn;
255 CHAR16 *StringSegment;
256 CHAR16 *StringSegmentEnd;
257 CHAR16 StringSegmentEndChar;
258 INT32 OrigAttribute;
259
260 ASSERT(ConsoleInfo != NULL);
261 TempCharHolder = CHAR_NULL;
262 RetVal = EFI_SUCCESS;
263 OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute;
264
265 //
266 // Disable cursor visibility and move it to the top left corner
267 //
268 ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE);
269 ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0);
270
271 Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
272 Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
273 for ( CurrentRow = 0
274 ; CurrentRow < ConsoleInfo->RowsPerScreen
275 ; CurrentRow++
276 , Screen += (ConsoleInfo->ColsPerScreen + 2)
277 , Attributes += ConsoleInfo->ColsPerScreen
278 ){
279 //
280 // dont use the last char - prevents screen scroll
281 //
282 if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)){
283 TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1];
284 Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL;
285 }
286
287 for ( Column = 0
288 ; Column < ConsoleInfo->ColsPerScreen
289 ; Column++
290 ){
291 if (Screen[Column] != CHAR_NULL) {
292 CurrentAttrib = Attributes[Column];
293 CurrentColumn = Column;
294 StringSegment = &Screen[Column];
295
296 //
297 // Find the first char with a different arrribute and make that temporarily NULL
298 // so we can do fewer printout statements. (later) restore that one and we will
299 // start at that collumn on the next loop.
300 //
301 StringSegmentEndChar = CHAR_NULL;
302 for ( StringSegmentEnd = StringSegment
303 ; StringSegmentEnd != CHAR_NULL
304 ; StringSegmentEnd++
305 , Column++
306 ){
307 if (Attributes[Column] != CurrentAttrib) {
308 StringSegmentEndChar = *StringSegmentEnd;
309 *StringSegmentEnd = CHAR_NULL;
310 break;
311 }
312 } // StringSegmentEnd loop
313
314 //
315 // Now write out as much as had the same Attributes
316 //
317
318 ConsoleInfo->OldConOut->SetAttribute(ConsoleInfo->OldConOut, CurrentAttrib);
319 ConsoleInfo->OldConOut->SetCursorPosition(ConsoleInfo->OldConOut, CurrentColumn, CurrentRow);
320 Status = ConsoleInfo->OldConOut->OutputString(ConsoleInfo->OldConOut, StringSegment);
321
322 if (EFI_ERROR(Status)) {
323 ASSERT(FALSE);
324 RetVal = Status;
325 }
326
327 //
328 // If we found a change in attribute put the character back and decrement the column
329 // so when it increments it will point at that character and we will start printing
330 // a segment with that new attribute
331 //
332 if (StringSegmentEndChar != CHAR_NULL) {
333 *StringSegmentEnd = StringSegmentEndChar;
334 StringSegmentEndChar = CHAR_NULL;
335 Column--;
336 }
337 }
338 } // column for loop
339
340 //
341 // If we removed the last char and this was the last row put it back
342 //
343 if (TempCharHolder != CHAR_NULL) {
344 Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder;
345 TempCharHolder = CHAR_NULL;
346 }
347 } // row for loop
348
349 //
350 // If we are setting the screen back to original turn on the cursor and make it visible
351 // and set the attributes back to what they were
352 //
353 if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
354 ConsoleInfo->OldConOut->SetAttribute (
355 ConsoleInfo->OldConOut,
356 ConsoleInfo->HistoryMode.Attribute
357 );
358 ConsoleInfo->OldConOut->SetCursorPosition (
359 ConsoleInfo->OldConOut,
360 ConsoleInfo->HistoryMode.CursorColumn,
361 ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow
362 );
363
364 Status = ConsoleInfo->OldConOut->EnableCursor (
365 ConsoleInfo->OldConOut,
366 ConsoleInfo->HistoryMode.CursorVisible
367 );
368 if (EFI_ERROR (Status)) {
369 RetVal = Status;
370 }
371 } else {
372 ConsoleInfo->OldConOut->SetAttribute (
373 ConsoleInfo->OldConOut,
374 OrigAttribute
375 );
376 }
377
378 return (RetVal);
379 }
380
381 /**
382 Reset the text output device hardware and optionaly run diagnostics
383
384 @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
385 @param ExtendedVerification Indicates that a more extensive test may be performed
386
387 @retval EFI_SUCCESS The text output device was reset.
388 @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
389 could not be reset.
390 **/
391 EFI_STATUS
392 EFIAPI
393 ConsoleLoggerReset (
394 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
395 IN BOOLEAN ExtendedVerification
396 )
397 {
398 EFI_STATUS Status;
399 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
400 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
401
402 //
403 // Forward the request to the original ConOut
404 //
405 Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification);
406
407 //
408 // Check that the buffers are still correct for logging
409 //
410 if (!EFI_ERROR (Status)) {
411 ConsoleLoggerResetBuffers(ConsoleInfo);
412 }
413
414 return Status;
415 }
416
417 /**
418 Appends a string to the history buffer. If the buffer is full then the oldest
419 information in the buffer will be dropped. Information is added in a line by
420 line manner such that an empty line takes up just as much space as a full line.
421
422 @param[in] String String pointer to add.
423 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
424 **/
425 EFI_STATUS
426 EFIAPI
427 AppendStringToHistory(
428 IN CONST CHAR16 *String,
429 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
430 )
431 {
432 CONST CHAR16 *Walker;
433 UINTN CopySize;
434 UINTN PrintIndex;
435 UINTN Index;
436
437 ASSERT(ConsoleInfo != NULL);
438
439 for ( Walker = String
440 ; Walker != NULL && *Walker != CHAR_NULL
441 ; Walker++
442 ){
443 switch (*Walker) {
444 case (CHAR_BACKSPACE):
445 if (ConsoleInfo->HistoryMode.CursorColumn > 0) {
446 ConsoleInfo->HistoryMode.CursorColumn--;
447 }
448 break;
449 case (CHAR_LINEFEED):
450 if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) {
451 //
452 // Should never be bigger
453 //
454 ASSERT(ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1));
455
456 //
457 // scroll history attributes 'up' 1 row and set the last row to default attribute
458 //
459 CopySize = ConsoleInfo->ColsPerScreen
460 * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
461 * sizeof(ConsoleInfo->Attributes[0]);
462 ASSERT(CopySize < ConsoleInfo->AttribSize);
463 CopyMem(
464 ConsoleInfo->Attributes,
465 ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen,
466 CopySize
467 );
468
469 for ( Index = 0
470 ; Index < ConsoleInfo->ColsPerScreen
471 ; Index++
472 ){
473 *(ConsoleInfo->Attributes + (CopySize/sizeof(ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute;
474 }
475
476 //
477 // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
478 //
479 CopySize = (ConsoleInfo->ColsPerScreen + 2)
480 * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
481 * sizeof(ConsoleInfo->Buffer[0]);
482 ASSERT(CopySize < ConsoleInfo->BufferSize);
483 CopyMem(
484 ConsoleInfo->Buffer,
485 ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2),
486 CopySize
487 );
488
489 //
490 // Set that last row of chars to spaces
491 //
492 SetMem16(((UINT8*)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof(CHAR16), L' ');
493 } else {
494 //
495 // we are not on the last row
496 //
497
498 //
499 // We should not be scrolling history
500 //
501 ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow);
502 //
503 // are we at the end of a row?
504 //
505 if (ConsoleInfo->HistoryMode.CursorRow == (INT32) (ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) {
506 ConsoleInfo->OriginalStartRow++;
507 ConsoleInfo->CurrentStartRow++;
508 }
509 ConsoleInfo->HistoryMode.CursorRow++;
510 }
511 break;
512 case (CHAR_CARRIAGE_RETURN):
513 //
514 // Move the cursor to the beginning of the current row.
515 //
516 ConsoleInfo->HistoryMode.CursorColumn = 0;
517 break;
518 default:
519 //
520 // Acrtually print characters into the history buffer
521 //
522
523 PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn;
524
525 for ( // no initializer needed
526 ; ConsoleInfo->HistoryMode.CursorColumn < (INT32) ConsoleInfo->ColsPerScreen
527 ; ConsoleInfo->HistoryMode.CursorColumn++
528 , PrintIndex++
529 , Walker++
530 ){
531 if (*Walker == CHAR_NULL
532 ||*Walker == CHAR_BACKSPACE
533 ||*Walker == CHAR_LINEFEED
534 ||*Walker == CHAR_CARRIAGE_RETURN
535 ){
536 Walker--;
537 break;
538 }
539 //
540 // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
541 //
542
543 ASSERT(PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize);
544 ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker;
545 ASSERT(PrintIndex < ConsoleInfo->AttribSize);
546 ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute;
547 } // for loop
548
549 //
550 // Add the carriage return and line feed at the end of the lines
551 //
552 if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) {
553 AppendStringToHistory(L"\r\n", ConsoleInfo);
554 Walker--;
555 }
556
557 break;
558 } // switch for character
559 } // for loop
560
561 return (EFI_SUCCESS);
562 }
563
564 /**
565 Worker function to handle printing the output to the screen
566 and the history buffer
567
568 @param[in] String The string to output
569 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
570
571 @retval EFI_SUCCESS The string was printed
572 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
573 the text.
574 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
575 defined text mode.
576 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
577 characters in the Unicode string could not be
578 rendered and were skipped.
579 **/
580 EFI_STATUS
581 EFIAPI
582 ConsoleLoggerOutputStringSplit(
583 IN CONST CHAR16 *String,
584 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
585 )
586 {
587 EFI_STATUS Status;
588
589 //
590 // Forward the request to the original ConOut
591 //
592 Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16*)String);
593
594 if (EFI_ERROR(Status)) {
595 return (Status);
596 }
597
598 return (AppendStringToHistory(String, ConsoleInfo));
599 }
600
601 /**
602 Function to handle page break mode.
603
604 This function will prompt for continue or break.
605
606 @retval EFI_SUCCESS Continue was choosen
607 @return other Break was choosen
608 **/
609 EFI_STATUS
610 EFIAPI
611 ConsoleLoggerDoPageBreak(
612 VOID
613 )
614 {
615 SHELL_PROMPT_RESPONSE *Resp;
616 EFI_STATUS Status;
617
618 Resp = NULL;
619 ASSERT(ShellInfoObject.PageBreakEnabled);
620 ShellInfoObject.PageBreakEnabled = FALSE;
621 Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN(STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID**)&Resp);
622 ShellInfoObject.PageBreakEnabled = TRUE;
623 ASSERT(Resp != NULL);
624 if (Resp == NULL) {
625 return (EFI_NOT_FOUND);
626 }
627 if (EFI_ERROR(Status)) {
628 if (Resp != NULL) {
629 FreePool(Resp);
630 }
631 return (Status);
632 }
633 if (*Resp == ShellPromptResponseContinue) {
634 FreePool(Resp);
635 ShellInfoObject.ConsoleInfo->RowCounter = 0;
636 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
637 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
638
639 return (EFI_SUCCESS);
640 } else if (*Resp == ShellPromptResponseQuit) {
641 FreePool(Resp);
642 ShellInfoObject.ConsoleInfo->Enabled = FALSE;
643 return (EFI_DEVICE_ERROR);
644 } else {
645 ASSERT(FALSE);
646 }
647 return (EFI_SUCCESS);
648 }
649 /**
650 Worker function to handle printing the output with page breaks.
651
652 @param[in] String The string to output
653 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
654
655 @retval EFI_SUCCESS The string was printed
656 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
657 the text.
658 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
659 defined text mode.
660 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
661 characters in the Unicode string could not be
662 rendered and were skipped.
663 **/
664 EFI_STATUS
665 EFIAPI
666 ConsoleLoggerPrintWithPageBreak(
667 IN CONST CHAR16 *String,
668 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
669 )
670 {
671 CONST CHAR16 *Walker;
672 CONST CHAR16 *LineStart;
673 CHAR16 *StringCopy;
674 CHAR16 TempChar;
675
676 StringCopy = NULL;
677 StringCopy = StrnCatGrow(&StringCopy, NULL, String, 0);
678 if (StringCopy == NULL) {
679 return (EFI_OUT_OF_RESOURCES);
680 }
681
682 for ( Walker = StringCopy
683 , LineStart = StringCopy
684 ; Walker != NULL && *Walker != CHAR_NULL
685 ; Walker++
686 ){
687 switch (*Walker) {
688 case (CHAR_BACKSPACE):
689 if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) {
690 ConsoleInfo->OurConOut.Mode->CursorColumn--;
691 }
692 break;
693 case (CHAR_LINEFEED):
694 //
695 // add a temp NULL terminator
696 //
697 TempChar = *(Walker + 1);
698 *((CHAR16*)(Walker+1)) = CHAR_NULL;
699
700 //
701 // output the string
702 //
703 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
704
705 //
706 // restore the temp NULL terminator to it's original character
707 //
708 *((CHAR16*)(Walker+1)) = TempChar;
709
710 //
711 // Update LineStart Variable
712 //
713 LineStart = Walker + 1;
714
715 //
716 // increment row count
717 //
718 ShellInfoObject.ConsoleInfo->RowCounter++;
719 ConsoleInfo->OurConOut.Mode->CursorRow++;
720
721 break;
722 case (CHAR_CARRIAGE_RETURN):
723 //
724 // Move the cursor to the beginning of the current row.
725 //
726 ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
727 break;
728 default:
729 //
730 // increment column count
731 //
732 ConsoleInfo->OurConOut.Mode->CursorColumn++;
733 //
734 // check if that is the last column
735 //
736 if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) {
737 //
738 // output a line similar to the linefeed character.
739 //
740
741 //
742 // add a temp NULL terminator
743 //
744 TempChar = *(Walker + 1);
745 *((CHAR16*)(Walker+1)) = CHAR_NULL;
746
747 //
748 // output the string
749 //
750 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
751
752 //
753 // restore the temp NULL terminator to it's original character
754 //
755 *((CHAR16*)(Walker+1)) = TempChar;
756
757 //
758 // Update LineStart Variable
759 //
760 LineStart = Walker + 1;
761
762 //
763 // increment row count and zero the column
764 //
765 ShellInfoObject.ConsoleInfo->RowCounter++;
766 ConsoleInfo->OurConOut.Mode->CursorRow++;
767 ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
768 } // last column on line
769 break;
770 } // switch for character
771
772 //
773 // check if that was the last printable row. If yes handle PageBreak mode
774 //
775 if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) {
776 if (EFI_ERROR(ConsoleLoggerDoPageBreak())) {
777 //
778 // We got an error which means 'break' and halt the printing
779 //
780 SHELL_FREE_NON_NULL(StringCopy);
781 return (EFI_DEVICE_ERROR);
782 }
783 }
784 } // for loop
785
786 if (LineStart != NULL && *LineStart != CHAR_NULL) {
787 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
788 }
789
790 SHELL_FREE_NON_NULL(StringCopy);
791 return (EFI_SUCCESS);
792 }
793
794 /**
795 Write a Unicode string to the output device.
796
797 @param[in] This Protocol instance pointer.
798 @param[in] WString The NULL-terminated Unicode string to be displayed on the output
799 device(s). All output devices must also support the Unicode
800 drawing defined in this file.
801 @retval EFI_SUCCESS The string was output to the device.
802 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
803 the text.
804 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
805 defined text mode.
806 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
807 characters in the Unicode string could not be
808 rendered and were skipped.
809 **/
810 EFI_STATUS
811 EFIAPI
812 ConsoleLoggerOutputString (
813 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
814 IN CHAR16 *WString
815 )
816 {
817 EFI_INPUT_KEY Key;
818 UINTN EventIndex;
819 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
820 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
821 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
822 return (EFI_UNSUPPORTED);
823 }
824 ASSERT(ShellInfoObject.ConsoleInfo == ConsoleInfo);
825 if (ShellInfoObject.HaltOutput) {
826 //
827 // just get some key
828 //
829 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
830 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
831 ShellInfoObject.HaltOutput = FALSE;
832 }
833 if (!ShellInfoObject.ConsoleInfo->Enabled) {
834 return (EFI_DEVICE_ERROR);
835 } else if (ShellInfoObject.PageBreakEnabled) {
836 return (ConsoleLoggerPrintWithPageBreak(WString, ConsoleInfo));
837 } else {
838 return (ConsoleLoggerOutputStringSplit(WString, ConsoleInfo));
839 }
840 }
841
842 /**
843 Verifies that all characters in a Unicode string can be output to the
844 target device.
845
846 @param[in] This Protocol instance pointer.
847 @param[in] WString The NULL-terminated Unicode string to be examined for the output
848 device(s).
849
850 @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
851 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
852 rendered by one or more of the output devices mapped
853 by the EFI handle.
854
855 **/
856 EFI_STATUS
857 EFIAPI
858 ConsoleLoggerTestString (
859 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
860 IN CHAR16 *WString
861 )
862 {
863 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
864 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
865 //
866 // Forward the request to the original ConOut
867 //
868 return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString));
869 }
870
871 /**
872 Returns information for an available text mode that the output device(s)
873 supports.
874
875 @param[in] This Protocol instance pointer.
876 @param[in] ModeNumber The mode number to return information on.
877 @param[out] Columns Upon return, the number of columns in the selected geometry
878 @param[out] Rows Upon return, the number of rows in the selected geometry
879
880 @retval EFI_SUCCESS The requested mode information was returned.
881 @retval EFI_DEVICE_ERROR The device had an error and could not
882 complete the request.
883 @retval EFI_UNSUPPORTED The mode number was not valid.
884 **/
885 EFI_STATUS
886 EFIAPI
887 ConsoleLoggerQueryMode (
888 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
889 IN UINTN ModeNumber,
890 OUT UINTN *Columns,
891 OUT UINTN *Rows
892 )
893 {
894 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
895 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
896 //
897 // Forward the request to the original ConOut
898 //
899 return (ConsoleInfo->OldConOut->QueryMode (
900 ConsoleInfo->OldConOut,
901 ModeNumber,
902 Columns,
903 Rows
904 ));
905 }
906
907 /**
908 Sets the output device(s) to a specified mode.
909
910 @param[in] This Protocol instance pointer.
911 @param[in] ModeNumber The mode number to set.
912
913
914 @retval EFI_SUCCESS The requested text mode was set.
915 @retval EFI_DEVICE_ERROR The device had an error and
916 could not complete the request.
917 @retval EFI_UNSUPPORTED The mode number was not valid.
918 **/
919 EFI_STATUS
920 EFIAPI
921 ConsoleLoggerSetMode (
922 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
923 IN UINTN ModeNumber
924 )
925 {
926 EFI_STATUS Status;
927
928 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
929 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
930
931 //
932 // Forward the request to the original ConOut
933 //
934 Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber);
935
936 //
937 // Check that the buffers are still correct for logging
938 //
939 if (!EFI_ERROR (Status)) {
940 ConsoleInfo->OurConOut.Mode = gST->ConOut->Mode;
941 ConsoleLoggerResetBuffers(ConsoleInfo);
942 }
943
944 return Status;
945 }
946
947 /**
948 Sets the background and foreground colors for the OutputString () and
949 ClearScreen () functions.
950
951 @param[in] This Protocol instance pointer.
952 @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
953 bits 4..6 are the background color. All other bits are undefined
954 and must be zero. The valid Attributes are defined in this file.
955
956 @retval EFI_SUCCESS The attribute was set.
957 @retval EFI_DEVICE_ERROR The device had an error and
958 could not complete the request.
959 @retval EFI_UNSUPPORTED The attribute requested is not defined.
960
961 **/
962 EFI_STATUS
963 EFIAPI
964 ConsoleLoggerSetAttribute (
965 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
966 IN UINTN Attribute
967 )
968 {
969 EFI_STATUS Status;
970
971 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
972 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
973
974 //
975 // Forward the request to the original ConOut
976 //
977 Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute);
978
979 //
980 // Record console output history
981 //
982 if (!EFI_ERROR (Status)) {
983 ConsoleInfo->HistoryMode.Attribute = (INT32) Attribute;
984 }
985
986 return Status;
987 }
988
989 /**
990 Clears the output device(s) display to the currently selected background
991 color.
992
993 @param[in] This Protocol instance pointer.
994
995 @retval EFI_SUCCESS The operation completed successfully.
996 @retval EFI_DEVICE_ERROR The device had an error and
997 could not complete the request.
998 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
999 **/
1000 EFI_STATUS
1001 EFIAPI
1002 ConsoleLoggerClearScreen (
1003 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
1004 )
1005 {
1006 EFI_STATUS Status;
1007 CHAR16 *Screen;
1008 INT32 *Attributes;
1009 UINTN Row;
1010 UINTN Column;
1011 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1012
1013 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
1014 return (EFI_UNSUPPORTED);
1015 }
1016
1017 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1018
1019 //
1020 // Forward the request to the original ConOut
1021 //
1022 Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
1023
1024 //
1025 // Record console output history
1026 //
1027 if (!EFI_ERROR (Status)) {
1028 Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
1029 Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
1030 for ( Row = ConsoleInfo->OriginalStartRow
1031 ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)
1032 ; Row++
1033 ){
1034 for ( Column = 0
1035 ; Column < ConsoleInfo->ColsPerScreen
1036 ; Column++
1037 , Screen++
1038 , Attributes++
1039 ){
1040 *Screen = L' ';
1041 *Attributes = ConsoleInfo->OldConOut->Mode->Attribute;
1042 }
1043 //
1044 // Skip the NULL on each column end in text buffer only
1045 //
1046 Screen += 2;
1047 }
1048 ConsoleInfo->HistoryMode.CursorColumn = 0;
1049 ConsoleInfo->HistoryMode.CursorRow = 0;
1050 }
1051
1052 return Status;
1053 }
1054
1055 /**
1056 Sets the current coordinates of the cursor position
1057
1058 @param[in] This Protocol instance pointer.
1059 @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
1060 @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
1061
1062 @retval EFI_SUCCESS The operation completed successfully.
1063 @retval EFI_DEVICE_ERROR The device had an error and
1064 could not complete the request.
1065 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
1066 cursor position is invalid for the current mode.
1067 **/
1068 EFI_STATUS
1069 EFIAPI
1070 ConsoleLoggerSetCursorPosition (
1071 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1072 IN UINTN Column,
1073 IN UINTN Row
1074 )
1075 {
1076 EFI_STATUS Status;
1077 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1078
1079 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
1080 return (EFI_UNSUPPORTED);
1081 }
1082
1083 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1084 //
1085 // Forward the request to the original ConOut
1086 //
1087 Status = ConsoleInfo->OldConOut->SetCursorPosition (
1088 ConsoleInfo->OldConOut,
1089 Column,
1090 Row
1091 );
1092
1093 //
1094 // Record console output history
1095 //
1096 if (!EFI_ERROR (Status)) {
1097 ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column;
1098 ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row);
1099 }
1100
1101 return Status;
1102 }
1103
1104 /**
1105 Makes the cursor visible or invisible
1106
1107 @param[in] This Protocol instance pointer.
1108 @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
1109 set to be invisible.
1110
1111 @retval EFI_SUCCESS The operation completed successfully.
1112 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1113 request, or the device does not support changing
1114 the cursor mode.
1115 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1116 **/
1117 EFI_STATUS
1118 EFIAPI
1119 ConsoleLoggerEnableCursor (
1120 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1121 IN BOOLEAN Visible
1122 )
1123 {
1124 EFI_STATUS Status;
1125
1126 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1127 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1128 //
1129 // Forward the request to the original ConOut
1130 //
1131 Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible);
1132
1133 //
1134 // Record console output history
1135 //
1136 if (!EFI_ERROR (Status)) {
1137 ConsoleInfo->HistoryMode.CursorVisible = Visible;
1138 }
1139
1140 return Status;
1141 }
1142
1143 /**
1144 Function to update and verify that the current buffers are correct.
1145
1146 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
1147
1148 This will be used when a mode has changed or a reset ocurred to verify all
1149 history buffers.
1150 **/
1151 EFI_STATUS
1152 EFIAPI
1153 ConsoleLoggerResetBuffers(
1154 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
1155 )
1156 {
1157 EFI_STATUS Status;
1158
1159 if (ConsoleInfo->Buffer != NULL) {
1160 FreePool(ConsoleInfo->Buffer);
1161 ConsoleInfo->Buffer = NULL;
1162 ConsoleInfo->BufferSize = 0;
1163 }
1164 if (ConsoleInfo->Attributes != NULL) {
1165 FreePool(ConsoleInfo->Attributes);
1166 ConsoleInfo->Attributes = NULL;
1167 ConsoleInfo->AttribSize = 0;
1168 }
1169
1170 Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen);
1171 if (EFI_ERROR(Status)){
1172 return (Status);
1173 }
1174
1175 ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Buffer[0]);
1176 ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Attributes[0]);
1177
1178 ConsoleInfo->Buffer = (CHAR16*)AllocateZeroPool(ConsoleInfo->BufferSize);
1179
1180 if (ConsoleInfo->Buffer == NULL) {
1181 return (EFI_OUT_OF_RESOURCES);
1182 }
1183
1184 ConsoleInfo->Attributes = (INT32*)AllocateZeroPool(ConsoleInfo->AttribSize);
1185 if (ConsoleInfo->Attributes == NULL) {
1186 FreePool(ConsoleInfo->Buffer);
1187 ConsoleInfo->Buffer = NULL;
1188 return (EFI_OUT_OF_RESOURCES);
1189 }
1190
1191 CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE));
1192
1193 return (EFI_SUCCESS);
1194 }