diff options
Diffstat (limited to 'ShellPkg/Application/Shell/ConsoleLogger.c')
| -rw-r--r-- | ShellPkg/Application/Shell/ConsoleLogger.c | 2556 |
1 files changed, 1278 insertions, 1278 deletions
diff --git a/ShellPkg/Application/Shell/ConsoleLogger.c b/ShellPkg/Application/Shell/ConsoleLogger.c index abef0a60d6..1a8ff25448 100644 --- a/ShellPkg/Application/Shell/ConsoleLogger.c +++ b/ShellPkg/Application/Shell/ConsoleLogger.c @@ -1,1278 +1,1278 @@ -/** @file
- Provides interface to shell console logger.
-
- (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2016 Hewlett-Packard Development Company, L.P.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include "Shell.h"
-
-/**
- Install our intermediate ConOut into the system table to
- keep a log of all the info that is displayed to the user.
-
- @param[in] ScreensToSave Sets how many screen-worths of data to save.
- @param[out] ConsoleInfo The object to pass into later functions.
-
- @retval EFI_SUCCESS The operation was successful.
- @return other The operation failed.
-
- @sa ConsoleLoggerResetBuffers
- @sa InstallProtocolInterface
-**/
-EFI_STATUS
-ConsoleLoggerInstall (
- IN CONST UINTN ScreensToSave,
- OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo
- )
-{
- EFI_STATUS Status;
-
- ASSERT (ConsoleInfo != NULL);
-
- (*ConsoleInfo) = AllocateZeroPool (sizeof (CONSOLE_LOGGER_PRIVATE_DATA));
- if ((*ConsoleInfo) == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE;
- (*ConsoleInfo)->OldConOut = gST->ConOut;
- (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle;
- (*ConsoleInfo)->Buffer = NULL;
- (*ConsoleInfo)->BufferSize = 0;
- (*ConsoleInfo)->OriginalStartRow = 0;
- (*ConsoleInfo)->CurrentStartRow = 0;
- (*ConsoleInfo)->RowsPerScreen = 0;
- (*ConsoleInfo)->ColsPerScreen = 0;
- (*ConsoleInfo)->Attributes = NULL;
- (*ConsoleInfo)->AttribSize = 0;
- (*ConsoleInfo)->ScreenCount = ScreensToSave;
- (*ConsoleInfo)->HistoryMode.MaxMode = 1;
- (*ConsoleInfo)->HistoryMode.Mode = 0;
- (*ConsoleInfo)->HistoryMode.Attribute = 0;
- (*ConsoleInfo)->HistoryMode.CursorColumn = 0;
- (*ConsoleInfo)->HistoryMode.CursorRow = 0;
- (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE;
- (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset;
- (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString;
- (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString;
- (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode;
- (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode;
- (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute;
- (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen;
- (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition;
- (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor;
- (*ConsoleInfo)->OurConOut.Mode = gST->ConOut->Mode;
- (*ConsoleInfo)->Enabled = TRUE;
-
- Status = ConsoleLoggerResetBuffers (*ConsoleInfo);
- if (EFI_ERROR (Status)) {
- SHELL_FREE_NON_NULL ((*ConsoleInfo));
- *ConsoleInfo = NULL;
- return (Status);
- }
-
- Status = gBS->InstallProtocolInterface (&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID *)&((*ConsoleInfo)->OurConOut));
- if (EFI_ERROR (Status)) {
- SHELL_FREE_NON_NULL ((*ConsoleInfo)->Buffer);
- SHELL_FREE_NON_NULL ((*ConsoleInfo)->Attributes);
- SHELL_FREE_NON_NULL ((*ConsoleInfo));
- *ConsoleInfo = NULL;
- return (Status);
- }
-
- gST->ConsoleOutHandle = gImageHandle;
- gST->ConOut = &(*ConsoleInfo)->OurConOut;
-
- //
- // Update the CRC32 in the EFI System Table header
- //
- gST->Hdr.CRC32 = 0;
- gBS->CalculateCrc32 (
- (UINT8 *)&gST->Hdr,
- gST->Hdr.HeaderSize,
- &gST->Hdr.CRC32
- );
- return (Status);
-}
-
-/**
- Return the system to the state it was before InstallConsoleLogger
- was installed.
-
- @param[in] ConsoleInfo The object from the install function.
-
- @retval EFI_SUCCESS The operation was successful
- @return other The operation failed. This was from UninstallProtocolInterface.
-**/
-EFI_STATUS
-ConsoleLoggerUninstall (
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- ASSERT (ConsoleInfo != NULL);
- ASSERT (ConsoleInfo->OldConOut != NULL);
-
- if (ConsoleInfo->Buffer != NULL) {
- FreePool (ConsoleInfo->Buffer);
- DEBUG_CODE (
- ConsoleInfo->Buffer = NULL;
- );
- DEBUG_CODE (
- ConsoleInfo->BufferSize = 0;
- );
- }
-
- if (ConsoleInfo->Attributes != NULL) {
- FreePool (ConsoleInfo->Attributes);
- DEBUG_CODE (
- ConsoleInfo->Attributes = NULL;
- );
- DEBUG_CODE (
- ConsoleInfo->AttribSize = 0;
- );
- }
-
- gST->ConsoleOutHandle = ConsoleInfo->OldConHandle;
- gST->ConOut = ConsoleInfo->OldConOut;
-
- //
- // Update the CRC32 in the EFI System Table header
- //
- gST->Hdr.CRC32 = 0;
- gBS->CalculateCrc32 (
- (UINT8 *)&gST->Hdr,
- gST->Hdr.HeaderSize,
- &gST->Hdr.CRC32
- );
-
- return (gBS->UninstallProtocolInterface (gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID *)&ConsoleInfo->OurConOut));
-}
-
-/**
- Displays previously logged output back to the screen.
-
- This will scroll the screen forwards and backwards through the log of previous
- output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
- is (UINTN)(-1) then the size of the screen will be scrolled.
-
- @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
- If FALSE then the log will be displayed backwards (scroll to older).
- @param[in] Rows Determines how many rows the log should scroll.
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-**/
-EFI_STATUS
-ConsoleLoggerDisplayHistory (
- IN CONST BOOLEAN Forward,
- IN CONST UINTN Rows,
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- UINTN RowChange;
-
- ASSERT (ConsoleInfo != NULL);
-
- //
- // Calculate the row number change
- //
- switch (Rows) {
- case ((UINTN)(-1)):
- RowChange = ConsoleInfo->RowsPerScreen;
- break;
- case (0):
- RowChange = ConsoleInfo->RowsPerScreen / 2;
- break;
- default:
- RowChange = Rows;
- break;
- }
-
- //
- // Do the math for direction
- //
- if (Forward) {
- if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) {
- RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow;
- }
- } else {
- if (ConsoleInfo->CurrentStartRow < RowChange) {
- RowChange = ConsoleInfo->CurrentStartRow;
- }
- }
-
- //
- // If we are already at one end or the other
- //
- if (RowChange == 0) {
- return (EFI_SUCCESS);
- }
-
- //
- // Clear the screen
- //
- ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
-
- //
- // Set the new start row
- //
- if (Forward) {
- ConsoleInfo->CurrentStartRow += RowChange;
- } else {
- ConsoleInfo->CurrentStartRow -= RowChange;
- }
-
- //
- // Change the screen
- //
- return (UpdateDisplayFromHistory (ConsoleInfo));
-}
-
-/**
- Function to return to normal output whent he scrolling is complete.
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-
- @retval EFI_SUCCESS The operation was successful.
- @return other The operation failed. See UpdateDisplayFromHistory.
-
- @sa UpdateDisplayFromHistory
-**/
-EFI_STATUS
-ConsoleLoggerStopHistory (
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- ASSERT (ConsoleInfo != NULL);
- if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
- return (EFI_SUCCESS);
- }
-
- //
- // Clear the screen
- //
- ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
-
- ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow;
- return (UpdateDisplayFromHistory (ConsoleInfo));
-}
-
-/**
- Updates the hidden ConOut to be displaying the correct stuff.
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-
- @retval EFI_SUCCESS The operation was successful.
- @return other The operation failed.
-**/
-EFI_STATUS
-UpdateDisplayFromHistory (
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- EFI_STATUS Status;
- EFI_STATUS RetVal;
- CHAR16 *Screen;
- INT32 *Attributes;
- UINTN CurrentRow;
- CHAR16 TempCharHolder;
- UINTN Column;
- INT32 CurrentAttrib;
- UINTN CurrentColumn;
- CHAR16 *StringSegment;
- CHAR16 *StringSegmentEnd;
- CHAR16 StringSegmentEndChar;
- INT32 OrigAttribute;
-
- ASSERT (ConsoleInfo != NULL);
- TempCharHolder = CHAR_NULL;
- RetVal = EFI_SUCCESS;
- OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute;
-
- //
- // Disable cursor visibility and move it to the top left corner
- //
- ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE);
- ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0);
-
- Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
- Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
- for ( CurrentRow = 0
- ; CurrentRow < ConsoleInfo->RowsPerScreen
- ; CurrentRow++,
- Screen += (ConsoleInfo->ColsPerScreen + 2),
- Attributes += ConsoleInfo->ColsPerScreen
- )
- {
- //
- // dont use the last char - prevents screen scroll
- //
- if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)) {
- TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1];
- Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL;
- }
-
- for ( Column = 0
- ; Column < ConsoleInfo->ColsPerScreen
- ; Column++
- )
- {
- if (Screen[Column] != CHAR_NULL) {
- CurrentAttrib = Attributes[Column];
- CurrentColumn = Column;
- StringSegment = &Screen[Column];
-
- //
- // Find the first char with a different attribute and make that temporarily NULL
- // so we can do fewer printout statements. (later) restore that one and we will
- // start at that column on the next loop.
- //
- StringSegmentEndChar = CHAR_NULL;
- for ( StringSegmentEnd = StringSegment
- ; *StringSegmentEnd != CHAR_NULL
- ; StringSegmentEnd++,
- Column++
- )
- {
- if (Attributes[Column] != CurrentAttrib) {
- StringSegmentEndChar = *StringSegmentEnd;
- *StringSegmentEnd = CHAR_NULL;
- break;
- }
- } // StringSegmentEnd loop
-
- //
- // Now write out as much as had the same Attributes
- //
-
- ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, CurrentAttrib);
- ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, CurrentColumn, CurrentRow);
- Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, StringSegment);
-
- if (EFI_ERROR (Status)) {
- ASSERT (FALSE);
- RetVal = Status;
- }
-
- //
- // If we found a change in attribute put the character back and decrement the column
- // so when it increments it will point at that character and we will start printing
- // a segment with that new attribute
- //
- if (StringSegmentEndChar != CHAR_NULL) {
- *StringSegmentEnd = StringSegmentEndChar;
- StringSegmentEndChar = CHAR_NULL;
- Column--;
- }
- }
- } // column for loop
-
- //
- // If we removed the last char and this was the last row put it back
- //
- if (TempCharHolder != CHAR_NULL) {
- Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder;
- TempCharHolder = CHAR_NULL;
- }
- } // row for loop
-
- //
- // If we are setting the screen back to original turn on the cursor and make it visible
- // and set the attributes back to what they were
- //
- if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
- ConsoleInfo->OldConOut->SetAttribute (
- ConsoleInfo->OldConOut,
- ConsoleInfo->HistoryMode.Attribute
- );
- ConsoleInfo->OldConOut->SetCursorPosition (
- ConsoleInfo->OldConOut,
- ConsoleInfo->HistoryMode.CursorColumn,
- ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow
- );
-
- Status = ConsoleInfo->OldConOut->EnableCursor (
- ConsoleInfo->OldConOut,
- ConsoleInfo->HistoryMode.CursorVisible
- );
- if (EFI_ERROR (Status)) {
- RetVal = Status;
- }
- } else {
- ConsoleInfo->OldConOut->SetAttribute (
- ConsoleInfo->OldConOut,
- OrigAttribute
- );
- }
-
- return (RetVal);
-}
-
-/**
- Reset the text output device hardware and optionally run diagnostics
-
- @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
- @param ExtendedVerification Indicates that a more extensive test may be performed
-
- @retval EFI_SUCCESS The text output device was reset.
- @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
- could not be reset.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerReset (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- EFI_STATUS Status;
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification);
-
- //
- // Check that the buffers are still correct for logging
- //
- if (!EFI_ERROR (Status)) {
- ConsoleLoggerResetBuffers (ConsoleInfo);
- if (ExtendedVerification) {
- ConsoleInfo->OriginalStartRow = 0;
- ConsoleInfo->CurrentStartRow = 0;
- }
- }
-
- return Status;
-}
-
-/**
- Appends a string to the history buffer. If the buffer is full then the oldest
- information in the buffer will be dropped. Information is added in a line by
- line manner such that an empty line takes up just as much space as a full line.
-
- @param[in] String String pointer to add.
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-**/
-EFI_STATUS
-AppendStringToHistory (
- IN CONST CHAR16 *String,
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- CONST CHAR16 *Walker;
- UINTN CopySize;
- UINTN PrintIndex;
- UINTN Index;
-
- ASSERT (ConsoleInfo != NULL);
-
- for ( Walker = String
- ; Walker != NULL && *Walker != CHAR_NULL
- ; Walker++
- )
- {
- switch (*Walker) {
- case (CHAR_BACKSPACE):
- if (ConsoleInfo->HistoryMode.CursorColumn > 0) {
- ConsoleInfo->HistoryMode.CursorColumn--;
- }
-
- break;
- case (CHAR_LINEFEED):
- if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) {
- //
- // Should never be bigger
- //
- ASSERT (ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1));
-
- //
- // scroll history attributes 'up' 1 row and set the last row to default attribute
- //
- CopySize = ConsoleInfo->ColsPerScreen
- * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
- * sizeof (ConsoleInfo->Attributes[0]);
- ASSERT (CopySize < ConsoleInfo->AttribSize);
- CopyMem (
- ConsoleInfo->Attributes,
- ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen,
- CopySize
- );
-
- for ( Index = 0
- ; Index < ConsoleInfo->ColsPerScreen
- ; Index++
- )
- {
- *(ConsoleInfo->Attributes + (CopySize/sizeof (ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute;
- }
-
- //
- // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
- //
- CopySize = (ConsoleInfo->ColsPerScreen + 2)
- * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
- * sizeof (ConsoleInfo->Buffer[0]);
- ASSERT (CopySize < ConsoleInfo->BufferSize);
- CopyMem (
- ConsoleInfo->Buffer,
- ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2),
- CopySize
- );
-
- //
- // Set that last row of chars to spaces
- //
- SetMem16 (((UINT8 *)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof (CHAR16), L' ');
- } else {
- //
- // we are not on the last row
- //
-
- //
- // We should not be scrolling history
- //
- ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow);
- //
- // are we at the end of a row?
- //
- if (ConsoleInfo->HistoryMode.CursorRow == (INT32)(ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) {
- ConsoleInfo->OriginalStartRow++;
- ConsoleInfo->CurrentStartRow++;
- }
-
- ConsoleInfo->HistoryMode.CursorRow++;
- }
-
- break;
- case (CHAR_CARRIAGE_RETURN):
- //
- // Move the cursor to the beginning of the current row.
- //
- ConsoleInfo->HistoryMode.CursorColumn = 0;
- break;
- default:
- //
- // Acrtually print characters into the history buffer
- //
-
- PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn;
-
- for ( // no initializer needed
- ; ConsoleInfo->HistoryMode.CursorColumn < (INT32)ConsoleInfo->ColsPerScreen
- ; ConsoleInfo->HistoryMode.CursorColumn++,
- PrintIndex++,
- Walker++
- )
- {
- if ( (*Walker == CHAR_NULL)
- || (*Walker == CHAR_BACKSPACE)
- || (*Walker == CHAR_LINEFEED)
- || (*Walker == CHAR_CARRIAGE_RETURN)
- )
- {
- Walker--;
- break;
- }
-
- //
- // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
- //
-
- ASSERT (PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize);
- ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker;
- ASSERT (PrintIndex < ConsoleInfo->AttribSize);
- ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute;
- } // for loop
-
- //
- // Add the carriage return and line feed at the end of the lines
- //
- if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) {
- AppendStringToHistory (L"\r\n", ConsoleInfo);
- Walker--;
- }
-
- break;
- } // switch for character
- } // for loop
-
- return (EFI_SUCCESS);
-}
-
-/**
- Worker function to handle printing the output to the screen
- and the history buffer
-
- @param[in] String The string to output
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-
- @retval EFI_SUCCESS The string was printed
- @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
- the text.
- @retval EFI_UNSUPPORTED The output device's mode is not currently in a
- defined text mode.
- @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
- characters in the Unicode string could not be
- rendered and were skipped.
-**/
-EFI_STATUS
-ConsoleLoggerOutputStringSplit (
- IN CONST CHAR16 *String,
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- EFI_STATUS Status;
-
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16 *)String);
-
- if (EFI_ERROR (Status)) {
- return (Status);
- }
-
- return (AppendStringToHistory (String, ConsoleInfo));
-}
-
-/**
- Function to handle page break mode.
-
- This function will prompt for continue or break.
-
- @retval EFI_SUCCESS Continue was choosen
- @return other Break was choosen
-**/
-EFI_STATUS
-ConsoleLoggerDoPageBreak (
- VOID
- )
-{
- SHELL_PROMPT_RESPONSE *Resp;
- EFI_STATUS Status;
-
- Resp = NULL;
- ASSERT (ShellInfoObject.PageBreakEnabled);
- ShellInfoObject.PageBreakEnabled = FALSE;
- Status = ShellPromptForResponseHii (ShellPromptResponseTypeQuitContinue, STRING_TOKEN (STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID **)&Resp);
- ShellInfoObject.PageBreakEnabled = TRUE;
- ASSERT (Resp != NULL);
- if (Resp == NULL) {
- return (EFI_NOT_FOUND);
- }
-
- if (EFI_ERROR (Status)) {
- if (Resp != NULL) {
- FreePool (Resp);
- }
-
- return (Status);
- }
-
- if (*Resp == ShellPromptResponseContinue) {
- FreePool (Resp);
- ShellInfoObject.ConsoleInfo->RowCounter = 0;
- // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
- // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
-
- return (EFI_SUCCESS);
- } else if (*Resp == ShellPromptResponseQuit) {
- FreePool (Resp);
- ShellInfoObject.ConsoleInfo->Enabled = FALSE;
- //
- // When user wants to quit, the shell should stop running the command.
- //
- gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);
- return (EFI_DEVICE_ERROR);
- } else {
- ASSERT (FALSE);
- }
-
- return (EFI_SUCCESS);
-}
-
-/**
- Worker function to handle printing the output with page breaks.
-
- @param[in] String The string to output
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-
- @retval EFI_SUCCESS The string was printed
- @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
- the text.
- @retval EFI_UNSUPPORTED The output device's mode is not currently in a
- defined text mode.
- @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
- characters in the Unicode string could not be
- rendered and were skipped.
-**/
-EFI_STATUS
-ConsoleLoggerPrintWithPageBreak (
- IN CONST CHAR16 *String,
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- CONST CHAR16 *Walker;
- CONST CHAR16 *LineStart;
- CHAR16 *StringCopy;
- CHAR16 TempChar;
-
- StringCopy = NULL;
- StringCopy = StrnCatGrow (&StringCopy, NULL, String, 0);
- if (StringCopy == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- for ( Walker = StringCopy,
- LineStart = StringCopy
- ; Walker != NULL && *Walker != CHAR_NULL
- ; Walker++
- )
- {
- switch (*Walker) {
- case (CHAR_BACKSPACE):
- if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) {
- ConsoleInfo->OurConOut.Mode->CursorColumn--;
- }
-
- break;
- case (CHAR_LINEFEED):
- //
- // add a temp NULL terminator
- //
- TempChar = *(Walker + 1);
- *((CHAR16 *)(Walker+1)) = CHAR_NULL;
-
- //
- // output the string
- //
- ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
-
- //
- // restore the temp NULL terminator to its original character
- //
- *((CHAR16 *)(Walker+1)) = TempChar;
-
- //
- // Update LineStart Variable
- //
- LineStart = Walker + 1;
-
- //
- // increment row count
- //
- ShellInfoObject.ConsoleInfo->RowCounter++;
- ConsoleInfo->OurConOut.Mode->CursorRow++;
-
- break;
- case (CHAR_CARRIAGE_RETURN):
- //
- // Move the cursor to the beginning of the current row.
- //
- ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
- break;
- default:
- //
- // increment column count
- //
- ConsoleInfo->OurConOut.Mode->CursorColumn++;
- //
- // check if that is the last column
- //
- if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) {
- //
- // output a line similar to the linefeed character.
- //
-
- //
- // add a temp NULL terminator
- //
- TempChar = *(Walker + 1);
- *((CHAR16 *)(Walker+1)) = CHAR_NULL;
-
- //
- // output the string
- //
- ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
-
- //
- // restore the temp NULL terminator to its original character
- //
- *((CHAR16 *)(Walker+1)) = TempChar;
-
- //
- // Update LineStart Variable
- //
- LineStart = Walker + 1;
-
- //
- // increment row count and zero the column
- //
- ShellInfoObject.ConsoleInfo->RowCounter++;
- ConsoleInfo->OurConOut.Mode->CursorRow++;
- ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
- } // last column on line
-
- break;
- } // switch for character
-
- //
- // check if that was the last printable row. If yes handle PageBreak mode
- //
- if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) {
- if (EFI_ERROR (ConsoleLoggerDoPageBreak ())) {
- //
- // We got an error which means 'break' and halt the printing
- //
- SHELL_FREE_NON_NULL (StringCopy);
- return (EFI_DEVICE_ERROR);
- }
- }
- } // for loop
-
- if ((LineStart != NULL) && (*LineStart != CHAR_NULL)) {
- ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
- }
-
- SHELL_FREE_NON_NULL (StringCopy);
- return (EFI_SUCCESS);
-}
-
-/**
- Write a Unicode string to the output device.
-
- @param[in] This Protocol instance pointer.
- @param[in] WString The NULL-terminated Unicode string to be displayed on the output
- device(s). All output devices must also support the Unicode
- drawing defined in this file.
- @retval EFI_SUCCESS The string was output to the device.
- @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
- the text.
- @retval EFI_UNSUPPORTED The output device's mode is not currently in a
- defined text mode.
- @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
- characters in the Unicode string could not be
- rendered and were skipped.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerOutputString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *WString
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
- EFI_KEY_DATA KeyData;
- UINTN EventIndex;
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
- if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
- return (EFI_UNSUPPORTED);
- }
-
- ASSERT (ShellInfoObject.ConsoleInfo == ConsoleInfo);
-
- Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
- if (!EFI_ERROR (Status)) {
- while (ShellInfoObject.HaltOutput) {
- ShellInfoObject.HaltOutput = FALSE;
- //
- // just get some key
- //
- Status = gBS->WaitForEvent (1, &TxtInEx->WaitForKeyEx, &EventIndex);
- ASSERT_EFI_ERROR (Status);
- Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- if ((KeyData.Key.UnicodeChar == L's') && (KeyData.Key.ScanCode == SCAN_NULL) &&
- ((KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED)) ||
- (KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_RIGHT_CONTROL_PRESSED))
- )
- )
- {
- ShellInfoObject.HaltOutput = TRUE;
- }
- }
- }
-
- if (!ShellInfoObject.ConsoleInfo->Enabled) {
- return (EFI_DEVICE_ERROR);
- } else if (ShellInfoObject.PageBreakEnabled) {
- return (ConsoleLoggerPrintWithPageBreak (WString, ConsoleInfo));
- } else {
- return (ConsoleLoggerOutputStringSplit (WString, ConsoleInfo));
- }
-}
-
-/**
- Verifies that all characters in a Unicode string can be output to the
- target device.
-
- @param[in] This Protocol instance pointer.
- @param[in] WString The NULL-terminated Unicode string to be examined for the output
- device(s).
-
- @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
- @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
- rendered by one or more of the output devices mapped
- by the EFI handle.
-
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerTestString (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN CHAR16 *WString
- )
-{
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
- //
- // Forward the request to the original ConOut
- //
- return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString));
-}
-
-/**
- Returns information for an available text mode that the output device(s)
- supports.
-
- @param[in] This Protocol instance pointer.
- @param[in] ModeNumber The mode number to return information on.
- @param[out] Columns Upon return, the number of columns in the selected geometry
- @param[out] Rows Upon return, the number of rows in the selected geometry
-
- @retval EFI_SUCCESS The requested mode information was returned.
- @retval EFI_DEVICE_ERROR The device had an error and could not
- complete the request.
- @retval EFI_UNSUPPORTED The mode number was not valid.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerQueryMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber,
- OUT UINTN *Columns,
- OUT UINTN *Rows
- )
-{
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
- //
- // Forward the request to the original ConOut
- //
- return (ConsoleInfo->OldConOut->QueryMode (
- ConsoleInfo->OldConOut,
- ModeNumber,
- Columns,
- Rows
- ));
-}
-
-/**
- Sets the output device(s) to a specified mode.
-
- @param[in] This Protocol instance pointer.
- @param[in] ModeNumber The mode number to set.
-
-
- @retval EFI_SUCCESS The requested text mode was set.
- @retval EFI_DEVICE_ERROR The device had an error and
- could not complete the request.
- @retval EFI_UNSUPPORTED The mode number was not valid.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerSetMode (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN ModeNumber
- )
-{
- EFI_STATUS Status;
-
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber);
-
- //
- // Check that the buffers are still correct for logging
- //
- if (!EFI_ERROR (Status)) {
- ConsoleInfo->OurConOut.Mode = ConsoleInfo->OldConOut->Mode;
- ConsoleLoggerResetBuffers (ConsoleInfo);
- ConsoleInfo->OriginalStartRow = 0;
- ConsoleInfo->CurrentStartRow = 0;
- ConsoleInfo->OurConOut.ClearScreen (&ConsoleInfo->OurConOut);
- }
-
- return Status;
-}
-
-/**
- Sets the background and foreground colors for the OutputString () and
- ClearScreen () functions.
-
- @param[in] This Protocol instance pointer.
- @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
- bits 4..6 are the background color. All other bits are undefined
- and must be zero. The valid Attributes are defined in this file.
-
- @retval EFI_SUCCESS The attribute was set.
- @retval EFI_DEVICE_ERROR The device had an error and
- could not complete the request.
- @retval EFI_UNSUPPORTED The attribute requested is not defined.
-
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerSetAttribute (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Attribute
- )
-{
- EFI_STATUS Status;
-
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute);
-
- //
- // Record console output history
- //
- if (!EFI_ERROR (Status)) {
- ConsoleInfo->HistoryMode.Attribute = (INT32)Attribute;
- }
-
- return Status;
-}
-
-/**
- Clears the output device(s) display to the currently selected background
- color.
-
- @param[in] This Protocol instance pointer.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_DEVICE_ERROR The device had an error and
- could not complete the request.
- @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerClearScreen (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
- )
-{
- EFI_STATUS Status;
- CHAR16 *Screen;
- INT32 *Attributes;
- UINTN Row;
- UINTN Column;
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
- return (EFI_UNSUPPORTED);
- }
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
-
- //
- // Record console output history
- //
- if (!EFI_ERROR (Status)) {
- Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
- Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
- for ( Row = ConsoleInfo->OriginalStartRow
- ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)
- ; Row++
- )
- {
- for ( Column = 0
- ; Column < ConsoleInfo->ColsPerScreen
- ; Column++,
- Screen++,
- Attributes++
- )
- {
- *Screen = L' ';
- *Attributes = ConsoleInfo->OldConOut->Mode->Attribute;
- }
-
- //
- // Skip the NULL on each column end in text buffer only
- //
- Screen += 2;
- }
-
- ConsoleInfo->HistoryMode.CursorColumn = 0;
- ConsoleInfo->HistoryMode.CursorRow = 0;
- }
-
- return Status;
-}
-
-/**
- Sets the current coordinates of the cursor position
-
- @param[in] This Protocol instance pointer.
- @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
- @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_DEVICE_ERROR The device had an error and
- could not complete the request.
- @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
- cursor position is invalid for the current mode.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerSetCursorPosition (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN UINTN Column,
- IN UINTN Row
- )
-{
- EFI_STATUS Status;
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
- return (EFI_UNSUPPORTED);
- }
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->SetCursorPosition (
- ConsoleInfo->OldConOut,
- Column,
- Row
- );
-
- //
- // Record console output history
- //
- if (!EFI_ERROR (Status)) {
- ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column;
- ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row);
- }
-
- return Status;
-}
-
-/**
- Makes the cursor visible or invisible
-
- @param[in] This Protocol instance pointer.
- @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
- set to be invisible.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_DEVICE_ERROR The device had an error and could not complete the
- request, or the device does not support changing
- the cursor mode.
- @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
-**/
-EFI_STATUS
-EFIAPI
-ConsoleLoggerEnableCursor (
- IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
- IN BOOLEAN Visible
- )
-{
- EFI_STATUS Status;
-
- CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
-
- ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This);
- //
- // Forward the request to the original ConOut
- //
- Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible);
-
- //
- // Record console output history
- //
- if (!EFI_ERROR (Status)) {
- ConsoleInfo->HistoryMode.CursorVisible = Visible;
- }
-
- return Status;
-}
-
-/**
- Function to update and verify that the current buffers are correct.
-
- @param[in] ConsoleInfo The pointer to the instance of the console logger information.
-
- This will be used when a mode has changed or a reset occurred to verify all
- history buffers.
-**/
-EFI_STATUS
-ConsoleLoggerResetBuffers (
- IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
- )
-{
- EFI_STATUS Status;
-
- if (ConsoleInfo->Buffer != NULL) {
- FreePool (ConsoleInfo->Buffer);
- ConsoleInfo->Buffer = NULL;
- ConsoleInfo->BufferSize = 0;
- }
-
- if (ConsoleInfo->Attributes != NULL) {
- FreePool (ConsoleInfo->Attributes);
- ConsoleInfo->Attributes = NULL;
- ConsoleInfo->AttribSize = 0;
- }
-
- Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen);
- if (EFI_ERROR (Status)) {
- return (Status);
- }
-
- ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof (ConsoleInfo->Buffer[0]);
- ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof (ConsoleInfo->Attributes[0]);
-
- ConsoleInfo->Buffer = (CHAR16 *)AllocateZeroPool (ConsoleInfo->BufferSize);
-
- if (ConsoleInfo->Buffer == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- ConsoleInfo->Attributes = (INT32 *)AllocateZeroPool (ConsoleInfo->AttribSize);
- if (ConsoleInfo->Attributes == NULL) {
- FreePool (ConsoleInfo->Buffer);
- ConsoleInfo->Buffer = NULL;
- return (EFI_OUT_OF_RESOURCES);
- }
-
- CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE));
-
- return (EFI_SUCCESS);
-}
+/** @file + Provides interface to shell console logger. + + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR> + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + (C) Copyright 2016 Hewlett-Packard Development Company, L.P.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Shell.h" + +/** + Install our intermediate ConOut into the system table to + keep a log of all the info that is displayed to the user. + + @param[in] ScreensToSave Sets how many screen-worths of data to save. + @param[out] ConsoleInfo The object to pass into later functions. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. + + @sa ConsoleLoggerResetBuffers + @sa InstallProtocolInterface +**/ +EFI_STATUS +ConsoleLoggerInstall ( + IN CONST UINTN ScreensToSave, + OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo + ) +{ + EFI_STATUS Status; + + ASSERT (ConsoleInfo != NULL); + + (*ConsoleInfo) = AllocateZeroPool (sizeof (CONSOLE_LOGGER_PRIVATE_DATA)); + if ((*ConsoleInfo) == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE; + (*ConsoleInfo)->OldConOut = gST->ConOut; + (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle; + (*ConsoleInfo)->Buffer = NULL; + (*ConsoleInfo)->BufferSize = 0; + (*ConsoleInfo)->OriginalStartRow = 0; + (*ConsoleInfo)->CurrentStartRow = 0; + (*ConsoleInfo)->RowsPerScreen = 0; + (*ConsoleInfo)->ColsPerScreen = 0; + (*ConsoleInfo)->Attributes = NULL; + (*ConsoleInfo)->AttribSize = 0; + (*ConsoleInfo)->ScreenCount = ScreensToSave; + (*ConsoleInfo)->HistoryMode.MaxMode = 1; + (*ConsoleInfo)->HistoryMode.Mode = 0; + (*ConsoleInfo)->HistoryMode.Attribute = 0; + (*ConsoleInfo)->HistoryMode.CursorColumn = 0; + (*ConsoleInfo)->HistoryMode.CursorRow = 0; + (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE; + (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset; + (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString; + (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString; + (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode; + (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode; + (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute; + (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen; + (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition; + (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor; + (*ConsoleInfo)->OurConOut.Mode = gST->ConOut->Mode; + (*ConsoleInfo)->Enabled = TRUE; + + Status = ConsoleLoggerResetBuffers (*ConsoleInfo); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL ((*ConsoleInfo)); + *ConsoleInfo = NULL; + return (Status); + } + + Status = gBS->InstallProtocolInterface (&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID *)&((*ConsoleInfo)->OurConOut)); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL ((*ConsoleInfo)->Buffer); + SHELL_FREE_NON_NULL ((*ConsoleInfo)->Attributes); + SHELL_FREE_NON_NULL ((*ConsoleInfo)); + *ConsoleInfo = NULL; + return (Status); + } + + gST->ConsoleOutHandle = gImageHandle; + gST->ConOut = &(*ConsoleInfo)->OurConOut; + + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + return (Status); +} + +/** + Return the system to the state it was before InstallConsoleLogger + was installed. + + @param[in] ConsoleInfo The object from the install function. + + @retval EFI_SUCCESS The operation was successful + @return other The operation failed. This was from UninstallProtocolInterface. +**/ +EFI_STATUS +ConsoleLoggerUninstall ( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT (ConsoleInfo != NULL); + ASSERT (ConsoleInfo->OldConOut != NULL); + + if (ConsoleInfo->Buffer != NULL) { + FreePool (ConsoleInfo->Buffer); + DEBUG_CODE ( + ConsoleInfo->Buffer = NULL; + ); + DEBUG_CODE ( + ConsoleInfo->BufferSize = 0; + ); + } + + if (ConsoleInfo->Attributes != NULL) { + FreePool (ConsoleInfo->Attributes); + DEBUG_CODE ( + ConsoleInfo->Attributes = NULL; + ); + DEBUG_CODE ( + ConsoleInfo->AttribSize = 0; + ); + } + + gST->ConsoleOutHandle = ConsoleInfo->OldConHandle; + gST->ConOut = ConsoleInfo->OldConOut; + + // + // Update the CRC32 in the EFI System Table header + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gST->Hdr, + gST->Hdr.HeaderSize, + &gST->Hdr.CRC32 + ); + + return (gBS->UninstallProtocolInterface (gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID *)&ConsoleInfo->OurConOut)); +} + +/** + Displays previously logged output back to the screen. + + This will scroll the screen forwards and backwards through the log of previous + output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows + is (UINTN)(-1) then the size of the screen will be scrolled. + + @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer). + If FALSE then the log will be displayed backwards (scroll to older). + @param[in] Rows Determines how many rows the log should scroll. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +ConsoleLoggerDisplayHistory ( + IN CONST BOOLEAN Forward, + IN CONST UINTN Rows, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + UINTN RowChange; + + ASSERT (ConsoleInfo != NULL); + + // + // Calculate the row number change + // + switch (Rows) { + case ((UINTN)(-1)): + RowChange = ConsoleInfo->RowsPerScreen; + break; + case (0): + RowChange = ConsoleInfo->RowsPerScreen / 2; + break; + default: + RowChange = Rows; + break; + } + + // + // Do the math for direction + // + if (Forward) { + if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) { + RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow; + } + } else { + if (ConsoleInfo->CurrentStartRow < RowChange) { + RowChange = ConsoleInfo->CurrentStartRow; + } + } + + // + // If we are already at one end or the other + // + if (RowChange == 0) { + return (EFI_SUCCESS); + } + + // + // Clear the screen + // + ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut); + + // + // Set the new start row + // + if (Forward) { + ConsoleInfo->CurrentStartRow += RowChange; + } else { + ConsoleInfo->CurrentStartRow -= RowChange; + } + + // + // Change the screen + // + return (UpdateDisplayFromHistory (ConsoleInfo)); +} + +/** + Function to return to normal output whent he scrolling is complete. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. See UpdateDisplayFromHistory. + + @sa UpdateDisplayFromHistory +**/ +EFI_STATUS +ConsoleLoggerStopHistory ( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT (ConsoleInfo != NULL); + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + return (EFI_SUCCESS); + } + + // + // Clear the screen + // + ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut); + + ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow; + return (UpdateDisplayFromHistory (ConsoleInfo)); +} + +/** + Updates the hidden ConOut to be displaying the correct stuff. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. +**/ +EFI_STATUS +UpdateDisplayFromHistory ( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + EFI_STATUS RetVal; + CHAR16 *Screen; + INT32 *Attributes; + UINTN CurrentRow; + CHAR16 TempCharHolder; + UINTN Column; + INT32 CurrentAttrib; + UINTN CurrentColumn; + CHAR16 *StringSegment; + CHAR16 *StringSegmentEnd; + CHAR16 StringSegmentEndChar; + INT32 OrigAttribute; + + ASSERT (ConsoleInfo != NULL); + TempCharHolder = CHAR_NULL; + RetVal = EFI_SUCCESS; + OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute; + + // + // Disable cursor visibility and move it to the top left corner + // + ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE); + ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0); + + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( CurrentRow = 0 + ; CurrentRow < ConsoleInfo->RowsPerScreen + ; CurrentRow++, + Screen += (ConsoleInfo->ColsPerScreen + 2), + Attributes += ConsoleInfo->ColsPerScreen + ) + { + // + // dont use the last char - prevents screen scroll + // + if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)) { + TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1]; + Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL; + } + + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++ + ) + { + if (Screen[Column] != CHAR_NULL) { + CurrentAttrib = Attributes[Column]; + CurrentColumn = Column; + StringSegment = &Screen[Column]; + + // + // Find the first char with a different attribute and make that temporarily NULL + // so we can do fewer printout statements. (later) restore that one and we will + // start at that column on the next loop. + // + StringSegmentEndChar = CHAR_NULL; + for ( StringSegmentEnd = StringSegment + ; *StringSegmentEnd != CHAR_NULL + ; StringSegmentEnd++, + Column++ + ) + { + if (Attributes[Column] != CurrentAttrib) { + StringSegmentEndChar = *StringSegmentEnd; + *StringSegmentEnd = CHAR_NULL; + break; + } + } // StringSegmentEnd loop + + // + // Now write out as much as had the same Attributes + // + + ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, CurrentAttrib); + ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, CurrentColumn, CurrentRow); + Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, StringSegment); + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + RetVal = Status; + } + + // + // If we found a change in attribute put the character back and decrement the column + // so when it increments it will point at that character and we will start printing + // a segment with that new attribute + // + if (StringSegmentEndChar != CHAR_NULL) { + *StringSegmentEnd = StringSegmentEndChar; + StringSegmentEndChar = CHAR_NULL; + Column--; + } + } + } // column for loop + + // + // If we removed the last char and this was the last row put it back + // + if (TempCharHolder != CHAR_NULL) { + Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder; + TempCharHolder = CHAR_NULL; + } + } // row for loop + + // + // If we are setting the screen back to original turn on the cursor and make it visible + // and set the attributes back to what they were + // + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + ConsoleInfo->OldConOut->SetAttribute ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.Attribute + ); + ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorColumn, + ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow + ); + + Status = ConsoleInfo->OldConOut->EnableCursor ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorVisible + ); + if (EFI_ERROR (Status)) { + RetVal = Status; + } + } else { + ConsoleInfo->OldConOut->SetAttribute ( + ConsoleInfo->OldConOut, + OrigAttribute + ); + } + + return (RetVal); +} + +/** + Reset the text output device hardware and optionally run diagnostics + + @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + @param ExtendedVerification Indicates that a more extensive test may be performed + + @retval EFI_SUCCESS The text output device was reset. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleLoggerResetBuffers (ConsoleInfo); + if (ExtendedVerification) { + ConsoleInfo->OriginalStartRow = 0; + ConsoleInfo->CurrentStartRow = 0; + } + } + + return Status; +} + +/** + Appends a string to the history buffer. If the buffer is full then the oldest + information in the buffer will be dropped. Information is added in a line by + line manner such that an empty line takes up just as much space as a full line. + + @param[in] String String pointer to add. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +AppendStringToHistory ( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + UINTN CopySize; + UINTN PrintIndex; + UINTN Index; + + ASSERT (ConsoleInfo != NULL); + + for ( Walker = String + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ) + { + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->HistoryMode.CursorColumn > 0) { + ConsoleInfo->HistoryMode.CursorColumn--; + } + + break; + case (CHAR_LINEFEED): + if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) { + // + // Should never be bigger + // + ASSERT (ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)); + + // + // scroll history attributes 'up' 1 row and set the last row to default attribute + // + CopySize = ConsoleInfo->ColsPerScreen + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof (ConsoleInfo->Attributes[0]); + ASSERT (CopySize < ConsoleInfo->AttribSize); + CopyMem ( + ConsoleInfo->Attributes, + ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen, + CopySize + ); + + for ( Index = 0 + ; Index < ConsoleInfo->ColsPerScreen + ; Index++ + ) + { + *(ConsoleInfo->Attributes + (CopySize/sizeof (ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute; + } + + // + // scroll history buffer 'up' 1 row and set the last row to spaces (L' ') + // + CopySize = (ConsoleInfo->ColsPerScreen + 2) + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof (ConsoleInfo->Buffer[0]); + ASSERT (CopySize < ConsoleInfo->BufferSize); + CopyMem ( + ConsoleInfo->Buffer, + ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2), + CopySize + ); + + // + // Set that last row of chars to spaces + // + SetMem16 (((UINT8 *)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof (CHAR16), L' '); + } else { + // + // we are not on the last row + // + + // + // We should not be scrolling history + // + ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow); + // + // are we at the end of a row? + // + if (ConsoleInfo->HistoryMode.CursorRow == (INT32)(ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) { + ConsoleInfo->OriginalStartRow++; + ConsoleInfo->CurrentStartRow++; + } + + ConsoleInfo->HistoryMode.CursorRow++; + } + + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->HistoryMode.CursorColumn = 0; + break; + default: + // + // Acrtually print characters into the history buffer + // + + PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn; + + for ( // no initializer needed + ; ConsoleInfo->HistoryMode.CursorColumn < (INT32)ConsoleInfo->ColsPerScreen + ; ConsoleInfo->HistoryMode.CursorColumn++, + PrintIndex++, + Walker++ + ) + { + if ( (*Walker == CHAR_NULL) + || (*Walker == CHAR_BACKSPACE) + || (*Walker == CHAR_LINEFEED) + || (*Walker == CHAR_CARRIAGE_RETURN) + ) + { + Walker--; + break; + } + + // + // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row. + // + + ASSERT (PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize); + ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker; + ASSERT (PrintIndex < ConsoleInfo->AttribSize); + ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute; + } // for loop + + // + // Add the carriage return and line feed at the end of the lines + // + if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) { + AppendStringToHistory (L"\r\n", ConsoleInfo); + Walker--; + } + + break; + } // switch for character + } // for loop + + return (EFI_SUCCESS); +} + +/** + Worker function to handle printing the output to the screen + and the history buffer + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +ConsoleLoggerOutputStringSplit ( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16 *)String); + + if (EFI_ERROR (Status)) { + return (Status); + } + + return (AppendStringToHistory (String, ConsoleInfo)); +} + +/** + Function to handle page break mode. + + This function will prompt for continue or break. + + @retval EFI_SUCCESS Continue was choosen + @return other Break was choosen +**/ +EFI_STATUS +ConsoleLoggerDoPageBreak ( + VOID + ) +{ + SHELL_PROMPT_RESPONSE *Resp; + EFI_STATUS Status; + + Resp = NULL; + ASSERT (ShellInfoObject.PageBreakEnabled); + ShellInfoObject.PageBreakEnabled = FALSE; + Status = ShellPromptForResponseHii (ShellPromptResponseTypeQuitContinue, STRING_TOKEN (STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID **)&Resp); + ShellInfoObject.PageBreakEnabled = TRUE; + ASSERT (Resp != NULL); + if (Resp == NULL) { + return (EFI_NOT_FOUND); + } + + if (EFI_ERROR (Status)) { + if (Resp != NULL) { + FreePool (Resp); + } + + return (Status); + } + + if (*Resp == ShellPromptResponseContinue) { + FreePool (Resp); + ShellInfoObject.ConsoleInfo->RowCounter = 0; + // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0; + // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + + return (EFI_SUCCESS); + } else if (*Resp == ShellPromptResponseQuit) { + FreePool (Resp); + ShellInfoObject.ConsoleInfo->Enabled = FALSE; + // + // When user wants to quit, the shell should stop running the command. + // + gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); + return (EFI_DEVICE_ERROR); + } else { + ASSERT (FALSE); + } + + return (EFI_SUCCESS); +} + +/** + Worker function to handle printing the output with page breaks. + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +ConsoleLoggerPrintWithPageBreak ( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + CONST CHAR16 *LineStart; + CHAR16 *StringCopy; + CHAR16 TempChar; + + StringCopy = NULL; + StringCopy = StrnCatGrow (&StringCopy, NULL, String, 0); + if (StringCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for ( Walker = StringCopy, + LineStart = StringCopy + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ) + { + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) { + ConsoleInfo->OurConOut.Mode->CursorColumn--; + } + + break; + case (CHAR_LINEFEED): + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16 *)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to its original character + // + *((CHAR16 *)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker + 1; + + // + // increment row count + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + break; + default: + // + // increment column count + // + ConsoleInfo->OurConOut.Mode->CursorColumn++; + // + // check if that is the last column + // + if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) { + // + // output a line similar to the linefeed character. + // + + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16 *)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to its original character + // + *((CHAR16 *)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker + 1; + + // + // increment row count and zero the column + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + } // last column on line + + break; + } // switch for character + + // + // check if that was the last printable row. If yes handle PageBreak mode + // + if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) { + if (EFI_ERROR (ConsoleLoggerDoPageBreak ())) { + // + // We got an error which means 'break' and halt the printing + // + SHELL_FREE_NON_NULL (StringCopy); + return (EFI_DEVICE_ERROR); + } + } + } // for loop + + if ((LineStart != NULL) && (*LineStart != CHAR_NULL)) { + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + } + + SHELL_FREE_NON_NULL (StringCopy); + return (EFI_SUCCESS); +} + +/** + Write a Unicode string to the output device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx; + EFI_KEY_DATA KeyData; + UINTN EventIndex; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + + ASSERT (ShellInfoObject.ConsoleInfo == ConsoleInfo); + + Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx); + if (!EFI_ERROR (Status)) { + while (ShellInfoObject.HaltOutput) { + ShellInfoObject.HaltOutput = FALSE; + // + // just get some key + // + Status = gBS->WaitForEvent (1, &TxtInEx->WaitForKeyEx, &EventIndex); + ASSERT_EFI_ERROR (Status); + Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData); + if (EFI_ERROR (Status)) { + break; + } + + if ((KeyData.Key.UnicodeChar == L's') && (KeyData.Key.ScanCode == SCAN_NULL) && + ((KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED)) || + (KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_RIGHT_CONTROL_PRESSED)) + ) + ) + { + ShellInfoObject.HaltOutput = TRUE; + } + } + } + + if (!ShellInfoObject.ConsoleInfo->Enabled) { + return (EFI_DEVICE_ERROR); + } else if (ShellInfoObject.PageBreakEnabled) { + return (ConsoleLoggerPrintWithPageBreak (WString, ConsoleInfo)); + } else { + return (ConsoleLoggerOutputStringSplit (WString, ConsoleInfo)); + } +} + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be examined for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString)); +} + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to return information on. + @param[out] Columns Upon return, the number of columns in the selected geometry + @param[out] Rows Upon return, the number of rows in the selected geometry + + @retval EFI_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not + complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->QueryMode ( + ConsoleInfo->OldConOut, + ModeNumber, + Columns, + Rows + )); +} + +/** + Sets the output device(s) to a specified mode. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to set. + + + @retval EFI_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->OurConOut.Mode = ConsoleInfo->OldConOut->Mode; + ConsoleLoggerResetBuffers (ConsoleInfo); + ConsoleInfo->OriginalStartRow = 0; + ConsoleInfo->CurrentStartRow = 0; + ConsoleInfo->OurConOut.ClearScreen (&ConsoleInfo->OurConOut); + } + + return Status; +} + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param[in] This Protocol instance pointer. + @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.Attribute = (INT32)Attribute; + } + + return Status; +} + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + EFI_STATUS Status; + CHAR16 *Screen; + INT32 *Attributes; + UINTN Row; + UINTN Column; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( Row = ConsoleInfo->OriginalStartRow + ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) + ; Row++ + ) + { + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++, + Screen++, + Attributes++ + ) + { + *Screen = L' '; + *Attributes = ConsoleInfo->OldConOut->Mode->Attribute; + } + + // + // Skip the NULL on each column end in text buffer only + // + Screen += 2; + } + + ConsoleInfo->HistoryMode.CursorColumn = 0; + ConsoleInfo->HistoryMode.CursorRow = 0; + } + + return Status; +} + +/** + Sets the current coordinates of the cursor position + + @param[in] This Protocol instance pointer. + @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode + @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + EFI_STATUS Status; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + Column, + Row + ); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column; + ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row); + } + + return Status; +} + +/** + Makes the cursor visible or invisible + + @param[in] This Protocol instance pointer. + @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS (This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorVisible = Visible; + } + + return Status; +} + +/** + Function to update and verify that the current buffers are correct. + + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + This will be used when a mode has changed or a reset occurred to verify all + history buffers. +**/ +EFI_STATUS +ConsoleLoggerResetBuffers ( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + if (ConsoleInfo->Buffer != NULL) { + FreePool (ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + ConsoleInfo->BufferSize = 0; + } + + if (ConsoleInfo->Attributes != NULL) { + FreePool (ConsoleInfo->Attributes); + ConsoleInfo->Attributes = NULL; + ConsoleInfo->AttribSize = 0; + } + + Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen); + if (EFI_ERROR (Status)) { + return (Status); + } + + ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof (ConsoleInfo->Buffer[0]); + ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof (ConsoleInfo->Attributes[0]); + + ConsoleInfo->Buffer = (CHAR16 *)AllocateZeroPool (ConsoleInfo->BufferSize); + + if (ConsoleInfo->Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + ConsoleInfo->Attributes = (INT32 *)AllocateZeroPool (ConsoleInfo->AttribSize); + if (ConsoleInfo->Attributes == NULL) { + FreePool (ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + return (EFI_OUT_OF_RESOURCES); + } + + CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE)); + + return (EFI_SUCCESS); +} |
