2 Provides interface to shell console logger.
4 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2016 Hewlett-Packard Development Company, L.P.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Install our intermediate ConOut into the system table to
14 keep a log of all the info that is displayed to the user.
16 @param[in] ScreensToSave Sets how many screen-worths of data to save.
17 @param[out] ConsoleInfo The object to pass into later functions.
19 @retval EFI_SUCCESS The operation was successful.
20 @return other The operation failed.
22 @sa ConsoleLoggerResetBuffers
23 @sa InstallProtocolInterface
26 ConsoleLoggerInstall (
27 IN CONST UINTN ScreensToSave
,
28 OUT CONSOLE_LOGGER_PRIVATE_DATA
**ConsoleInfo
33 ASSERT (ConsoleInfo
!= NULL
);
35 (*ConsoleInfo
) = AllocateZeroPool (sizeof (CONSOLE_LOGGER_PRIVATE_DATA
));
36 if ((*ConsoleInfo
) == NULL
) {
37 return (EFI_OUT_OF_RESOURCES
);
40 (*ConsoleInfo
)->Signature
= CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE
;
41 (*ConsoleInfo
)->OldConOut
= gST
->ConOut
;
42 (*ConsoleInfo
)->OldConHandle
= gST
->ConsoleOutHandle
;
43 (*ConsoleInfo
)->Buffer
= NULL
;
44 (*ConsoleInfo
)->BufferSize
= 0;
45 (*ConsoleInfo
)->OriginalStartRow
= 0;
46 (*ConsoleInfo
)->CurrentStartRow
= 0;
47 (*ConsoleInfo
)->RowsPerScreen
= 0;
48 (*ConsoleInfo
)->ColsPerScreen
= 0;
49 (*ConsoleInfo
)->Attributes
= NULL
;
50 (*ConsoleInfo
)->AttribSize
= 0;
51 (*ConsoleInfo
)->ScreenCount
= ScreensToSave
;
52 (*ConsoleInfo
)->HistoryMode
.MaxMode
= 1;
53 (*ConsoleInfo
)->HistoryMode
.Mode
= 0;
54 (*ConsoleInfo
)->HistoryMode
.Attribute
= 0;
55 (*ConsoleInfo
)->HistoryMode
.CursorColumn
= 0;
56 (*ConsoleInfo
)->HistoryMode
.CursorRow
= 0;
57 (*ConsoleInfo
)->HistoryMode
.CursorVisible
= FALSE
;
58 (*ConsoleInfo
)->OurConOut
.Reset
= ConsoleLoggerReset
;
59 (*ConsoleInfo
)->OurConOut
.OutputString
= ConsoleLoggerOutputString
;
60 (*ConsoleInfo
)->OurConOut
.TestString
= ConsoleLoggerTestString
;
61 (*ConsoleInfo
)->OurConOut
.QueryMode
= ConsoleLoggerQueryMode
;
62 (*ConsoleInfo
)->OurConOut
.SetMode
= ConsoleLoggerSetMode
;
63 (*ConsoleInfo
)->OurConOut
.SetAttribute
= ConsoleLoggerSetAttribute
;
64 (*ConsoleInfo
)->OurConOut
.ClearScreen
= ConsoleLoggerClearScreen
;
65 (*ConsoleInfo
)->OurConOut
.SetCursorPosition
= ConsoleLoggerSetCursorPosition
;
66 (*ConsoleInfo
)->OurConOut
.EnableCursor
= ConsoleLoggerEnableCursor
;
67 (*ConsoleInfo
)->OurConOut
.Mode
= gST
->ConOut
->Mode
;
68 (*ConsoleInfo
)->Enabled
= TRUE
;
70 Status
= ConsoleLoggerResetBuffers (*ConsoleInfo
);
71 if (EFI_ERROR (Status
)) {
72 SHELL_FREE_NON_NULL ((*ConsoleInfo
));
77 Status
= gBS
->InstallProtocolInterface (&gImageHandle
, &gEfiSimpleTextOutProtocolGuid
, EFI_NATIVE_INTERFACE
, (VOID
*)&((*ConsoleInfo
)->OurConOut
));
78 if (EFI_ERROR (Status
)) {
79 SHELL_FREE_NON_NULL ((*ConsoleInfo
)->Buffer
);
80 SHELL_FREE_NON_NULL ((*ConsoleInfo
)->Attributes
);
81 SHELL_FREE_NON_NULL ((*ConsoleInfo
));
86 gST
->ConsoleOutHandle
= gImageHandle
;
87 gST
->ConOut
= &(*ConsoleInfo
)->OurConOut
;
90 // Update the CRC32 in the EFI System Table header
102 Return the system to the state it was before InstallConsoleLogger
105 @param[in] ConsoleInfo The object from the install function.
107 @retval EFI_SUCCESS The operation was successful
108 @return other The operation failed. This was from UninstallProtocolInterface.
111 ConsoleLoggerUninstall (
112 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
115 ASSERT (ConsoleInfo
!= NULL
);
116 ASSERT (ConsoleInfo
->OldConOut
!= NULL
);
118 if (ConsoleInfo
->Buffer
!= NULL
) {
119 FreePool (ConsoleInfo
->Buffer
);
121 ConsoleInfo
->Buffer
= NULL
;
124 ConsoleInfo
->BufferSize
= 0;
128 if (ConsoleInfo
->Attributes
!= NULL
) {
129 FreePool (ConsoleInfo
->Attributes
);
131 ConsoleInfo
->Attributes
= NULL
;
134 ConsoleInfo
->AttribSize
= 0;
138 gST
->ConsoleOutHandle
= ConsoleInfo
->OldConHandle
;
139 gST
->ConOut
= ConsoleInfo
->OldConOut
;
142 // Update the CRC32 in the EFI System Table header
145 gBS
->CalculateCrc32 (
151 return (gBS
->UninstallProtocolInterface (gImageHandle
, &gEfiSimpleTextOutProtocolGuid
, (VOID
*)&ConsoleInfo
->OurConOut
));
155 Displays previously logged output back to the screen.
157 This will scroll the screen forwards and backwards through the log of previous
158 output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
159 is (UINTN)(-1) then the size of the screen will be scrolled.
161 @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
162 If FALSE then the log will be displayed backwards (scroll to older).
163 @param[in] Rows Determines how many rows the log should scroll.
164 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
167 ConsoleLoggerDisplayHistory (
168 IN CONST BOOLEAN Forward
,
170 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
175 ASSERT (ConsoleInfo
!= NULL
);
178 // Calculate the row number change
182 RowChange
= ConsoleInfo
->RowsPerScreen
;
185 RowChange
= ConsoleInfo
->RowsPerScreen
/ 2;
193 // Do the math for direction
196 if ((ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
) < RowChange
) {
197 RowChange
= ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
;
200 if (ConsoleInfo
->CurrentStartRow
< RowChange
) {
201 RowChange
= ConsoleInfo
->CurrentStartRow
;
206 // If we are already at one end or the other
208 if (RowChange
== 0) {
209 return (EFI_SUCCESS
);
215 ConsoleInfo
->OldConOut
->ClearScreen (ConsoleInfo
->OldConOut
);
218 // Set the new start row
221 ConsoleInfo
->CurrentStartRow
+= RowChange
;
223 ConsoleInfo
->CurrentStartRow
-= RowChange
;
229 return (UpdateDisplayFromHistory (ConsoleInfo
));
233 Function to return to normal output whent he scrolling is complete.
234 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
236 @retval EFI_SUCCESS The operation was successful.
237 @return other The operation failed. See UpdateDisplayFromHistory.
239 @sa UpdateDisplayFromHistory
242 ConsoleLoggerStopHistory (
243 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
246 ASSERT (ConsoleInfo
!= NULL
);
247 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
248 return (EFI_SUCCESS
);
254 ConsoleInfo
->OldConOut
->ClearScreen (ConsoleInfo
->OldConOut
);
256 ConsoleInfo
->CurrentStartRow
= ConsoleInfo
->OriginalStartRow
;
257 return (UpdateDisplayFromHistory (ConsoleInfo
));
261 Updates the hidden ConOut to be displaying the correct stuff.
262 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
264 @retval EFI_SUCCESS The operation was successful.
265 @return other The operation failed.
268 UpdateDisplayFromHistory (
269 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
277 CHAR16 TempCharHolder
;
281 CHAR16
*StringSegment
;
282 CHAR16
*StringSegmentEnd
;
283 CHAR16 StringSegmentEndChar
;
286 ASSERT (ConsoleInfo
!= NULL
);
287 TempCharHolder
= CHAR_NULL
;
288 RetVal
= EFI_SUCCESS
;
289 OrigAttribute
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
292 // Disable cursor visibility and move it to the top left corner
294 ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, FALSE
);
295 ConsoleInfo
->OldConOut
->SetCursorPosition (ConsoleInfo
->OldConOut
, 0, 0);
297 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
298 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
300 ; CurrentRow
< ConsoleInfo
->RowsPerScreen
302 Screen
+= (ConsoleInfo
->ColsPerScreen
+ 2),
303 Attributes
+= ConsoleInfo
->ColsPerScreen
307 // dont use the last char - prevents screen scroll
309 if (CurrentRow
== (ConsoleInfo
->RowsPerScreen
-1)) {
310 TempCharHolder
= Screen
[ConsoleInfo
->ColsPerScreen
- 1];
311 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = CHAR_NULL
;
315 ; Column
< ConsoleInfo
->ColsPerScreen
319 if (Screen
[Column
] != CHAR_NULL
) {
320 CurrentAttrib
= Attributes
[Column
];
321 CurrentColumn
= Column
;
322 StringSegment
= &Screen
[Column
];
325 // Find the first char with a different attribute and make that temporarily NULL
326 // so we can do fewer printout statements. (later) restore that one and we will
327 // start at that column on the next loop.
329 StringSegmentEndChar
= CHAR_NULL
;
330 for ( StringSegmentEnd
= StringSegment
331 ; *StringSegmentEnd
!= CHAR_NULL
332 ; StringSegmentEnd
++,
336 if (Attributes
[Column
] != CurrentAttrib
) {
337 StringSegmentEndChar
= *StringSegmentEnd
;
338 *StringSegmentEnd
= CHAR_NULL
;
341 } // StringSegmentEnd loop
344 // Now write out as much as had the same Attributes
347 ConsoleInfo
->OldConOut
->SetAttribute (ConsoleInfo
->OldConOut
, CurrentAttrib
);
348 ConsoleInfo
->OldConOut
->SetCursorPosition (ConsoleInfo
->OldConOut
, CurrentColumn
, CurrentRow
);
349 Status
= ConsoleInfo
->OldConOut
->OutputString (ConsoleInfo
->OldConOut
, StringSegment
);
351 if (EFI_ERROR (Status
)) {
357 // If we found a change in attribute put the character back and decrement the column
358 // so when it increments it will point at that character and we will start printing
359 // a segment with that new attribute
361 if (StringSegmentEndChar
!= CHAR_NULL
) {
362 *StringSegmentEnd
= StringSegmentEndChar
;
363 StringSegmentEndChar
= CHAR_NULL
;
370 // If we removed the last char and this was the last row put it back
372 if (TempCharHolder
!= CHAR_NULL
) {
373 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = TempCharHolder
;
374 TempCharHolder
= CHAR_NULL
;
379 // If we are setting the screen back to original turn on the cursor and make it visible
380 // and set the attributes back to what they were
382 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
383 ConsoleInfo
->OldConOut
->SetAttribute (
384 ConsoleInfo
->OldConOut
,
385 ConsoleInfo
->HistoryMode
.Attribute
387 ConsoleInfo
->OldConOut
->SetCursorPosition (
388 ConsoleInfo
->OldConOut
,
389 ConsoleInfo
->HistoryMode
.CursorColumn
,
390 ConsoleInfo
->HistoryMode
.CursorRow
- ConsoleInfo
->OriginalStartRow
393 Status
= ConsoleInfo
->OldConOut
->EnableCursor (
394 ConsoleInfo
->OldConOut
,
395 ConsoleInfo
->HistoryMode
.CursorVisible
397 if (EFI_ERROR (Status
)) {
401 ConsoleInfo
->OldConOut
->SetAttribute (
402 ConsoleInfo
->OldConOut
,
411 Reset the text output device hardware and optionally run diagnostics
413 @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
414 @param ExtendedVerification Indicates that a more extensive test may be performed
416 @retval EFI_SUCCESS The text output device was reset.
417 @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
423 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
424 IN BOOLEAN ExtendedVerification
428 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
430 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
433 // Forward the request to the original ConOut
435 Status
= ConsoleInfo
->OldConOut
->Reset (ConsoleInfo
->OldConOut
, ExtendedVerification
);
438 // Check that the buffers are still correct for logging
440 if (!EFI_ERROR (Status
)) {
441 ConsoleLoggerResetBuffers (ConsoleInfo
);
442 if (ExtendedVerification
) {
443 ConsoleInfo
->OriginalStartRow
= 0;
444 ConsoleInfo
->CurrentStartRow
= 0;
452 Appends a string to the history buffer. If the buffer is full then the oldest
453 information in the buffer will be dropped. Information is added in a line by
454 line manner such that an empty line takes up just as much space as a full line.
456 @param[in] String String pointer to add.
457 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
460 AppendStringToHistory (
461 IN CONST CHAR16
*String
,
462 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
465 CONST CHAR16
*Walker
;
470 ASSERT (ConsoleInfo
!= NULL
);
472 for ( Walker
= String
473 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
478 case (CHAR_BACKSPACE
):
479 if (ConsoleInfo
->HistoryMode
.CursorColumn
> 0) {
480 ConsoleInfo
->HistoryMode
.CursorColumn
--;
484 case (CHAR_LINEFEED
):
485 if (ConsoleInfo
->HistoryMode
.CursorRow
>= (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1)) {
487 // Should never be bigger
489 ASSERT (ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1));
492 // scroll history attributes 'up' 1 row and set the last row to default attribute
494 CopySize
= ConsoleInfo
->ColsPerScreen
495 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
496 * sizeof (ConsoleInfo
->Attributes
[0]);
497 ASSERT (CopySize
< ConsoleInfo
->AttribSize
);
499 ConsoleInfo
->Attributes
,
500 ConsoleInfo
->Attributes
+ ConsoleInfo
->ColsPerScreen
,
505 ; Index
< ConsoleInfo
->ColsPerScreen
509 *(ConsoleInfo
->Attributes
+ (CopySize
/sizeof (ConsoleInfo
->Attributes
[0])) + Index
) = ConsoleInfo
->HistoryMode
.Attribute
;
513 // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
515 CopySize
= (ConsoleInfo
->ColsPerScreen
+ 2)
516 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
517 * sizeof (ConsoleInfo
->Buffer
[0]);
518 ASSERT (CopySize
< ConsoleInfo
->BufferSize
);
521 ConsoleInfo
->Buffer
+ (ConsoleInfo
->ColsPerScreen
+ 2),
526 // Set that last row of chars to spaces
528 SetMem16 (((UINT8
*)ConsoleInfo
->Buffer
)+CopySize
, ConsoleInfo
->ColsPerScreen
*sizeof (CHAR16
), L
' ');
531 // we are not on the last row
535 // We should not be scrolling history
537 ASSERT (ConsoleInfo
->OriginalStartRow
== ConsoleInfo
->CurrentStartRow
);
539 // are we at the end of a row?
541 if (ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
)(ConsoleInfo
->OriginalStartRow
+ ConsoleInfo
->RowsPerScreen
- 1)) {
542 ConsoleInfo
->OriginalStartRow
++;
543 ConsoleInfo
->CurrentStartRow
++;
546 ConsoleInfo
->HistoryMode
.CursorRow
++;
550 case (CHAR_CARRIAGE_RETURN
):
552 // Move the cursor to the beginning of the current row.
554 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
558 // Acrtually print characters into the history buffer
561 PrintIndex
= ConsoleInfo
->HistoryMode
.CursorRow
* ConsoleInfo
->ColsPerScreen
+ ConsoleInfo
->HistoryMode
.CursorColumn
;
563 for ( // no initializer needed
564 ; ConsoleInfo
->HistoryMode
.CursorColumn
< (INT32
)ConsoleInfo
->ColsPerScreen
565 ; ConsoleInfo
->HistoryMode
.CursorColumn
++,
570 if ( (*Walker
== CHAR_NULL
)
571 || (*Walker
== CHAR_BACKSPACE
)
572 || (*Walker
== CHAR_LINEFEED
)
573 || (*Walker
== CHAR_CARRIAGE_RETURN
)
581 // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
584 ASSERT (PrintIndex
+ ConsoleInfo
->HistoryMode
.CursorRow
< ConsoleInfo
->BufferSize
);
585 ConsoleInfo
->Buffer
[PrintIndex
+ (2*ConsoleInfo
->HistoryMode
.CursorRow
)] = *Walker
;
586 ASSERT (PrintIndex
< ConsoleInfo
->AttribSize
);
587 ConsoleInfo
->Attributes
[PrintIndex
] = ConsoleInfo
->HistoryMode
.Attribute
;
591 // Add the carriage return and line feed at the end of the lines
593 if (ConsoleInfo
->HistoryMode
.CursorColumn
>= (INT32
)ConsoleInfo
->ColsPerScreen
) {
594 AppendStringToHistory (L
"\r\n", ConsoleInfo
);
599 } // switch for character
602 return (EFI_SUCCESS
);
606 Worker function to handle printing the output to the screen
607 and the history buffer
609 @param[in] String The string to output
610 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
612 @retval EFI_SUCCESS The string was printed
613 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
615 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
617 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
618 characters in the Unicode string could not be
619 rendered and were skipped.
622 ConsoleLoggerOutputStringSplit (
623 IN CONST CHAR16
*String
,
624 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
630 // Forward the request to the original ConOut
632 Status
= ConsoleInfo
->OldConOut
->OutputString (ConsoleInfo
->OldConOut
, (CHAR16
*)String
);
634 if (EFI_ERROR (Status
)) {
638 return (AppendStringToHistory (String
, ConsoleInfo
));
642 Function to handle page break mode.
644 This function will prompt for continue or break.
646 @retval EFI_SUCCESS Continue was choosen
647 @return other Break was choosen
650 ConsoleLoggerDoPageBreak (
654 SHELL_PROMPT_RESPONSE
*Resp
;
658 ASSERT (ShellInfoObject
.PageBreakEnabled
);
659 ShellInfoObject
.PageBreakEnabled
= FALSE
;
660 Status
= ShellPromptForResponseHii (ShellPromptResponseTypeQuitContinue
, STRING_TOKEN (STR_SHELL_QUIT_CONT
), ShellInfoObject
.HiiHandle
, (VOID
**)&Resp
);
661 ShellInfoObject
.PageBreakEnabled
= TRUE
;
662 ASSERT (Resp
!= NULL
);
664 return (EFI_NOT_FOUND
);
667 if (EFI_ERROR (Status
)) {
675 if (*Resp
== ShellPromptResponseContinue
) {
677 ShellInfoObject
.ConsoleInfo
->RowCounter
= 0;
678 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
679 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
681 return (EFI_SUCCESS
);
682 } else if (*Resp
== ShellPromptResponseQuit
) {
684 ShellInfoObject
.ConsoleInfo
->Enabled
= FALSE
;
686 // When user wants to quit, the shell should stop running the command.
688 gBS
->SignalEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
);
689 return (EFI_DEVICE_ERROR
);
694 return (EFI_SUCCESS
);
698 Worker function to handle printing the output with page breaks.
700 @param[in] String The string to output
701 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
703 @retval EFI_SUCCESS The string was printed
704 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
706 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
708 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
709 characters in the Unicode string could not be
710 rendered and were skipped.
713 ConsoleLoggerPrintWithPageBreak (
714 IN CONST CHAR16
*String
,
715 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
718 CONST CHAR16
*Walker
;
719 CONST CHAR16
*LineStart
;
724 StringCopy
= StrnCatGrow (&StringCopy
, NULL
, String
, 0);
725 if (StringCopy
== NULL
) {
726 return (EFI_OUT_OF_RESOURCES
);
729 for ( Walker
= StringCopy
,
730 LineStart
= StringCopy
731 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
736 case (CHAR_BACKSPACE
):
737 if (ConsoleInfo
->OurConOut
.Mode
->CursorColumn
> 0) {
738 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
--;
742 case (CHAR_LINEFEED
):
744 // add a temp NULL terminator
746 TempChar
= *(Walker
+ 1);
747 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
752 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
755 // restore the temp NULL terminator to its original character
757 *((CHAR16
*)(Walker
+1)) = TempChar
;
760 // Update LineStart Variable
762 LineStart
= Walker
+ 1;
765 // increment row count
767 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
768 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
771 case (CHAR_CARRIAGE_RETURN
):
773 // Move the cursor to the beginning of the current row.
775 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
779 // increment column count
781 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
++;
783 // check if that is the last column
785 if ((INTN
)ConsoleInfo
->ColsPerScreen
== ConsoleInfo
->OurConOut
.Mode
->CursorColumn
+ 1) {
787 // output a line similar to the linefeed character.
791 // add a temp NULL terminator
793 TempChar
= *(Walker
+ 1);
794 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
799 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
802 // restore the temp NULL terminator to its original character
804 *((CHAR16
*)(Walker
+1)) = TempChar
;
807 // Update LineStart Variable
809 LineStart
= Walker
+ 1;
812 // increment row count and zero the column
814 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
815 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
816 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
817 } // last column on line
820 } // switch for character
823 // check if that was the last printable row. If yes handle PageBreak mode
825 if ((ConsoleInfo
->RowsPerScreen
) -1 == ShellInfoObject
.ConsoleInfo
->RowCounter
) {
826 if (EFI_ERROR (ConsoleLoggerDoPageBreak ())) {
828 // We got an error which means 'break' and halt the printing
830 SHELL_FREE_NON_NULL (StringCopy
);
831 return (EFI_DEVICE_ERROR
);
836 if ((LineStart
!= NULL
) && (*LineStart
!= CHAR_NULL
)) {
837 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
840 SHELL_FREE_NON_NULL (StringCopy
);
841 return (EFI_SUCCESS
);
845 Write a Unicode string to the output device.
847 @param[in] This Protocol instance pointer.
848 @param[in] WString The NULL-terminated Unicode string to be displayed on the output
849 device(s). All output devices must also support the Unicode
850 drawing defined in this file.
851 @retval EFI_SUCCESS The string was output to the device.
852 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
854 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
856 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
857 characters in the Unicode string could not be
858 rendered and were skipped.
862 ConsoleLoggerOutputString (
863 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
868 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
869 EFI_KEY_DATA KeyData
;
871 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
873 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
874 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
875 return (EFI_UNSUPPORTED
);
878 ASSERT (ShellInfoObject
.ConsoleInfo
== ConsoleInfo
);
880 Status
= gBS
->HandleProtocol (gST
->ConsoleInHandle
, &gEfiSimpleTextInputExProtocolGuid
, (VOID
**)&TxtInEx
);
881 if (!EFI_ERROR (Status
)) {
882 while (ShellInfoObject
.HaltOutput
) {
883 ShellInfoObject
.HaltOutput
= FALSE
;
887 Status
= gBS
->WaitForEvent (1, &TxtInEx
->WaitForKeyEx
, &EventIndex
);
888 ASSERT_EFI_ERROR (Status
);
889 Status
= TxtInEx
->ReadKeyStrokeEx (TxtInEx
, &KeyData
);
890 if (EFI_ERROR (Status
)) {
894 if ((KeyData
.Key
.UnicodeChar
== L
's') && (KeyData
.Key
.ScanCode
== SCAN_NULL
) &&
895 ((KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_LEFT_CONTROL_PRESSED
)) ||
896 (KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_RIGHT_CONTROL_PRESSED
))
900 ShellInfoObject
.HaltOutput
= TRUE
;
905 if (!ShellInfoObject
.ConsoleInfo
->Enabled
) {
906 return (EFI_DEVICE_ERROR
);
907 } else if (ShellInfoObject
.PageBreakEnabled
) {
908 return (ConsoleLoggerPrintWithPageBreak (WString
, ConsoleInfo
));
910 return (ConsoleLoggerOutputStringSplit (WString
, ConsoleInfo
));
915 Verifies that all characters in a Unicode string can be output to the
918 @param[in] This Protocol instance pointer.
919 @param[in] WString The NULL-terminated Unicode string to be examined for the output
922 @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
923 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
924 rendered by one or more of the output devices mapped
930 ConsoleLoggerTestString (
931 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
935 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
937 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
939 // Forward the request to the original ConOut
941 return (ConsoleInfo
->OldConOut
->TestString (ConsoleInfo
->OldConOut
, WString
));
945 Returns information for an available text mode that the output device(s)
948 @param[in] This Protocol instance pointer.
949 @param[in] ModeNumber The mode number to return information on.
950 @param[out] Columns Upon return, the number of columns in the selected geometry
951 @param[out] Rows Upon return, the number of rows in the selected geometry
953 @retval EFI_SUCCESS The requested mode information was returned.
954 @retval EFI_DEVICE_ERROR The device had an error and could not
955 complete the request.
956 @retval EFI_UNSUPPORTED The mode number was not valid.
960 ConsoleLoggerQueryMode (
961 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
967 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
969 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
971 // Forward the request to the original ConOut
973 return (ConsoleInfo
->OldConOut
->QueryMode (
974 ConsoleInfo
->OldConOut
,
982 Sets the output device(s) to a specified mode.
984 @param[in] This Protocol instance pointer.
985 @param[in] ModeNumber The mode number to set.
988 @retval EFI_SUCCESS The requested text mode was set.
989 @retval EFI_DEVICE_ERROR The device had an error and
990 could not complete the request.
991 @retval EFI_UNSUPPORTED The mode number was not valid.
995 ConsoleLoggerSetMode (
996 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1002 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1004 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
1007 // Forward the request to the original ConOut
1009 Status
= ConsoleInfo
->OldConOut
->SetMode (ConsoleInfo
->OldConOut
, ModeNumber
);
1012 // Check that the buffers are still correct for logging
1014 if (!EFI_ERROR (Status
)) {
1015 ConsoleInfo
->OurConOut
.Mode
= ConsoleInfo
->OldConOut
->Mode
;
1016 ConsoleLoggerResetBuffers (ConsoleInfo
);
1017 ConsoleInfo
->OriginalStartRow
= 0;
1018 ConsoleInfo
->CurrentStartRow
= 0;
1019 ConsoleInfo
->OurConOut
.ClearScreen (&ConsoleInfo
->OurConOut
);
1026 Sets the background and foreground colors for the OutputString () and
1027 ClearScreen () functions.
1029 @param[in] This Protocol instance pointer.
1030 @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
1031 bits 4..6 are the background color. All other bits are undefined
1032 and must be zero. The valid Attributes are defined in this file.
1034 @retval EFI_SUCCESS The attribute was set.
1035 @retval EFI_DEVICE_ERROR The device had an error and
1036 could not complete the request.
1037 @retval EFI_UNSUPPORTED The attribute requested is not defined.
1042 ConsoleLoggerSetAttribute (
1043 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1049 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1051 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
1054 // Forward the request to the original ConOut
1056 Status
= ConsoleInfo
->OldConOut
->SetAttribute (ConsoleInfo
->OldConOut
, Attribute
);
1059 // Record console output history
1061 if (!EFI_ERROR (Status
)) {
1062 ConsoleInfo
->HistoryMode
.Attribute
= (INT32
)Attribute
;
1069 Clears the output device(s) display to the currently selected background
1072 @param[in] This Protocol instance pointer.
1074 @retval EFI_SUCCESS The operation completed successfully.
1075 @retval EFI_DEVICE_ERROR The device had an error and
1076 could not complete the request.
1077 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1081 ConsoleLoggerClearScreen (
1082 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
1090 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1092 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1093 return (EFI_UNSUPPORTED
);
1096 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
1099 // Forward the request to the original ConOut
1101 Status
= ConsoleInfo
->OldConOut
->ClearScreen (ConsoleInfo
->OldConOut
);
1104 // Record console output history
1106 if (!EFI_ERROR (Status
)) {
1107 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
1108 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
1109 for ( Row
= ConsoleInfo
->OriginalStartRow
1110 ; Row
< (ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)
1115 ; Column
< ConsoleInfo
->ColsPerScreen
1122 *Attributes
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
1126 // Skip the NULL on each column end in text buffer only
1131 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
1132 ConsoleInfo
->HistoryMode
.CursorRow
= 0;
1139 Sets the current coordinates of the cursor position
1141 @param[in] This Protocol instance pointer.
1142 @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
1143 @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
1145 @retval EFI_SUCCESS The operation completed successfully.
1146 @retval EFI_DEVICE_ERROR The device had an error and
1147 could not complete the request.
1148 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
1149 cursor position is invalid for the current mode.
1153 ConsoleLoggerSetCursorPosition (
1154 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1160 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1162 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1163 return (EFI_UNSUPPORTED
);
1166 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
1168 // Forward the request to the original ConOut
1170 Status
= ConsoleInfo
->OldConOut
->SetCursorPosition (
1171 ConsoleInfo
->OldConOut
,
1177 // Record console output history
1179 if (!EFI_ERROR (Status
)) {
1180 ConsoleInfo
->HistoryMode
.CursorColumn
= (INT32
)Column
;
1181 ConsoleInfo
->HistoryMode
.CursorRow
= (INT32
)(ConsoleInfo
->OriginalStartRow
+ Row
);
1188 Makes the cursor visible or invisible
1190 @param[in] This Protocol instance pointer.
1191 @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
1192 set to be invisible.
1194 @retval EFI_SUCCESS The operation completed successfully.
1195 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1196 request, or the device does not support changing
1198 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1202 ConsoleLoggerEnableCursor (
1203 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1209 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1211 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This
);
1213 // Forward the request to the original ConOut
1215 Status
= ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, Visible
);
1218 // Record console output history
1220 if (!EFI_ERROR (Status
)) {
1221 ConsoleInfo
->HistoryMode
.CursorVisible
= Visible
;
1228 Function to update and verify that the current buffers are correct.
1230 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
1232 This will be used when a mode has changed or a reset occurred to verify all
1236 ConsoleLoggerResetBuffers (
1237 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
1242 if (ConsoleInfo
->Buffer
!= NULL
) {
1243 FreePool (ConsoleInfo
->Buffer
);
1244 ConsoleInfo
->Buffer
= NULL
;
1245 ConsoleInfo
->BufferSize
= 0;
1248 if (ConsoleInfo
->Attributes
!= NULL
) {
1249 FreePool (ConsoleInfo
->Attributes
);
1250 ConsoleInfo
->Attributes
= NULL
;
1251 ConsoleInfo
->AttribSize
= 0;
1254 Status
= gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &ConsoleInfo
->ColsPerScreen
, &ConsoleInfo
->RowsPerScreen
);
1255 if (EFI_ERROR (Status
)) {
1259 ConsoleInfo
->BufferSize
= (ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof (ConsoleInfo
->Buffer
[0]);
1260 ConsoleInfo
->AttribSize
= ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof (ConsoleInfo
->Attributes
[0]);
1262 ConsoleInfo
->Buffer
= (CHAR16
*)AllocateZeroPool (ConsoleInfo
->BufferSize
);
1264 if (ConsoleInfo
->Buffer
== NULL
) {
1265 return (EFI_OUT_OF_RESOURCES
);
1268 ConsoleInfo
->Attributes
= (INT32
*)AllocateZeroPool (ConsoleInfo
->AttribSize
);
1269 if (ConsoleInfo
->Attributes
== NULL
) {
1270 FreePool (ConsoleInfo
->Buffer
);
1271 ConsoleInfo
->Buffer
= NULL
;
1272 return (EFI_OUT_OF_RESOURCES
);
1275 CopyMem (&ConsoleInfo
->HistoryMode
, ConsoleInfo
->OldConOut
->Mode
, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE
));
1277 return (EFI_SUCCESS
);