summaryrefslogtreecommitdiff
path: root/Core/ShellPkg/Application/Shell/ConsoleLogger.c
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-22 17:06:43 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:14:49 +0800
commit4e4db0c4b54ee5d5377fca0e4c2330286b1b0b41 (patch)
tree751790d383df04329bb700e8fe800c3d459eeaae /Core/ShellPkg/Application/Shell/ConsoleLogger.c
parent1922f267f671b43de0ea43138ccb5806657056b4 (diff)
downloadedk2-platforms-4e4db0c4b54ee5d5377fca0e4c2330286b1b0b41.tar.xz
ShellPkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/ShellPkg/Application/Shell/ConsoleLogger.c')
-rw-r--r--Core/ShellPkg/Application/Shell/ConsoleLogger.c1233
1 files changed, 1233 insertions, 0 deletions
diff --git a/Core/ShellPkg/Application/Shell/ConsoleLogger.c b/Core/ShellPkg/Application/Shell/ConsoleLogger.c
new file mode 100644
index 0000000000..9b64303cf0
--- /dev/null
+++ b/Core/ShellPkg/Application/Shell/ConsoleLogger.c
@@ -0,0 +1,1233 @@
+/** @file
+ Provides interface to shell console logger.
+
+ (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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
+EFIAPI
+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;
+
+ 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
+EFIAPI
+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;
+
+ 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
+EFIAPI
+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
+EFIAPI
+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
+EFIAPI
+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 arrribute and make that temporarily NULL
+ // so we can do fewer printout statements. (later) restore that one and we will
+ // start at that collumn 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 optionaly 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
+EFIAPI
+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
+EFIAPI
+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
+EFIAPI
+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
+EFIAPI
+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 it's 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 it's 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 ocurred to verify all
+ history buffers.
+**/
+EFI_STATUS
+EFIAPI
+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);
+}