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 (C) Copyright 2016 Hewlett-Packard Development Company, L.P.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Install our intermediate ConOut into the system table to
20 keep a log of all the info that is displayed to the user.
22 @param[in] ScreensToSave Sets how many screen-worths of data to save.
23 @param[out] ConsoleInfo The object to pass into later functions.
25 @retval EFI_SUCCESS The operation was successful.
26 @return other The operation failed.
28 @sa ConsoleLoggerResetBuffers
29 @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
;
95 // Update the CRC32 in the EFI System Table header
107 Return the system to the state it was before InstallConsoleLogger
110 @param[in] ConsoleInfo The object from the install function.
112 @retval EFI_SUCCESS The operation was successful
113 @return other The operation failed. This was from UninstallProtocolInterface.
116 ConsoleLoggerUninstall(
117 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
120 ASSERT(ConsoleInfo
!= NULL
);
121 ASSERT(ConsoleInfo
->OldConOut
!= NULL
);
123 if (ConsoleInfo
->Buffer
!= NULL
) {
124 FreePool(ConsoleInfo
->Buffer
);
125 DEBUG_CODE(ConsoleInfo
->Buffer
= NULL
;);
126 DEBUG_CODE(ConsoleInfo
->BufferSize
= 0;);
128 if (ConsoleInfo
->Attributes
!= NULL
) {
129 FreePool(ConsoleInfo
->Attributes
);
130 DEBUG_CODE(ConsoleInfo
->Attributes
= NULL
;);
131 DEBUG_CODE(ConsoleInfo
->AttribSize
= 0;);
134 gST
->ConsoleOutHandle
= ConsoleInfo
->OldConHandle
;
135 gST
->ConOut
= ConsoleInfo
->OldConOut
;
138 // Update the CRC32 in the EFI System Table header
141 gBS
->CalculateCrc32 (
147 return (gBS
->UninstallProtocolInterface(gImageHandle
, &gEfiSimpleTextOutProtocolGuid
, (VOID
*)&ConsoleInfo
->OurConOut
));
151 Displays previously logged output back to the screen.
153 This will scroll the screen forwards and backwards through the log of previous
154 output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
155 is (UINTN)(-1) then the size of the screen will be scrolled.
157 @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
158 If FALSE then the log will be displayed backwards (scroll to older).
159 @param[in] Rows Determines how many rows the log should scroll.
160 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
163 ConsoleLoggerDisplayHistory(
164 IN CONST BOOLEAN Forward
,
166 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
171 ASSERT(ConsoleInfo
!= NULL
);
174 // Calculate the row number change
178 RowChange
= ConsoleInfo
->RowsPerScreen
;
181 RowChange
= ConsoleInfo
->RowsPerScreen
/ 2;
189 // Do the math for direction
192 if ((ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
) < RowChange
) {
193 RowChange
= ConsoleInfo
->OriginalStartRow
- ConsoleInfo
->CurrentStartRow
;
196 if (ConsoleInfo
->CurrentStartRow
< RowChange
) {
197 RowChange
= ConsoleInfo
->CurrentStartRow
;
202 // If we are already at one end or the other
204 if (RowChange
== 0) {
205 return (EFI_SUCCESS
);
211 ConsoleInfo
->OldConOut
->ClearScreen(ConsoleInfo
->OldConOut
);
214 // Set the new start row
217 ConsoleInfo
->CurrentStartRow
+= RowChange
;
219 ConsoleInfo
->CurrentStartRow
-= RowChange
;
225 return (UpdateDisplayFromHistory(ConsoleInfo
));
229 Function to return to normal output whent he scrolling is complete.
230 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
232 @retval EFI_SUCCESS The operation was successful.
233 @return other The operation failed. See UpdateDisplayFromHistory.
235 @sa UpdateDisplayFromHistory
238 ConsoleLoggerStopHistory(
239 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
242 ASSERT(ConsoleInfo
!= NULL
);
243 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
244 return (EFI_SUCCESS
);
250 ConsoleInfo
->OldConOut
->ClearScreen(ConsoleInfo
->OldConOut
);
252 ConsoleInfo
->CurrentStartRow
= ConsoleInfo
->OriginalStartRow
;
253 return (UpdateDisplayFromHistory(ConsoleInfo
));
257 Updates the hidden ConOut to be displaying the correct stuff.
258 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
260 @retval EFI_SUCCESS The operation was successful.
261 @return other The operation failed.
264 UpdateDisplayFromHistory(
265 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
273 CHAR16 TempCharHolder
;
277 CHAR16
*StringSegment
;
278 CHAR16
*StringSegmentEnd
;
279 CHAR16 StringSegmentEndChar
;
282 ASSERT(ConsoleInfo
!= NULL
);
283 TempCharHolder
= CHAR_NULL
;
284 RetVal
= EFI_SUCCESS
;
285 OrigAttribute
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
288 // Disable cursor visibility and move it to the top left corner
290 ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, FALSE
);
291 ConsoleInfo
->OldConOut
->SetCursorPosition (ConsoleInfo
->OldConOut
, 0, 0);
293 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
294 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
296 ; CurrentRow
< ConsoleInfo
->RowsPerScreen
298 , Screen
+= (ConsoleInfo
->ColsPerScreen
+ 2)
299 , Attributes
+= ConsoleInfo
->ColsPerScreen
302 // dont use the last char - prevents screen scroll
304 if (CurrentRow
== (ConsoleInfo
->RowsPerScreen
-1)){
305 TempCharHolder
= Screen
[ConsoleInfo
->ColsPerScreen
- 1];
306 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = CHAR_NULL
;
310 ; Column
< ConsoleInfo
->ColsPerScreen
313 if (Screen
[Column
] != CHAR_NULL
) {
314 CurrentAttrib
= Attributes
[Column
];
315 CurrentColumn
= Column
;
316 StringSegment
= &Screen
[Column
];
319 // Find the first char with a different arrribute and make that temporarily NULL
320 // so we can do fewer printout statements. (later) restore that one and we will
321 // start at that collumn on the next loop.
323 StringSegmentEndChar
= CHAR_NULL
;
324 for ( StringSegmentEnd
= StringSegment
325 ; StringSegmentEnd
!= CHAR_NULL
329 if (Attributes
[Column
] != CurrentAttrib
) {
330 StringSegmentEndChar
= *StringSegmentEnd
;
331 *StringSegmentEnd
= CHAR_NULL
;
334 } // StringSegmentEnd loop
337 // Now write out as much as had the same Attributes
340 ConsoleInfo
->OldConOut
->SetAttribute(ConsoleInfo
->OldConOut
, CurrentAttrib
);
341 ConsoleInfo
->OldConOut
->SetCursorPosition(ConsoleInfo
->OldConOut
, CurrentColumn
, CurrentRow
);
342 Status
= ConsoleInfo
->OldConOut
->OutputString(ConsoleInfo
->OldConOut
, StringSegment
);
344 if (EFI_ERROR(Status
)) {
350 // If we found a change in attribute put the character back and decrement the column
351 // so when it increments it will point at that character and we will start printing
352 // a segment with that new attribute
354 if (StringSegmentEndChar
!= CHAR_NULL
) {
355 *StringSegmentEnd
= StringSegmentEndChar
;
356 StringSegmentEndChar
= CHAR_NULL
;
363 // If we removed the last char and this was the last row put it back
365 if (TempCharHolder
!= CHAR_NULL
) {
366 Screen
[ConsoleInfo
->ColsPerScreen
- 1] = TempCharHolder
;
367 TempCharHolder
= CHAR_NULL
;
372 // If we are setting the screen back to original turn on the cursor and make it visible
373 // and set the attributes back to what they were
375 if (ConsoleInfo
->CurrentStartRow
== ConsoleInfo
->OriginalStartRow
) {
376 ConsoleInfo
->OldConOut
->SetAttribute (
377 ConsoleInfo
->OldConOut
,
378 ConsoleInfo
->HistoryMode
.Attribute
380 ConsoleInfo
->OldConOut
->SetCursorPosition (
381 ConsoleInfo
->OldConOut
,
382 ConsoleInfo
->HistoryMode
.CursorColumn
,
383 ConsoleInfo
->HistoryMode
.CursorRow
- ConsoleInfo
->OriginalStartRow
386 Status
= ConsoleInfo
->OldConOut
->EnableCursor (
387 ConsoleInfo
->OldConOut
,
388 ConsoleInfo
->HistoryMode
.CursorVisible
390 if (EFI_ERROR (Status
)) {
394 ConsoleInfo
->OldConOut
->SetAttribute (
395 ConsoleInfo
->OldConOut
,
404 Reset the text output device hardware and optionaly run diagnostics
406 @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
407 @param ExtendedVerification Indicates that a more extensive test may be performed
409 @retval EFI_SUCCESS The text output device was reset.
410 @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
416 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
417 IN BOOLEAN ExtendedVerification
421 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
422 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
425 // Forward the request to the original ConOut
427 Status
= ConsoleInfo
->OldConOut
->Reset (ConsoleInfo
->OldConOut
, ExtendedVerification
);
430 // Check that the buffers are still correct for logging
432 if (!EFI_ERROR (Status
)) {
433 ConsoleLoggerResetBuffers(ConsoleInfo
);
434 if (ExtendedVerification
) {
435 ConsoleInfo
->OriginalStartRow
= 0;
436 ConsoleInfo
->CurrentStartRow
= 0;
444 Appends a string to the history buffer. If the buffer is full then the oldest
445 information in the buffer will be dropped. Information is added in a line by
446 line manner such that an empty line takes up just as much space as a full line.
448 @param[in] String String pointer to add.
449 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
452 AppendStringToHistory(
453 IN CONST CHAR16
*String
,
454 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
457 CONST CHAR16
*Walker
;
462 ASSERT(ConsoleInfo
!= NULL
);
464 for ( Walker
= String
465 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
469 case (CHAR_BACKSPACE
):
470 if (ConsoleInfo
->HistoryMode
.CursorColumn
> 0) {
471 ConsoleInfo
->HistoryMode
.CursorColumn
--;
474 case (CHAR_LINEFEED
):
475 if (ConsoleInfo
->HistoryMode
.CursorRow
>= (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1)) {
477 // Should never be bigger
479 ASSERT(ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
)((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)-1));
482 // scroll history attributes 'up' 1 row and set the last row to default attribute
484 CopySize
= ConsoleInfo
->ColsPerScreen
485 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
486 * sizeof(ConsoleInfo
->Attributes
[0]);
487 ASSERT(CopySize
< ConsoleInfo
->AttribSize
);
489 ConsoleInfo
->Attributes
,
490 ConsoleInfo
->Attributes
+ ConsoleInfo
->ColsPerScreen
,
495 ; Index
< ConsoleInfo
->ColsPerScreen
498 *(ConsoleInfo
->Attributes
+ (CopySize
/sizeof(ConsoleInfo
->Attributes
[0])) + Index
) = ConsoleInfo
->HistoryMode
.Attribute
;
502 // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
504 CopySize
= (ConsoleInfo
->ColsPerScreen
+ 2)
505 * ((ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
) - 1)
506 * sizeof(ConsoleInfo
->Buffer
[0]);
507 ASSERT(CopySize
< ConsoleInfo
->BufferSize
);
510 ConsoleInfo
->Buffer
+ (ConsoleInfo
->ColsPerScreen
+ 2),
515 // Set that last row of chars to spaces
517 SetMem16(((UINT8
*)ConsoleInfo
->Buffer
)+CopySize
, ConsoleInfo
->ColsPerScreen
*sizeof(CHAR16
), L
' ');
520 // we are not on the last row
524 // We should not be scrolling history
526 ASSERT (ConsoleInfo
->OriginalStartRow
== ConsoleInfo
->CurrentStartRow
);
528 // are we at the end of a row?
530 if (ConsoleInfo
->HistoryMode
.CursorRow
== (INT32
) (ConsoleInfo
->OriginalStartRow
+ ConsoleInfo
->RowsPerScreen
- 1)) {
531 ConsoleInfo
->OriginalStartRow
++;
532 ConsoleInfo
->CurrentStartRow
++;
534 ConsoleInfo
->HistoryMode
.CursorRow
++;
537 case (CHAR_CARRIAGE_RETURN
):
539 // Move the cursor to the beginning of the current row.
541 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
545 // Acrtually print characters into the history buffer
548 PrintIndex
= ConsoleInfo
->HistoryMode
.CursorRow
* ConsoleInfo
->ColsPerScreen
+ ConsoleInfo
->HistoryMode
.CursorColumn
;
550 for ( // no initializer needed
551 ; ConsoleInfo
->HistoryMode
.CursorColumn
< (INT32
) ConsoleInfo
->ColsPerScreen
552 ; ConsoleInfo
->HistoryMode
.CursorColumn
++
556 if (*Walker
== CHAR_NULL
557 ||*Walker
== CHAR_BACKSPACE
558 ||*Walker
== CHAR_LINEFEED
559 ||*Walker
== CHAR_CARRIAGE_RETURN
565 // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
568 ASSERT(PrintIndex
+ ConsoleInfo
->HistoryMode
.CursorRow
< ConsoleInfo
->BufferSize
);
569 ConsoleInfo
->Buffer
[PrintIndex
+ (2*ConsoleInfo
->HistoryMode
.CursorRow
)] = *Walker
;
570 ASSERT(PrintIndex
< ConsoleInfo
->AttribSize
);
571 ConsoleInfo
->Attributes
[PrintIndex
] = ConsoleInfo
->HistoryMode
.Attribute
;
575 // Add the carriage return and line feed at the end of the lines
577 if (ConsoleInfo
->HistoryMode
.CursorColumn
>= (INT32
)ConsoleInfo
->ColsPerScreen
) {
578 AppendStringToHistory(L
"\r\n", ConsoleInfo
);
583 } // switch for character
586 return (EFI_SUCCESS
);
590 Worker function to handle printing the output to the screen
591 and the history buffer
593 @param[in] String The string to output
594 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
596 @retval EFI_SUCCESS The string was printed
597 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
599 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
601 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
602 characters in the Unicode string could not be
603 rendered and were skipped.
606 ConsoleLoggerOutputStringSplit(
607 IN CONST CHAR16
*String
,
608 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
614 // Forward the request to the original ConOut
616 Status
= ConsoleInfo
->OldConOut
->OutputString (ConsoleInfo
->OldConOut
, (CHAR16
*)String
);
618 if (EFI_ERROR(Status
)) {
622 return (AppendStringToHistory(String
, ConsoleInfo
));
626 Function to handle page break mode.
628 This function will prompt for continue or break.
630 @retval EFI_SUCCESS Continue was choosen
631 @return other Break was choosen
634 ConsoleLoggerDoPageBreak(
638 SHELL_PROMPT_RESPONSE
*Resp
;
642 ASSERT(ShellInfoObject
.PageBreakEnabled
);
643 ShellInfoObject
.PageBreakEnabled
= FALSE
;
644 Status
= ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue
, STRING_TOKEN(STR_SHELL_QUIT_CONT
), ShellInfoObject
.HiiHandle
, (VOID
**)&Resp
);
645 ShellInfoObject
.PageBreakEnabled
= TRUE
;
646 ASSERT(Resp
!= NULL
);
648 return (EFI_NOT_FOUND
);
650 if (EFI_ERROR(Status
)) {
656 if (*Resp
== ShellPromptResponseContinue
) {
658 ShellInfoObject
.ConsoleInfo
->RowCounter
= 0;
659 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
660 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
662 return (EFI_SUCCESS
);
663 } else if (*Resp
== ShellPromptResponseQuit
) {
665 ShellInfoObject
.ConsoleInfo
->Enabled
= FALSE
;
667 // When user wants to quit, the shell should stop running the command.
669 gBS
->SignalEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
);
670 return (EFI_DEVICE_ERROR
);
674 return (EFI_SUCCESS
);
677 Worker function to handle printing the output with page breaks.
679 @param[in] String The string to output
680 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
682 @retval EFI_SUCCESS The string was printed
683 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
685 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
687 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
688 characters in the Unicode string could not be
689 rendered and were skipped.
692 ConsoleLoggerPrintWithPageBreak(
693 IN CONST CHAR16
*String
,
694 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
697 CONST CHAR16
*Walker
;
698 CONST CHAR16
*LineStart
;
703 StringCopy
= StrnCatGrow(&StringCopy
, NULL
, String
, 0);
704 if (StringCopy
== NULL
) {
705 return (EFI_OUT_OF_RESOURCES
);
708 for ( Walker
= StringCopy
709 , LineStart
= StringCopy
710 ; Walker
!= NULL
&& *Walker
!= CHAR_NULL
714 case (CHAR_BACKSPACE
):
715 if (ConsoleInfo
->OurConOut
.Mode
->CursorColumn
> 0) {
716 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
--;
719 case (CHAR_LINEFEED
):
721 // add a temp NULL terminator
723 TempChar
= *(Walker
+ 1);
724 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
729 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
732 // restore the temp NULL terminator to it's original character
734 *((CHAR16
*)(Walker
+1)) = TempChar
;
737 // Update LineStart Variable
739 LineStart
= Walker
+ 1;
742 // increment row count
744 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
745 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
748 case (CHAR_CARRIAGE_RETURN
):
750 // Move the cursor to the beginning of the current row.
752 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
756 // increment column count
758 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
++;
760 // check if that is the last column
762 if ((INTN
)ConsoleInfo
->ColsPerScreen
== ConsoleInfo
->OurConOut
.Mode
->CursorColumn
+ 1) {
764 // output a line similar to the linefeed character.
768 // add a temp NULL terminator
770 TempChar
= *(Walker
+ 1);
771 *((CHAR16
*)(Walker
+1)) = CHAR_NULL
;
776 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
779 // restore the temp NULL terminator to it's original character
781 *((CHAR16
*)(Walker
+1)) = TempChar
;
784 // Update LineStart Variable
786 LineStart
= Walker
+ 1;
789 // increment row count and zero the column
791 ShellInfoObject
.ConsoleInfo
->RowCounter
++;
792 ConsoleInfo
->OurConOut
.Mode
->CursorRow
++;
793 ConsoleInfo
->OurConOut
.Mode
->CursorColumn
= 0;
794 } // last column on line
796 } // switch for character
799 // check if that was the last printable row. If yes handle PageBreak mode
801 if ((ConsoleInfo
->RowsPerScreen
) -1 == ShellInfoObject
.ConsoleInfo
->RowCounter
) {
802 if (EFI_ERROR(ConsoleLoggerDoPageBreak())) {
804 // We got an error which means 'break' and halt the printing
806 SHELL_FREE_NON_NULL(StringCopy
);
807 return (EFI_DEVICE_ERROR
);
812 if (LineStart
!= NULL
&& *LineStart
!= CHAR_NULL
) {
813 ConsoleLoggerOutputStringSplit (LineStart
, ConsoleInfo
);
816 SHELL_FREE_NON_NULL(StringCopy
);
817 return (EFI_SUCCESS
);
821 Write a Unicode string to the output device.
823 @param[in] This Protocol instance pointer.
824 @param[in] WString The NULL-terminated Unicode string to be displayed on the output
825 device(s). All output devices must also support the Unicode
826 drawing defined in this file.
827 @retval EFI_SUCCESS The string was output to the device.
828 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
830 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
832 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
833 characters in the Unicode string could not be
834 rendered and were skipped.
838 ConsoleLoggerOutputString (
839 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
844 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
845 EFI_KEY_DATA KeyData
;
847 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
849 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
850 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
851 return (EFI_UNSUPPORTED
);
853 ASSERT(ShellInfoObject
.ConsoleInfo
== ConsoleInfo
);
855 Status
= gBS
->HandleProtocol (gST
->ConsoleInHandle
, &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
856 if (!EFI_ERROR (Status
)) {
857 while (ShellInfoObject
.HaltOutput
) {
859 ShellInfoObject
.HaltOutput
= FALSE
;
863 Status
= gBS
->WaitForEvent (1, &TxtInEx
->WaitForKeyEx
, &EventIndex
);
864 ASSERT_EFI_ERROR (Status
);
865 Status
= TxtInEx
->ReadKeyStrokeEx (TxtInEx
, &KeyData
);
866 if (EFI_ERROR(Status
)) {
870 if ((KeyData
.Key
.UnicodeChar
== L
's') && (KeyData
.Key
.ScanCode
== SCAN_NULL
) &&
871 ((KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_LEFT_CONTROL_PRESSED
)) ||
872 (KeyData
.KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
| EFI_RIGHT_CONTROL_PRESSED
))
875 ShellInfoObject
.HaltOutput
= TRUE
;
880 if (!ShellInfoObject
.ConsoleInfo
->Enabled
) {
881 return (EFI_DEVICE_ERROR
);
882 } else if (ShellInfoObject
.PageBreakEnabled
) {
883 return (ConsoleLoggerPrintWithPageBreak(WString
, ConsoleInfo
));
885 return (ConsoleLoggerOutputStringSplit(WString
, ConsoleInfo
));
890 Verifies that all characters in a Unicode string can be output to the
893 @param[in] This Protocol instance pointer.
894 @param[in] WString The NULL-terminated Unicode string to be examined for the output
897 @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
898 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
899 rendered by one or more of the output devices mapped
905 ConsoleLoggerTestString (
906 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
910 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
911 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
913 // Forward the request to the original ConOut
915 return (ConsoleInfo
->OldConOut
->TestString (ConsoleInfo
->OldConOut
, WString
));
919 Returns information for an available text mode that the output device(s)
922 @param[in] This Protocol instance pointer.
923 @param[in] ModeNumber The mode number to return information on.
924 @param[out] Columns Upon return, the number of columns in the selected geometry
925 @param[out] Rows Upon return, the number of rows in the selected geometry
927 @retval EFI_SUCCESS The requested mode information was returned.
928 @retval EFI_DEVICE_ERROR The device had an error and could not
929 complete the request.
930 @retval EFI_UNSUPPORTED The mode number was not valid.
934 ConsoleLoggerQueryMode (
935 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
941 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
942 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
944 // Forward the request to the original ConOut
946 return (ConsoleInfo
->OldConOut
->QueryMode (
947 ConsoleInfo
->OldConOut
,
955 Sets the output device(s) to a specified mode.
957 @param[in] This Protocol instance pointer.
958 @param[in] ModeNumber The mode number to set.
961 @retval EFI_SUCCESS The requested text mode was set.
962 @retval EFI_DEVICE_ERROR The device had an error and
963 could not complete the request.
964 @retval EFI_UNSUPPORTED The mode number was not valid.
968 ConsoleLoggerSetMode (
969 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
975 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
976 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
979 // Forward the request to the original ConOut
981 Status
= ConsoleInfo
->OldConOut
->SetMode (ConsoleInfo
->OldConOut
, ModeNumber
);
984 // Check that the buffers are still correct for logging
986 if (!EFI_ERROR (Status
)) {
987 ConsoleInfo
->OurConOut
.Mode
= ConsoleInfo
->OldConOut
->Mode
;
988 ConsoleLoggerResetBuffers(ConsoleInfo
);
989 ConsoleInfo
->OriginalStartRow
= 0;
990 ConsoleInfo
->CurrentStartRow
= 0;
991 ConsoleInfo
->OurConOut
.ClearScreen (&ConsoleInfo
->OurConOut
);
998 Sets the background and foreground colors for the OutputString () and
999 ClearScreen () functions.
1001 @param[in] This Protocol instance pointer.
1002 @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
1003 bits 4..6 are the background color. All other bits are undefined
1004 and must be zero. The valid Attributes are defined in this file.
1006 @retval EFI_SUCCESS The attribute was set.
1007 @retval EFI_DEVICE_ERROR The device had an error and
1008 could not complete the request.
1009 @retval EFI_UNSUPPORTED The attribute requested is not defined.
1014 ConsoleLoggerSetAttribute (
1015 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1021 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1022 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1025 // Forward the request to the original ConOut
1027 Status
= ConsoleInfo
->OldConOut
->SetAttribute (ConsoleInfo
->OldConOut
, Attribute
);
1030 // Record console output history
1032 if (!EFI_ERROR (Status
)) {
1033 ConsoleInfo
->HistoryMode
.Attribute
= (INT32
) Attribute
;
1040 Clears the output device(s) display to the currently selected background
1043 @param[in] This Protocol instance pointer.
1045 @retval EFI_SUCCESS The operation completed successfully.
1046 @retval EFI_DEVICE_ERROR The device had an error and
1047 could not complete the request.
1048 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1052 ConsoleLoggerClearScreen (
1053 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
1061 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1063 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1064 return (EFI_UNSUPPORTED
);
1067 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1070 // Forward the request to the original ConOut
1072 Status
= ConsoleInfo
->OldConOut
->ClearScreen (ConsoleInfo
->OldConOut
);
1075 // Record console output history
1077 if (!EFI_ERROR (Status
)) {
1078 Screen
= &ConsoleInfo
->Buffer
[(ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->CurrentStartRow
];
1079 Attributes
= &ConsoleInfo
->Attributes
[ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->CurrentStartRow
];
1080 for ( Row
= ConsoleInfo
->OriginalStartRow
1081 ; Row
< (ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
)
1085 ; Column
< ConsoleInfo
->ColsPerScreen
1091 *Attributes
= ConsoleInfo
->OldConOut
->Mode
->Attribute
;
1094 // Skip the NULL on each column end in text buffer only
1098 ConsoleInfo
->HistoryMode
.CursorColumn
= 0;
1099 ConsoleInfo
->HistoryMode
.CursorRow
= 0;
1106 Sets the current coordinates of the cursor position
1108 @param[in] This Protocol instance pointer.
1109 @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
1110 @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
1112 @retval EFI_SUCCESS The operation completed successfully.
1113 @retval EFI_DEVICE_ERROR The device had an error and
1114 could not complete the request.
1115 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
1116 cursor position is invalid for the current mode.
1120 ConsoleLoggerSetCursorPosition (
1121 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1127 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1129 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
1130 return (EFI_UNSUPPORTED
);
1133 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1135 // Forward the request to the original ConOut
1137 Status
= ConsoleInfo
->OldConOut
->SetCursorPosition (
1138 ConsoleInfo
->OldConOut
,
1144 // Record console output history
1146 if (!EFI_ERROR (Status
)) {
1147 ConsoleInfo
->HistoryMode
.CursorColumn
= (INT32
)Column
;
1148 ConsoleInfo
->HistoryMode
.CursorRow
= (INT32
)(ConsoleInfo
->OriginalStartRow
+ Row
);
1155 Makes the cursor visible or invisible
1157 @param[in] This Protocol instance pointer.
1158 @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
1159 set to be invisible.
1161 @retval EFI_SUCCESS The operation completed successfully.
1162 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1163 request, or the device does not support changing
1165 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1169 ConsoleLoggerEnableCursor (
1170 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
1176 CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
;
1177 ConsoleInfo
= CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This
);
1179 // Forward the request to the original ConOut
1181 Status
= ConsoleInfo
->OldConOut
->EnableCursor (ConsoleInfo
->OldConOut
, Visible
);
1184 // Record console output history
1186 if (!EFI_ERROR (Status
)) {
1187 ConsoleInfo
->HistoryMode
.CursorVisible
= Visible
;
1194 Function to update and verify that the current buffers are correct.
1196 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
1198 This will be used when a mode has changed or a reset ocurred to verify all
1202 ConsoleLoggerResetBuffers(
1203 IN CONSOLE_LOGGER_PRIVATE_DATA
*ConsoleInfo
1208 if (ConsoleInfo
->Buffer
!= NULL
) {
1209 FreePool(ConsoleInfo
->Buffer
);
1210 ConsoleInfo
->Buffer
= NULL
;
1211 ConsoleInfo
->BufferSize
= 0;
1213 if (ConsoleInfo
->Attributes
!= NULL
) {
1214 FreePool(ConsoleInfo
->Attributes
);
1215 ConsoleInfo
->Attributes
= NULL
;
1216 ConsoleInfo
->AttribSize
= 0;
1219 Status
= gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &ConsoleInfo
->ColsPerScreen
, &ConsoleInfo
->RowsPerScreen
);
1220 if (EFI_ERROR(Status
)){
1224 ConsoleInfo
->BufferSize
= (ConsoleInfo
->ColsPerScreen
+ 2) * ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof(ConsoleInfo
->Buffer
[0]);
1225 ConsoleInfo
->AttribSize
= ConsoleInfo
->ColsPerScreen
* ConsoleInfo
->RowsPerScreen
* ConsoleInfo
->ScreenCount
* sizeof(ConsoleInfo
->Attributes
[0]);
1227 ConsoleInfo
->Buffer
= (CHAR16
*)AllocateZeroPool(ConsoleInfo
->BufferSize
);
1229 if (ConsoleInfo
->Buffer
== NULL
) {
1230 return (EFI_OUT_OF_RESOURCES
);
1233 ConsoleInfo
->Attributes
= (INT32
*)AllocateZeroPool(ConsoleInfo
->AttribSize
);
1234 if (ConsoleInfo
->Attributes
== NULL
) {
1235 FreePool(ConsoleInfo
->Buffer
);
1236 ConsoleInfo
->Buffer
= NULL
;
1237 return (EFI_OUT_OF_RESOURCES
);
1240 CopyMem (&ConsoleInfo
->HistoryMode
, ConsoleInfo
->OldConOut
->Mode
, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE
));
1242 return (EFI_SUCCESS
);