2 Provides interface to shell console logger.
4 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Install our intermediate ConOut into the system table to
19 keep a log of all the info that is displayed to the user.
21 @param[in] ScreensToSave Sets how many screen-worths of data to save.
22 @param[out] ConsoleInfo The object to pass into later functions.
24 @retval EFI_SUCCESS The operation was successful.
25 @return other The operation failed.
27 @sa ConsoleLoggerResetBuffers
28 @sa InstallProtocolInterface
33 IN CONST UINTN ScreensToSave
,
34 OUT CONSOLE_LOGGER_PRIVATE_DATA
**ConsoleInfo
38 ASSERT(ConsoleInfo
!= NULL
);
40 (*ConsoleInfo
) = AllocateZeroPool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA
));
41 if ((*ConsoleInfo
) == NULL
) {
42 return (EFI_OUT_OF_RESOURCES
);
45 (*ConsoleInfo
)->Signature
= CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE
;
46 (*ConsoleInfo
)->OldConOut
= gST
->ConOut
;
47 (*ConsoleInfo
)->OldConHandle
= gST
->ConsoleOutHandle
;
48 (*ConsoleInfo
)->Buffer
= NULL
;
49 (*ConsoleInfo
)->BufferSize
= 0;
50 (*ConsoleInfo
)->OriginalStartRow
= 0;
51 (*ConsoleInfo
)->CurrentStartRow
= 0;
52 (*ConsoleInfo
)->RowsPerScreen
= 0;
53 (*ConsoleInfo
)->ColsPerScreen
= 0;
54 (*ConsoleInfo
)->Attributes
= NULL
;
55 (*ConsoleInfo
)->AttribSize
= 0;
56 (*ConsoleInfo
)->ScreenCount
= ScreensToSave
;
57 (*ConsoleInfo
)->HistoryMode
.MaxMode
= 1;
58 (*ConsoleInfo
)->HistoryMode
.Mode
= 0;
59 (*ConsoleInfo
)->HistoryMode
.Attribute
= 0;
60 (*ConsoleInfo
)->HistoryMode
.CursorColumn
= 0;
61 (*ConsoleInfo
)->HistoryMode
.CursorRow
= 0;
62 (*ConsoleInfo
)->HistoryMode
.CursorVisible
= FALSE
;
63 (*ConsoleInfo
)->OurConOut
.Reset
= ConsoleLoggerReset
;
64 (*ConsoleInfo
)->OurConOut
.OutputString
= ConsoleLoggerOutputString
;
65 (*ConsoleInfo
)->OurConOut
.TestString
= ConsoleLoggerTestString
;
66 (*ConsoleInfo
)->OurConOut
.QueryMode
= ConsoleLoggerQueryMode
;
67 (*ConsoleInfo
)->OurConOut
.SetMode
= ConsoleLoggerSetMode
;
68 (*ConsoleInfo
)->OurConOut
.SetAttribute
= ConsoleLoggerSetAttribute
;
69 (*ConsoleInfo
)->OurConOut
.ClearScreen
= ConsoleLoggerClearScreen
;
70 (*ConsoleInfo
)->OurConOut
.SetCursorPosition
= ConsoleLoggerSetCursorPosition
;
71 (*ConsoleInfo
)->OurConOut
.EnableCursor
= ConsoleLoggerEnableCursor
;
72 (*ConsoleInfo
)->OurConOut
.Mode
= gST
->ConOut
->Mode
;
73 (*ConsoleInfo
)->Enabled
= TRUE
;
75 Status
= ConsoleLoggerResetBuffers(*ConsoleInfo
);
76 if (EFI_ERROR(Status
)) {
77 SHELL_FREE_NON_NULL((*ConsoleInfo
));
82 Status
= gBS
->InstallProtocolInterface(&gImageHandle
, &gEfiSimpleTextOutProtocolGuid
, EFI_NATIVE_INTERFACE
, (VOID
*)&((*ConsoleInfo
)->OurConOut
));
83 if (EFI_ERROR(Status
)) {
84 SHELL_FREE_NON_NULL((*ConsoleInfo
)->Buffer
);
85 SHELL_FREE_NON_NULL((*ConsoleInfo
)->Attributes
);
86 SHELL_FREE_NON_NULL((*ConsoleInfo
));
91 gST
->ConsoleOutHandle
= gImageHandle
;
92 gST
->ConOut
= &(*ConsoleInfo
)->OurConOut
;
98 Return the system to the state it was before InstallConsoleLogger
101 @param[in] ConsoleInfo The object from the install function.
103 @retval EFI_SUCCESS The operation was successful
104 @return other The operation failed. This was from UninstallProtocolInterface.
108 ConsoleLoggerUninstall(
109 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
112 ASSERT(ConsoleInfo
!= NULL
);
113 ASSERT(ConsoleInfo
->OldConOut
!= NULL
);
115 if (ConsoleInfo
->Buffer
!= NULL
) {
116 FreePool(ConsoleInfo
->Buffer
);
117 DEBUG_CODE(ConsoleInfo
->Buffer
= NULL
;);
118 DEBUG_CODE(ConsoleInfo
->BufferSize
= 0;);
120 if (ConsoleInfo
->Attributes
!= NULL
) {
121 FreePool(ConsoleInfo
->Attributes
);
122 DEBUG_CODE(ConsoleInfo
->Attributes
= NULL
;);
123 DEBUG_CODE(ConsoleInfo
->AttribSize
= 0;);
126 gST
->ConsoleOutHandle
= ConsoleInfo
->OldConHandle
;
127 gST
->ConOut
= ConsoleInfo
->OldConOut
;
129 return (gBS
->UninstallProtocolInterface(gImageHandle
, &gEfiSimpleTextOutProtocolGuid
, (VOID
*)&ConsoleInfo
->OurConOut
));
133 Displays previously logged output back to the screen.
135 This will scroll the screen forwards and backwards through the log of previous
136 output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
137 is (UINTN)(-1) then the size of the screen will be scrolled.
139 @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
140 If FALSE then the log will be displayed backwards (scroll to older).
141 @param[in] Rows Determines how many rows the log should scroll.
142 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
146 ConsoleLoggerDisplayHistory(
147 IN CONST BOOLEAN Forward
,
149 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
154 ASSERT(ConsoleInfo
!= NULL
);
157 // Calculate the row number change
161 RowChange
= ConsoleInfo
->RowsPerScreen
;
164 RowChange
= ConsoleInfo
->RowsPerScreen
/ 2;
172 // Do the math for direction
175 if ((ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
) < RowChange
) {
176 RowChange
= ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
;
179 if (ConsoleInfo
->CurrentStartRow
< RowChange
) {
180 RowChange
= ConsoleInfo
->CurrentStartRow
;
185 // If we are already at one end or the other
187 if (RowChange
== 0) {
188 return (EFI_SUCCESS
);
194 ConsoleInfo
->OldConOut
->ClearScreen(ConsoleInfo
->OldConOut
);
197 // Set the new start row
200 ConsoleInfo
->CurrentStartRow
+= RowChange
;
202 ConsoleInfo
->CurrentStartRow
-= RowChange
;
208 return (UpdateDisplayFromHistory(ConsoleInfo
));
212 Function to return to normal output whent he scrolling is complete.
213 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
215 @retval EFI_SUCCESS The operation was successful.
216 @return other The operation failed. See UpdateDisplayFromHistory.
218 @sa UpdateDisplayFromHistory
222 ConsoleLoggerStopHistory(
223 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
226 ASSERT(ConsoleInfo
!= NULL
);
227 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
228 return (EFI_SUCCESS
);
234 ConsoleInfo
->OldConOut
->ClearScreen(ConsoleInfo
->OldConOut
);
236 ConsoleInfo
->CurrentStartRow
= ConsoleInfo
->OriginalStartRow
;
237 return (UpdateDisplayFromHistory(ConsoleInfo
));
241 Updates the hidden ConOut to be displaying the correct stuff.
242 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
244 @retval EFI_SUCCESS The operation was successful.
245 @return other The operation failed.
249 UpdateDisplayFromHistory(
250 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
258 CHAR16 TempCharHolder
;
262 CHAR16
*StringSegment
;
263 CHAR16
*StringSegmentEnd
;
264 CHAR16 StringSegmentEndChar
;
267 ASSERT(ConsoleInfo
!= NULL
);
268 TempCharHolder
= CHAR_NULL
;
269 RetVal
= EFI_SUCCESS
;
270 OrigAttribute
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
273 // Disable cursor visibility and move it to the top left corner
275 ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, FALSE
);
276 ConsoleInfo
->OldConOut
->SetCursorPosition (ConsoleInfo
->OldConOut
, 0, 0);
278 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
279 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
281 ; CurrentRow
< ConsoleInfo
->RowsPerScreen
283 , Screen
+= (ConsoleInfo
->ColsPerScreen
+ 2)
284 , Attributes
+= ConsoleInfo
->ColsPerScreen
287 // dont use the last char - prevents screen scroll
289 if (CurrentRow
== (ConsoleInfo
->RowsPerScreen
-1)){
290 TempCharHolder
= Screen
[ConsoleInfo
->ColsPerScreen
- 1];
291 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = CHAR_NULL
;
295 ; Column
< ConsoleInfo
->ColsPerScreen
298 if (Screen
[Column
] != CHAR_NULL
) {
299 CurrentAttrib
= Attributes
[Column
];
300 CurrentColumn
= Column
;
301 StringSegment
= &Screen
[Column
];
304 // Find the first char with a different arrribute and make that temporarily NULL
305 // so we can do fewer printout statements. (later) restore that one and we will
306 // start at that collumn on the next loop.
308 StringSegmentEndChar
= CHAR_NULL
;
309 for ( StringSegmentEnd
= StringSegment
310 ; StringSegmentEnd
!= CHAR_NULL
314 if (Attributes
[Column
] != CurrentAttrib
) {
315 StringSegmentEndChar
= *StringSegmentEnd
;
316 *StringSegmentEnd
= CHAR_NULL
;
319 } // StringSegmentEnd loop
322 // Now write out as much as had the same Attributes
325 ConsoleInfo
->OldConOut
->SetAttribute(ConsoleInfo
->OldConOut
, CurrentAttrib
);
326 ConsoleInfo
->OldConOut
->SetCursorPosition(ConsoleInfo
->OldConOut
, CurrentColumn
, CurrentRow
);
327 Status
= ConsoleInfo
->OldConOut
->OutputString(ConsoleInfo
->OldConOut
, StringSegment
);
329 if (EFI_ERROR(Status
)) {
335 // If we found a change in attribute put the character back and decrement the column
336 // so when it increments it will point at that character and we will start printing
337 // a segment with that new attribute
339 if (StringSegmentEndChar
!= CHAR_NULL
) {
340 *StringSegmentEnd
= StringSegmentEndChar
;
341 StringSegmentEndChar
= CHAR_NULL
;
348 // If we removed the last char and this was the last row put it back
350 if (TempCharHolder
!= CHAR_NULL
) {
351 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = TempCharHolder
;
352 TempCharHolder
= CHAR_NULL
;
357 // If we are setting the screen back to original turn on the cursor and make it visible
358 // and set the attributes back to what they were
360 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
361 ConsoleInfo
->OldConOut
->SetAttribute (
362 ConsoleInfo
->OldConOut
,
363 ConsoleInfo
->HistoryMode
.Attribute
365 ConsoleInfo
->OldConOut
->SetCursorPosition (
366 ConsoleInfo
->OldConOut
,
367 ConsoleInfo
->HistoryMode
.CursorColumn
,
368 ConsoleInfo
->HistoryMode
.CursorRow
- ConsoleInfo
->OriginalStartRow
371 Status
= ConsoleInfo
->OldConOut
->EnableCursor (
372 ConsoleInfo
->OldConOut
,
373 ConsoleInfo
->HistoryMode
.CursorVisible
375 if (EFI_ERROR (Status
)) {
379 ConsoleInfo
->OldConOut
->SetAttribute (
380 ConsoleInfo
->OldConOut
,
389 Reset the text output device hardware and optionaly run diagnostics
391 @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
392 @param ExtendedVerification Indicates that a more extensive test may be performed
394 @retval EFI_SUCCESS The text output device was reset.
395 @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
401 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
402 IN BOOLEAN ExtendedVerification
406 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
407 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
410 // Forward the request to the original ConOut
412 Status
= ConsoleInfo
->OldConOut
->Reset (ConsoleInfo
->OldConOut
, ExtendedVerification
);
415 // Check that the buffers are still correct for logging
417 if (!EFI_ERROR (Status
)) {
418 ConsoleLoggerResetBuffers(ConsoleInfo
);
419 if (ExtendedVerification
) {
420 ConsoleInfo
->OriginalStartRow
= 0;
421 ConsoleInfo
->CurrentStartRow
= 0;
429 Appends a string to the history buffer. If the buffer is full then the oldest
430 information in the buffer will be dropped. Information is added in a line by
431 line manner such that an empty line takes up just as much space as a full line.
433 @param[in] String String pointer to add.
434 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
438 AppendStringToHistory(
439 IN CONST CHAR16
*String
,
440 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
443 CONST CHAR16
*Walker
;
448 ASSERT(ConsoleInfo
!= NULL
);
450 for ( Walker
= String
451 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
455 case (CHAR_BACKSPACE
):
456 if (ConsoleInfo
->HistoryMode
.CursorColumn
> 0) {
457 ConsoleInfo
->HistoryMode
.CursorColumn
--;
460 case (CHAR_LINEFEED
):
461 if (ConsoleInfo
->HistoryMode
.CursorRow
>= (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1)) {
463 // Should never be bigger
465 ASSERT(ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1));
468 // scroll history attributes 'up' 1 row and set the last row to default attribute
470 CopySize
= ConsoleInfo
->ColsPerScreen
471 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
472 * sizeof(ConsoleInfo
->Attributes
[0]);
473 ASSERT(CopySize
< ConsoleInfo
->AttribSize
);
475 ConsoleInfo
->Attributes
,
476 ConsoleInfo
->Attributes
+ ConsoleInfo
->ColsPerScreen
,
481 ; Index
< ConsoleInfo
->ColsPerScreen
484 *(ConsoleInfo
->Attributes
+ (CopySize
/sizeof(ConsoleInfo
->Attributes
[0])) + Index
) = ConsoleInfo
->HistoryMode
.Attribute
;
488 // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
490 CopySize
= (ConsoleInfo
->ColsPerScreen
+ 2)
491 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
492 * sizeof(ConsoleInfo
->Buffer
[0]);
493 ASSERT(CopySize
< ConsoleInfo
->BufferSize
);
496 ConsoleInfo
->Buffer
+ (ConsoleInfo
->ColsPerScreen
+ 2),
501 // Set that last row of chars to spaces
503 SetMem16(((UINT8
*)ConsoleInfo
->Buffer
)+CopySize
, ConsoleInfo
->ColsPerScreen
*sizeof(CHAR16
), L
' ');
506 // we are not on the last row
510 // We should not be scrolling history
512 ASSERT (ConsoleInfo
->OriginalStartRow
== ConsoleInfo
->CurrentStartRow
);
514 // are we at the end of a row?
516 if (ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
) (ConsoleInfo
->OriginalStartRow
+ ConsoleInfo
->RowsPerScreen
- 1)) {
517 ConsoleInfo
->OriginalStartRow
++;
518 ConsoleInfo
->CurrentStartRow
++;
520 ConsoleInfo
->HistoryMode
.CursorRow
++;
523 case (CHAR_CARRIAGE_RETURN
):
525 // Move the cursor to the beginning of the current row.
527 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
531 // Acrtually print characters into the history buffer
534 PrintIndex
= ConsoleInfo
->HistoryMode
.CursorRow
* ConsoleInfo
->ColsPerScreen
+ ConsoleInfo
->HistoryMode
.CursorColumn
;
536 for ( // no initializer needed
537 ; ConsoleInfo
->HistoryMode
.CursorColumn
< (INT32
) ConsoleInfo
->ColsPerScreen
538 ; ConsoleInfo
->HistoryMode
.CursorColumn
++
542 if (*Walker
== CHAR_NULL
543 ||*Walker
== CHAR_BACKSPACE
544 ||*Walker
== CHAR_LINEFEED
545 ||*Walker
== CHAR_CARRIAGE_RETURN
551 // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
554 ASSERT(PrintIndex
+ ConsoleInfo
->HistoryMode
.CursorRow
< ConsoleInfo
->BufferSize
);
555 ConsoleInfo
->Buffer
[PrintIndex
+ (2*ConsoleInfo
->HistoryMode
.CursorRow
)] = *Walker
;
556 ASSERT(PrintIndex
< ConsoleInfo
->AttribSize
);
557 ConsoleInfo
->Attributes
[PrintIndex
] = ConsoleInfo
->HistoryMode
.Attribute
;
561 // Add the carriage return and line feed at the end of the lines
563 if (ConsoleInfo
->HistoryMode
.CursorColumn
>= (INT32
)ConsoleInfo
->ColsPerScreen
) {
564 AppendStringToHistory(L
"\r\n", ConsoleInfo
);
569 } // switch for character
572 return (EFI_SUCCESS
);
576 Worker function to handle printing the output to the screen
577 and the history buffer
579 @param[in] String The string to output
580 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
582 @retval EFI_SUCCESS The string was printed
583 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
585 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
587 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
588 characters in the Unicode string could not be
589 rendered and were skipped.
593 ConsoleLoggerOutputStringSplit(
594 IN CONST CHAR16
*String
,
595 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
601 // Forward the request to the original ConOut
603 Status
= ConsoleInfo
->OldConOut
->OutputString (ConsoleInfo
->OldConOut
, (CHAR16
*)String
);
605 if (EFI_ERROR(Status
)) {
609 return (AppendStringToHistory(String
, ConsoleInfo
));
613 Function to handle page break mode.
615 This function will prompt for continue or break.
617 @retval EFI_SUCCESS Continue was choosen
618 @return other Break was choosen
622 ConsoleLoggerDoPageBreak(
626 SHELL_PROMPT_RESPONSE
*Resp
;
630 ASSERT(ShellInfoObject
.PageBreakEnabled
);
631 ShellInfoObject
.PageBreakEnabled
= FALSE
;
632 Status
= ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue
, STRING_TOKEN(STR_SHELL_QUIT_CONT
), ShellInfoObject
.HiiHandle
, (VOID
**)&Resp
);
633 ShellInfoObject
.PageBreakEnabled
= TRUE
;
634 ASSERT(Resp
!= NULL
);
636 return (EFI_NOT_FOUND
);
638 if (EFI_ERROR(Status
)) {
644 if (*Resp
== ShellPromptResponseContinue
) {
646 ShellInfoObject
.ConsoleInfo
->RowCounter
= 0;
647 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
648 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
650 return (EFI_SUCCESS
);
651 } else if (*Resp
== ShellPromptResponseQuit
) {
653 ShellInfoObject
.ConsoleInfo
->Enabled
= FALSE
;
655 // When user wants to quit, the shell should stop running the command.
657 gBS
->SignalEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
);
658 return (EFI_DEVICE_ERROR
);
662 return (EFI_SUCCESS
);
665 Worker function to handle printing the output with page breaks.
667 @param[in] String The string to output
668 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
670 @retval EFI_SUCCESS The string was printed
671 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
673 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
675 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
676 characters in the Unicode string could not be
677 rendered and were skipped.
681 ConsoleLoggerPrintWithPageBreak(
682 IN CONST CHAR16
*String
,
683 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
686 CONST CHAR16
*Walker
;
687 CONST CHAR16
*LineStart
;
692 StringCopy
= StrnCatGrow(&StringCopy
, NULL
, String
, 0);
693 if (StringCopy
== NULL
) {
694 return (EFI_OUT_OF_RESOURCES
);
697 for ( Walker
= StringCopy
698 , LineStart
= StringCopy
699 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
703 case (CHAR_BACKSPACE
):
704 if (ConsoleInfo
->OurConOut
.Mode
->CursorColumn
> 0) {
705 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
--;
708 case (CHAR_LINEFEED
):
710 // add a temp NULL terminator
712 TempChar
= *(Walker
+ 1);
713 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
718 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
721 // restore the temp NULL terminator to it's original character
723 *((CHAR16
*)(Walker
+1)) = TempChar
;
726 // Update LineStart Variable
728 LineStart
= Walker
+ 1;
731 // increment row count
733 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
734 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
737 case (CHAR_CARRIAGE_RETURN
):
739 // Move the cursor to the beginning of the current row.
741 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
745 // increment column count
747 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
++;
749 // check if that is the last column
751 if ((INTN
)ConsoleInfo
->ColsPerScreen
== ConsoleInfo
->OurConOut
.Mode
->CursorColumn
+ 1) {
753 // output a line similar to the linefeed character.
757 // add a temp NULL terminator
759 TempChar
= *(Walker
+ 1);
760 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
765 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
768 // restore the temp NULL terminator to it's original character
770 *((CHAR16
*)(Walker
+1)) = TempChar
;
773 // Update LineStart Variable
775 LineStart
= Walker
+ 1;
778 // increment row count and zero the column
780 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
781 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
782 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
783 } // last column on line
785 } // switch for character
788 // check if that was the last printable row. If yes handle PageBreak mode
790 if ((ConsoleInfo
->RowsPerScreen
) -1 == ShellInfoObject
.ConsoleInfo
->RowCounter
) {
791 if (EFI_ERROR(ConsoleLoggerDoPageBreak())) {
793 // We got an error which means 'break' and halt the printing
795 SHELL_FREE_NON_NULL(StringCopy
);
796 return (EFI_DEVICE_ERROR
);
801 if (LineStart
!= NULL
&& *LineStart
!= CHAR_NULL
) {
802 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
805 SHELL_FREE_NON_NULL(StringCopy
);
806 return (EFI_SUCCESS
);
810 Write a Unicode string to the output device.
812 @param[in] This Protocol instance pointer.
813 @param[in] WString The NULL-terminated Unicode string to be displayed on the output
814 device(s). All output devices must also support the Unicode
815 drawing defined in this file.
816 @retval EFI_SUCCESS The string was output to the device.
817 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
819 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
821 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
822 characters in the Unicode string could not be
823 rendered and were skipped.
827 ConsoleLoggerOutputString (
828 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
833 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
834 EFI_KEY_DATA KeyData
;
836 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
838 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
839 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
840 return (EFI_UNSUPPORTED
);
842 ASSERT(ShellInfoObject
.ConsoleInfo
== ConsoleInfo
);
844 Status
= gBS
->HandleProtocol (gST
->ConsoleInHandle
, &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
845 if (!EFI_ERROR (Status
)) {
846 while (ShellInfoObject
.HaltOutput
) {
848 ShellInfoObject
.HaltOutput
= FALSE
;
852 Status
= gBS
->WaitForEvent (1, &TxtInEx
->WaitForKeyEx
, &EventIndex
);
853 ASSERT_EFI_ERROR (Status
);
854 Status
= TxtInEx
->ReadKeyStrokeEx (TxtInEx
, &KeyData
);
855 if (EFI_ERROR(Status
)) {
859 if ((KeyData
.Key
.UnicodeChar
== L
's') && (KeyData
.Key
.ScanCode
== SCAN_NULL
) &&
860 ((KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_LEFT_CONTROL_PRESSED
)) ||
861 (KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_RIGHT_CONTROL_PRESSED
))
864 ShellInfoObject
.HaltOutput
= TRUE
;
869 if (!ShellInfoObject
.ConsoleInfo
->Enabled
) {
870 return (EFI_DEVICE_ERROR
);
871 } else if (ShellInfoObject
.PageBreakEnabled
) {
872 return (ConsoleLoggerPrintWithPageBreak(WString
, ConsoleInfo
));
874 return (ConsoleLoggerOutputStringSplit(WString
, ConsoleInfo
));
879 Verifies that all characters in a Unicode string can be output to the
882 @param[in] This Protocol instance pointer.
883 @param[in] WString The NULL-terminated Unicode string to be examined for the output
886 @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
887 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
888 rendered by one or more of the output devices mapped
894 ConsoleLoggerTestString (
895 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
899 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
900 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
902 // Forward the request to the original ConOut
904 return (ConsoleInfo
->OldConOut
->TestString (ConsoleInfo
->OldConOut
, WString
));
908 Returns information for an available text mode that the output device(s)
911 @param[in] This Protocol instance pointer.
912 @param[in] ModeNumber The mode number to return information on.
913 @param[out] Columns Upon return, the number of columns in the selected geometry
914 @param[out] Rows Upon return, the number of rows in the selected geometry
916 @retval EFI_SUCCESS The requested mode information was returned.
917 @retval EFI_DEVICE_ERROR The device had an error and could not
918 complete the request.
919 @retval EFI_UNSUPPORTED The mode number was not valid.
923 ConsoleLoggerQueryMode (
924 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
930 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
931 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
933 // Forward the request to the original ConOut
935 return (ConsoleInfo
->OldConOut
->QueryMode (
936 ConsoleInfo
->OldConOut
,
944 Sets the output device(s) to a specified mode.
946 @param[in] This Protocol instance pointer.
947 @param[in] ModeNumber The mode number to set.
950 @retval EFI_SUCCESS The requested text mode was set.
951 @retval EFI_DEVICE_ERROR The device had an error and
952 could not complete the request.
953 @retval EFI_UNSUPPORTED The mode number was not valid.
957 ConsoleLoggerSetMode (
958 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
964 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
965 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
968 // Forward the request to the original ConOut
970 Status
= ConsoleInfo
->OldConOut
->SetMode (ConsoleInfo
->OldConOut
, ModeNumber
);
973 // Check that the buffers are still correct for logging
975 if (!EFI_ERROR (Status
)) {
976 ConsoleInfo
->OurConOut
.Mode
= ConsoleInfo
->OldConOut
->Mode
;
977 ConsoleLoggerResetBuffers(ConsoleInfo
);
978 ConsoleInfo
->OriginalStartRow
= 0;
979 ConsoleInfo
->CurrentStartRow
= 0;
980 ConsoleInfo
->OurConOut
.ClearScreen (&ConsoleInfo
->OurConOut
);
987 Sets the background and foreground colors for the OutputString () and
988 ClearScreen () functions.
990 @param[in] This Protocol instance pointer.
991 @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
992 bits 4..6 are the background color. All other bits are undefined
993 and must be zero. The valid Attributes are defined in this file.
995 @retval EFI_SUCCESS The attribute was set.
996 @retval EFI_DEVICE_ERROR The device had an error and
997 could not complete the request.
998 @retval EFI_UNSUPPORTED The attribute requested is not defined.
1003 ConsoleLoggerSetAttribute (
1004 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1010 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1011 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1014 // Forward the request to the original ConOut
1016 Status
= ConsoleInfo
->OldConOut
->SetAttribute (ConsoleInfo
->OldConOut
, Attribute
);
1019 // Record console output history
1021 if (!EFI_ERROR (Status
)) {
1022 ConsoleInfo
->HistoryMode
.Attribute
= (INT32
) Attribute
;
1029 Clears the output device(s) display to the currently selected background
1032 @param[in] This Protocol instance pointer.
1034 @retval EFI_SUCCESS The operation completed successfully.
1035 @retval EFI_DEVICE_ERROR The device had an error and
1036 could not complete the request.
1037 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1041 ConsoleLoggerClearScreen (
1042 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
1050 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1052 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1053 return (EFI_UNSUPPORTED
);
1056 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1059 // Forward the request to the original ConOut
1061 Status
= ConsoleInfo
->OldConOut
->ClearScreen (ConsoleInfo
->OldConOut
);
1064 // Record console output history
1066 if (!EFI_ERROR (Status
)) {
1067 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
1068 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
1069 for ( Row
= ConsoleInfo
->OriginalStartRow
1070 ; Row
< (ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)
1074 ; Column
< ConsoleInfo
->ColsPerScreen
1080 *Attributes
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
1083 // Skip the NULL on each column end in text buffer only
1087 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
1088 ConsoleInfo
->HistoryMode
.CursorRow
= 0;
1095 Sets the current coordinates of the cursor position
1097 @param[in] This Protocol instance pointer.
1098 @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
1099 @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
1101 @retval EFI_SUCCESS The operation completed successfully.
1102 @retval EFI_DEVICE_ERROR The device had an error and
1103 could not complete the request.
1104 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
1105 cursor position is invalid for the current mode.
1109 ConsoleLoggerSetCursorPosition (
1110 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1116 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1118 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1119 return (EFI_UNSUPPORTED
);
1122 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1124 // Forward the request to the original ConOut
1126 Status
= ConsoleInfo
->OldConOut
->SetCursorPosition (
1127 ConsoleInfo
->OldConOut
,
1133 // Record console output history
1135 if (!EFI_ERROR (Status
)) {
1136 ConsoleInfo
->HistoryMode
.CursorColumn
= (INT32
)Column
;
1137 ConsoleInfo
->HistoryMode
.CursorRow
= (INT32
)(ConsoleInfo
->OriginalStartRow
+ Row
);
1144 Makes the cursor visible or invisible
1146 @param[in] This Protocol instance pointer.
1147 @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
1148 set to be invisible.
1150 @retval EFI_SUCCESS The operation completed successfully.
1151 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1152 request, or the device does not support changing
1154 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1158 ConsoleLoggerEnableCursor (
1159 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1165 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1166 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1168 // Forward the request to the original ConOut
1170 Status
= ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, Visible
);
1173 // Record console output history
1175 if (!EFI_ERROR (Status
)) {
1176 ConsoleInfo
->HistoryMode
.CursorVisible
= Visible
;
1183 Function to update and verify that the current buffers are correct.
1185 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
1187 This will be used when a mode has changed or a reset ocurred to verify all
1192 ConsoleLoggerResetBuffers(
1193 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
1198 if (ConsoleInfo
->Buffer
!= NULL
) {
1199 FreePool(ConsoleInfo
->Buffer
);
1200 ConsoleInfo
->Buffer
= NULL
;
1201 ConsoleInfo
->BufferSize
= 0;
1203 if (ConsoleInfo
->Attributes
!= NULL
) {
1204 FreePool(ConsoleInfo
->Attributes
);
1205 ConsoleInfo
->Attributes
= NULL
;
1206 ConsoleInfo
->AttribSize
= 0;
1209 Status
= gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &ConsoleInfo
->ColsPerScreen
, &ConsoleInfo
->RowsPerScreen
);
1210 if (EFI_ERROR(Status
)){
1214 ConsoleInfo
->BufferSize
= (ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof(ConsoleInfo
->Buffer
[0]);
1215 ConsoleInfo
->AttribSize
= ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof(ConsoleInfo
->Attributes
[0]);
1217 ConsoleInfo
->Buffer
= (CHAR16
*)AllocateZeroPool(ConsoleInfo
->BufferSize
);
1219 if (ConsoleInfo
->Buffer
== NULL
) {
1220 return (EFI_OUT_OF_RESOURCES
);
1223 ConsoleInfo
->Attributes
= (INT32
*)AllocateZeroPool(ConsoleInfo
->AttribSize
);
1224 if (ConsoleInfo
->Attributes
== NULL
) {
1225 FreePool(ConsoleInfo
->Buffer
);
1226 ConsoleInfo
->Buffer
= NULL
;
1227 return (EFI_OUT_OF_RESOURCES
);
1230 CopyMem (&ConsoleInfo
->HistoryMode
, ConsoleInfo
->OldConOut
->Mode
, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE
));
1232 return (EFI_SUCCESS
);