Home | History | Annotate | Download | only in Shell
      1 /** @file
      2   Provides interface to shell console logger.
      3 
      4   (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      6   (C) Copyright 2016 Hewlett-Packard Development Company, L.P.<BR>
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 **/
     15 
     16 #include "Shell.h"
     17 
     18 /**
     19   Install our intermediate ConOut into the system table to
     20   keep a log of all the info that is displayed to the user.
     21 
     22   @param[in] ScreensToSave  Sets how many screen-worths of data to save.
     23   @param[out] ConsoleInfo   The object to pass into later functions.
     24 
     25   @retval EFI_SUCCESS       The operation was successful.
     26   @return other             The operation failed.
     27 
     28   @sa ConsoleLoggerResetBuffers
     29   @sa InstallProtocolInterface
     30 **/
     31 EFI_STATUS
     32 ConsoleLoggerInstall(
     33   IN CONST UINTN ScreensToSave,
     34   OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo
     35   )
     36 {
     37   EFI_STATUS Status;
     38   ASSERT(ConsoleInfo != NULL);
     39 
     40   (*ConsoleInfo) = AllocateZeroPool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA));
     41   if ((*ConsoleInfo) == NULL) {
     42     return (EFI_OUT_OF_RESOURCES);
     43   }
     44 
     45   (*ConsoleInfo)->Signature                   = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE;
     46   (*ConsoleInfo)->OldConOut                   = gST->ConOut;
     47   (*ConsoleInfo)->OldConHandle                = gST->ConsoleOutHandle;
     48   (*ConsoleInfo)->Buffer                      = NULL;
     49   (*ConsoleInfo)->BufferSize                  = 0;
     50   (*ConsoleInfo)->OriginalStartRow            = 0;
     51   (*ConsoleInfo)->CurrentStartRow             = 0;
     52   (*ConsoleInfo)->RowsPerScreen               = 0;
     53   (*ConsoleInfo)->ColsPerScreen               = 0;
     54   (*ConsoleInfo)->Attributes                  = NULL;
     55   (*ConsoleInfo)->AttribSize                  = 0;
     56   (*ConsoleInfo)->ScreenCount                 = ScreensToSave;
     57   (*ConsoleInfo)->HistoryMode.MaxMode         = 1;
     58   (*ConsoleInfo)->HistoryMode.Mode            = 0;
     59   (*ConsoleInfo)->HistoryMode.Attribute       = 0;
     60   (*ConsoleInfo)->HistoryMode.CursorColumn    = 0;
     61   (*ConsoleInfo)->HistoryMode.CursorRow       = 0;
     62   (*ConsoleInfo)->HistoryMode.CursorVisible   = FALSE;
     63   (*ConsoleInfo)->OurConOut.Reset             = ConsoleLoggerReset;
     64   (*ConsoleInfo)->OurConOut.OutputString      = ConsoleLoggerOutputString;
     65   (*ConsoleInfo)->OurConOut.TestString        = ConsoleLoggerTestString;
     66   (*ConsoleInfo)->OurConOut.QueryMode         = ConsoleLoggerQueryMode;
     67   (*ConsoleInfo)->OurConOut.SetMode           = ConsoleLoggerSetMode;
     68   (*ConsoleInfo)->OurConOut.SetAttribute      = ConsoleLoggerSetAttribute;
     69   (*ConsoleInfo)->OurConOut.ClearScreen       = ConsoleLoggerClearScreen;
     70   (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition;
     71   (*ConsoleInfo)->OurConOut.EnableCursor      = ConsoleLoggerEnableCursor;
     72   (*ConsoleInfo)->OurConOut.Mode              = gST->ConOut->Mode;
     73   (*ConsoleInfo)->Enabled                     = TRUE;
     74 
     75   Status = ConsoleLoggerResetBuffers(*ConsoleInfo);
     76   if (EFI_ERROR(Status)) {
     77     SHELL_FREE_NON_NULL((*ConsoleInfo));
     78     *ConsoleInfo = NULL;
     79     return (Status);
     80   }
     81 
     82   Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut));
     83   if (EFI_ERROR(Status)) {
     84     SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer);
     85     SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes);
     86     SHELL_FREE_NON_NULL((*ConsoleInfo));
     87     *ConsoleInfo = NULL;
     88     return (Status);
     89   }
     90 
     91   gST->ConsoleOutHandle = gImageHandle;
     92   gST->ConOut           = &(*ConsoleInfo)->OurConOut;
     93 
     94   //
     95   // Update the CRC32 in the EFI System Table header
     96   //
     97   gST->Hdr.CRC32 = 0;
     98   gBS->CalculateCrc32 (
     99         (UINT8 *)&gST->Hdr,
    100         gST->Hdr.HeaderSize,
    101         &gST->Hdr.CRC32
    102         );
    103   return (Status);
    104 }
    105 
    106 /**
    107   Return the system to the state it was before InstallConsoleLogger
    108   was installed.
    109 
    110   @param[in] ConsoleInfo  The object from the install function.
    111 
    112   @retval EFI_SUCCESS     The operation was successful
    113   @return other           The operation failed.  This was from UninstallProtocolInterface.
    114 **/
    115 EFI_STATUS
    116 ConsoleLoggerUninstall(
    117   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    118   )
    119 {
    120   ASSERT(ConsoleInfo != NULL);
    121   ASSERT(ConsoleInfo->OldConOut != NULL);
    122 
    123   if (ConsoleInfo->Buffer != NULL) {
    124     FreePool(ConsoleInfo->Buffer);
    125     DEBUG_CODE(ConsoleInfo->Buffer     = NULL;);
    126     DEBUG_CODE(ConsoleInfo->BufferSize = 0;);
    127   }
    128   if (ConsoleInfo->Attributes != NULL) {
    129     FreePool(ConsoleInfo->Attributes);
    130     DEBUG_CODE(ConsoleInfo->Attributes = NULL;);
    131     DEBUG_CODE(ConsoleInfo->AttribSize = 0;);
    132   }
    133 
    134   gST->ConsoleOutHandle = ConsoleInfo->OldConHandle;
    135   gST->ConOut = ConsoleInfo->OldConOut;
    136 
    137   //
    138   // Update the CRC32 in the EFI System Table header
    139   //
    140   gST->Hdr.CRC32 = 0;
    141   gBS->CalculateCrc32 (
    142         (UINT8 *)&gST->Hdr,
    143         gST->Hdr.HeaderSize,
    144         &gST->Hdr.CRC32
    145         );
    146 
    147   return (gBS->UninstallProtocolInterface(gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID*)&ConsoleInfo->OurConOut));
    148 }
    149 
    150 /**
    151   Displays previously logged output back to the screen.
    152 
    153   This will scroll the screen forwards and backwards through the log of previous
    154   output.  If Rows is 0 then the size of 1/2 the screen will be scrolled.  If Rows
    155   is (UINTN)(-1) then the size of the screen will be scrolled.
    156 
    157   @param[in] Forward      If TRUE then the log will be displayed forwards (scroll to newer).
    158                           If FALSE then the log will be displayed backwards (scroll to older).
    159   @param[in] Rows         Determines how many rows the log should scroll.
    160   @param[in] ConsoleInfo  The pointer to the instance of the console logger information.
    161 **/
    162 EFI_STATUS
    163 ConsoleLoggerDisplayHistory(
    164   IN CONST BOOLEAN  Forward,
    165   IN CONST UINTN    Rows,
    166   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    167   )
    168 {
    169   UINTN   RowChange;
    170 
    171   ASSERT(ConsoleInfo != NULL);
    172 
    173   //
    174   // Calculate the row number change
    175   //
    176   switch (Rows) {
    177   case ((UINTN)(-1)):
    178     RowChange = ConsoleInfo->RowsPerScreen;
    179     break;
    180   case (0):
    181     RowChange = ConsoleInfo->RowsPerScreen / 2;
    182     break;
    183   default:
    184     RowChange = Rows;
    185     break;
    186   }
    187 
    188   //
    189   // Do the math for direction
    190   //
    191   if (Forward) {
    192     if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) {
    193       RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow;
    194     }
    195   } else {
    196     if (ConsoleInfo->CurrentStartRow < RowChange) {
    197       RowChange = ConsoleInfo->CurrentStartRow;
    198     }
    199   }
    200 
    201   //
    202   // If we are already at one end or the other
    203   //
    204   if (RowChange == 0) {
    205     return (EFI_SUCCESS);
    206   }
    207 
    208   //
    209   // Clear the screen
    210   //
    211   ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut);
    212 
    213   //
    214   // Set the new start row
    215   //
    216   if (Forward) {
    217     ConsoleInfo->CurrentStartRow += RowChange;
    218   } else {
    219     ConsoleInfo->CurrentStartRow -= RowChange;
    220   }
    221 
    222   //
    223   // Change the screen
    224   //
    225   return (UpdateDisplayFromHistory(ConsoleInfo));
    226 }
    227 
    228 /**
    229   Function to return to normal output whent he scrolling is complete.
    230   @param[in] ConsoleInfo  The pointer to the instance of the console logger information.
    231 
    232   @retval EFI_SUCCESS   The operation was successful.
    233   @return other         The operation failed.  See UpdateDisplayFromHistory.
    234 
    235   @sa UpdateDisplayFromHistory
    236 **/
    237 EFI_STATUS
    238 ConsoleLoggerStopHistory(
    239   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    240   )
    241 {
    242   ASSERT(ConsoleInfo != NULL);
    243   if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
    244     return (EFI_SUCCESS);
    245   }
    246 
    247   //
    248   // Clear the screen
    249   //
    250   ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut);
    251 
    252   ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow;
    253   return (UpdateDisplayFromHistory(ConsoleInfo));
    254 }
    255 
    256 /**
    257   Updates the hidden ConOut to be displaying the correct stuff.
    258   @param[in] ConsoleInfo  The pointer to the instance of the console logger information.
    259 
    260   @retval EFI_SUCCESS     The operation was successful.
    261   @return other           The operation failed.
    262 **/
    263 EFI_STATUS
    264 UpdateDisplayFromHistory(
    265   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    266   )
    267 {
    268   EFI_STATUS      Status;
    269   EFI_STATUS      RetVal;
    270   CHAR16          *Screen;
    271   INT32           *Attributes;
    272   UINTN           CurrentRow;
    273   CHAR16          TempCharHolder;
    274   UINTN           Column;
    275   INT32           CurrentAttrib;
    276   UINTN           CurrentColumn;
    277   CHAR16          *StringSegment;
    278   CHAR16          *StringSegmentEnd;
    279   CHAR16          StringSegmentEndChar;
    280   INT32           OrigAttribute;
    281 
    282   ASSERT(ConsoleInfo != NULL);
    283   TempCharHolder = CHAR_NULL;
    284   RetVal = EFI_SUCCESS;
    285   OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute;
    286 
    287   //
    288   // Disable cursor visibility and move it to the top left corner
    289   //
    290   ConsoleInfo->OldConOut->EnableCursor       (ConsoleInfo->OldConOut, FALSE);
    291   ConsoleInfo->OldConOut->SetCursorPosition  (ConsoleInfo->OldConOut, 0, 0);
    292 
    293   Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
    294   Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
    295   for ( CurrentRow = 0
    296       ; CurrentRow < ConsoleInfo->RowsPerScreen
    297       ; CurrentRow++
    298       , Screen += (ConsoleInfo->ColsPerScreen + 2)
    299       , Attributes += ConsoleInfo->ColsPerScreen
    300      ){
    301     //
    302     // dont use the last char - prevents screen scroll
    303     //
    304     if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)){
    305       TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1];
    306       Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL;
    307     }
    308 
    309     for ( Column = 0
    310         ; Column < ConsoleInfo->ColsPerScreen
    311         ; Column++
    312        ){
    313       if (Screen[Column] != CHAR_NULL) {
    314         CurrentAttrib = Attributes[Column];
    315         CurrentColumn = Column;
    316         StringSegment = &Screen[Column];
    317 
    318         //
    319         // Find the first char with a different arrribute and make that temporarily NULL
    320         // so we can do fewer printout statements.  (later) restore that one and we will
    321         // start at that collumn on the next loop.
    322         //
    323         StringSegmentEndChar = CHAR_NULL;
    324         for ( StringSegmentEnd = StringSegment
    325             ; StringSegmentEnd != CHAR_NULL
    326             ; StringSegmentEnd++
    327             , Column++
    328            ){
    329           if (Attributes[Column] != CurrentAttrib) {
    330             StringSegmentEndChar = *StringSegmentEnd;
    331             *StringSegmentEnd    = CHAR_NULL;
    332             break;
    333           }
    334         } // StringSegmentEnd loop
    335 
    336         //
    337         // Now write out as much as had the same Attributes
    338         //
    339 
    340         ConsoleInfo->OldConOut->SetAttribute(ConsoleInfo->OldConOut, CurrentAttrib);
    341         ConsoleInfo->OldConOut->SetCursorPosition(ConsoleInfo->OldConOut, CurrentColumn, CurrentRow);
    342         Status = ConsoleInfo->OldConOut->OutputString(ConsoleInfo->OldConOut, StringSegment);
    343 
    344         if (EFI_ERROR(Status)) {
    345           ASSERT(FALSE);
    346           RetVal = Status;
    347         }
    348 
    349         //
    350         // If we found a change in attribute put the character back and decrement the column
    351         // so when it increments it will point at that character and we will start printing
    352         // a segment with that new attribute
    353         //
    354         if (StringSegmentEndChar != CHAR_NULL) {
    355           *StringSegmentEnd = StringSegmentEndChar;
    356           StringSegmentEndChar = CHAR_NULL;
    357           Column--;
    358         }
    359       }
    360     } // column for loop
    361 
    362     //
    363     // If we removed the last char and this was the last row put it back
    364     //
    365     if (TempCharHolder != CHAR_NULL) {
    366       Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder;
    367       TempCharHolder = CHAR_NULL;
    368     }
    369   } // row for loop
    370 
    371   //
    372   // If we are setting the screen back to original turn on the cursor and make it visible
    373   // and set the attributes back to what they were
    374   //
    375   if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
    376     ConsoleInfo->OldConOut->SetAttribute (
    377                                 ConsoleInfo->OldConOut,
    378                                 ConsoleInfo->HistoryMode.Attribute
    379                                );
    380     ConsoleInfo->OldConOut->SetCursorPosition (
    381                                 ConsoleInfo->OldConOut,
    382                                 ConsoleInfo->HistoryMode.CursorColumn,
    383                                 ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow
    384                                );
    385 
    386     Status = ConsoleInfo->OldConOut->EnableCursor (
    387                                 ConsoleInfo->OldConOut,
    388                                 ConsoleInfo->HistoryMode.CursorVisible
    389                                );
    390     if (EFI_ERROR (Status)) {
    391       RetVal = Status;
    392     }
    393   } else {
    394     ConsoleInfo->OldConOut->SetAttribute (
    395                                 ConsoleInfo->OldConOut,
    396                                 OrigAttribute
    397                                );
    398   }
    399 
    400   return (RetVal);
    401 }
    402 
    403 /**
    404   Reset the text output device hardware and optionaly run diagnostics
    405 
    406   @param  This                pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    407   @param ExtendedVerification Indicates that a more extensive test may be performed
    408 
    409   @retval EFI_SUCCESS         The text output device was reset.
    410   @retval EFI_DEVICE_ERROR    The text output device is not functioning correctly and
    411                               could not be reset.
    412 **/
    413 EFI_STATUS
    414 EFIAPI
    415 ConsoleLoggerReset (
    416   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
    417   IN  BOOLEAN                         ExtendedVerification
    418   )
    419 {
    420   EFI_STATUS                  Status;
    421   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
    422   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
    423 
    424   //
    425   // Forward the request to the original ConOut
    426   //
    427   Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification);
    428 
    429   //
    430   // Check that the buffers are still correct for logging
    431   //
    432   if (!EFI_ERROR (Status)) {
    433     ConsoleLoggerResetBuffers(ConsoleInfo);
    434     if (ExtendedVerification) {
    435       ConsoleInfo->OriginalStartRow = 0;
    436       ConsoleInfo->CurrentStartRow = 0;
    437     }
    438   }
    439 
    440   return Status;
    441 }
    442 
    443 /**
    444   Appends a string to the history buffer.  If the buffer is full then the oldest
    445   information in the buffer will be dropped.  Information is added in a line by
    446   line manner such that an empty line takes up just as much space as a full line.
    447 
    448   @param[in] String       String pointer to add.
    449   @param[in] ConsoleInfo  The pointer to the instance of the console logger information.
    450 **/
    451 EFI_STATUS
    452 AppendStringToHistory(
    453   IN CONST CHAR16 *String,
    454   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    455   )
    456 {
    457   CONST CHAR16  *Walker;
    458   UINTN         CopySize;
    459   UINTN         PrintIndex;
    460   UINTN         Index;
    461 
    462   ASSERT(ConsoleInfo != NULL);
    463 
    464   for ( Walker = String
    465       ; Walker != NULL && *Walker != CHAR_NULL
    466       ; Walker++
    467      ){
    468     switch (*Walker) {
    469     case (CHAR_BACKSPACE):
    470       if (ConsoleInfo->HistoryMode.CursorColumn > 0) {
    471         ConsoleInfo->HistoryMode.CursorColumn--;
    472       }
    473       break;
    474     case (CHAR_LINEFEED):
    475       if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) {
    476         //
    477         // Should never be bigger
    478         //
    479         ASSERT(ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1));
    480 
    481         //
    482         // scroll history attributes 'up' 1 row and set the last row to default attribute
    483         //
    484         CopySize = ConsoleInfo->ColsPerScreen
    485                  * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
    486                  * sizeof(ConsoleInfo->Attributes[0]);
    487         ASSERT(CopySize < ConsoleInfo->AttribSize);
    488         CopyMem(
    489           ConsoleInfo->Attributes,
    490           ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen,
    491           CopySize
    492          );
    493 
    494         for ( Index = 0
    495             ; Index < ConsoleInfo->ColsPerScreen
    496             ; Index++
    497            ){
    498           *(ConsoleInfo->Attributes + (CopySize/sizeof(ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute;
    499         }
    500 
    501         //
    502         // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
    503         //
    504         CopySize = (ConsoleInfo->ColsPerScreen + 2)
    505                  * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
    506                  * sizeof(ConsoleInfo->Buffer[0]);
    507         ASSERT(CopySize < ConsoleInfo->BufferSize);
    508         CopyMem(
    509           ConsoleInfo->Buffer,
    510           ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2),
    511           CopySize
    512          );
    513 
    514         //
    515         // Set that last row of chars to spaces
    516         //
    517         SetMem16(((UINT8*)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof(CHAR16), L' ');
    518       } else {
    519         //
    520         // we are not on the last row
    521         //
    522 
    523         //
    524         // We should not be scrolling history
    525         //
    526         ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow);
    527         //
    528         // are we at the end of a row?
    529         //
    530         if (ConsoleInfo->HistoryMode.CursorRow == (INT32) (ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) {
    531           ConsoleInfo->OriginalStartRow++;
    532           ConsoleInfo->CurrentStartRow++;
    533         }
    534         ConsoleInfo->HistoryMode.CursorRow++;
    535       }
    536       break;
    537     case (CHAR_CARRIAGE_RETURN):
    538       //
    539       // Move the cursor to the beginning of the current row.
    540       //
    541       ConsoleInfo->HistoryMode.CursorColumn = 0;
    542       break;
    543     default:
    544       //
    545       // Acrtually print characters into the history buffer
    546       //
    547 
    548       PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn;
    549 
    550       for ( // no initializer needed
    551           ; ConsoleInfo->HistoryMode.CursorColumn < (INT32) ConsoleInfo->ColsPerScreen
    552           ; ConsoleInfo->HistoryMode.CursorColumn++
    553           , PrintIndex++
    554           , Walker++
    555          ){
    556         if (*Walker == CHAR_NULL
    557           ||*Walker == CHAR_BACKSPACE
    558           ||*Walker == CHAR_LINEFEED
    559           ||*Walker == CHAR_CARRIAGE_RETURN
    560          ){
    561             Walker--;
    562             break;
    563         }
    564         //
    565         // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
    566         //
    567 
    568         ASSERT(PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize);
    569         ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker;
    570         ASSERT(PrintIndex < ConsoleInfo->AttribSize);
    571         ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute;
    572       } // for loop
    573 
    574       //
    575       // Add the carriage return and line feed at the end of the lines
    576       //
    577       if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) {
    578         AppendStringToHistory(L"\r\n", ConsoleInfo);
    579         Walker--;
    580       }
    581 
    582       break;
    583     } // switch for character
    584   } // for loop
    585 
    586   return (EFI_SUCCESS);
    587 }
    588 
    589 /**
    590   Worker function to handle printing the output to the screen
    591   and the history buffer
    592 
    593   @param[in] String               The string to output
    594   @param[in] ConsoleInfo          The pointer to the instance of the console logger information.
    595 
    596   @retval EFI_SUCCESS             The string was printed
    597   @retval EFI_DEVICE_ERROR        The device reported an error while attempting to output
    598                                   the text.
    599   @retval EFI_UNSUPPORTED         The output device's mode is not currently in a
    600                                   defined text mode.
    601   @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the
    602                                   characters in the Unicode string could not be
    603                                   rendered and were skipped.
    604 **/
    605 EFI_STATUS
    606 ConsoleLoggerOutputStringSplit(
    607   IN CONST CHAR16   *String,
    608   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    609   )
    610 {
    611   EFI_STATUS    Status;
    612 
    613   //
    614   // Forward the request to the original ConOut
    615   //
    616   Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16*)String);
    617 
    618   if (EFI_ERROR(Status)) {
    619     return (Status);
    620   }
    621 
    622   return (AppendStringToHistory(String, ConsoleInfo));
    623 }
    624 
    625 /**
    626   Function to handle page break mode.
    627 
    628   This function will prompt for continue or break.
    629 
    630   @retval EFI_SUCCESS   Continue was choosen
    631   @return other         Break was choosen
    632 **/
    633 EFI_STATUS
    634 ConsoleLoggerDoPageBreak(
    635   VOID
    636   )
    637 {
    638   SHELL_PROMPT_RESPONSE *Resp;
    639   EFI_STATUS            Status;
    640 
    641   Resp = NULL;
    642   ASSERT(ShellInfoObject.PageBreakEnabled);
    643   ShellInfoObject.PageBreakEnabled = FALSE;
    644   Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN(STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID**)&Resp);
    645   ShellInfoObject.PageBreakEnabled = TRUE;
    646   ASSERT(Resp != NULL);
    647   if (Resp == NULL) {
    648     return (EFI_NOT_FOUND);
    649   }
    650   if (EFI_ERROR(Status)) {
    651     if (Resp != NULL) {
    652       FreePool(Resp);
    653     }
    654     return (Status);
    655   }
    656   if (*Resp == ShellPromptResponseContinue) {
    657     FreePool(Resp);
    658     ShellInfoObject.ConsoleInfo->RowCounter                   = 0;
    659 //    ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow    = 0;
    660 //    ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
    661 
    662     return (EFI_SUCCESS);
    663   } else if (*Resp == ShellPromptResponseQuit) {
    664     FreePool(Resp);
    665     ShellInfoObject.ConsoleInfo->Enabled = FALSE;
    666     //
    667     // When user wants to quit, the shell should stop running the command.
    668     //
    669     gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);
    670     return (EFI_DEVICE_ERROR);
    671   } else {
    672     ASSERT(FALSE);
    673   }
    674   return (EFI_SUCCESS);
    675 }
    676 /**
    677   Worker function to handle printing the output with page breaks.
    678 
    679   @param[in] String               The string to output
    680   @param[in] ConsoleInfo          The pointer to the instance of the console logger information.
    681 
    682   @retval EFI_SUCCESS             The string was printed
    683   @retval EFI_DEVICE_ERROR        The device reported an error while attempting to output
    684                                   the text.
    685   @retval EFI_UNSUPPORTED         The output device's mode is not currently in a
    686                                   defined text mode.
    687   @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the
    688                                   characters in the Unicode string could not be
    689                                   rendered and were skipped.
    690 **/
    691 EFI_STATUS
    692 ConsoleLoggerPrintWithPageBreak(
    693   IN CONST CHAR16   *String,
    694   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
    695   )
    696 {
    697   CONST CHAR16  *Walker;
    698   CONST CHAR16  *LineStart;
    699   CHAR16        *StringCopy;
    700   CHAR16        TempChar;
    701 
    702   StringCopy = NULL;
    703   StringCopy = StrnCatGrow(&StringCopy, NULL, String, 0);
    704   if (StringCopy == NULL) {
    705     return (EFI_OUT_OF_RESOURCES);
    706   }
    707 
    708   for ( Walker = StringCopy
    709       , LineStart = StringCopy
    710       ; Walker != NULL && *Walker != CHAR_NULL
    711       ; Walker++
    712      ){
    713     switch (*Walker) {
    714     case (CHAR_BACKSPACE):
    715       if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) {
    716         ConsoleInfo->OurConOut.Mode->CursorColumn--;
    717       }
    718       break;
    719     case (CHAR_LINEFEED):
    720       //
    721       // add a temp NULL terminator
    722       //
    723       TempChar = *(Walker + 1);
    724       *((CHAR16*)(Walker+1)) = CHAR_NULL;
    725 
    726       //
    727       // output the string
    728       //
    729       ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
    730 
    731       //
    732       // restore the temp NULL terminator to it's original character
    733       //
    734       *((CHAR16*)(Walker+1)) = TempChar;
    735 
    736       //
    737       // Update LineStart Variable
    738       //
    739       LineStart = Walker + 1;
    740 
    741       //
    742       // increment row count
    743       //
    744       ShellInfoObject.ConsoleInfo->RowCounter++;
    745       ConsoleInfo->OurConOut.Mode->CursorRow++;
    746 
    747       break;
    748     case (CHAR_CARRIAGE_RETURN):
    749       //
    750       // Move the cursor to the beginning of the current row.
    751       //
    752       ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
    753       break;
    754     default:
    755       //
    756       // increment column count
    757       //
    758       ConsoleInfo->OurConOut.Mode->CursorColumn++;
    759       //
    760       // check if that is the last column
    761       //
    762       if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) {
    763         //
    764         // output a line similar to the linefeed character.
    765         //
    766 
    767         //
    768         // add a temp NULL terminator
    769         //
    770         TempChar = *(Walker + 1);
    771         *((CHAR16*)(Walker+1)) = CHAR_NULL;
    772 
    773         //
    774         // output the string
    775         //
    776         ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
    777 
    778         //
    779         // restore the temp NULL terminator to it's original character
    780         //
    781         *((CHAR16*)(Walker+1)) = TempChar;
    782 
    783         //
    784         // Update LineStart Variable
    785         //
    786         LineStart = Walker + 1;
    787 
    788         //
    789         // increment row count and zero the column
    790         //
    791         ShellInfoObject.ConsoleInfo->RowCounter++;
    792         ConsoleInfo->OurConOut.Mode->CursorRow++;
    793         ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
    794       } // last column on line
    795       break;
    796     } // switch for character
    797 
    798     //
    799     // check if that was the last printable row.  If yes handle PageBreak mode
    800     //
    801     if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) {
    802       if (EFI_ERROR(ConsoleLoggerDoPageBreak())) {
    803         //
    804         // We got an error which means 'break' and halt the printing
    805         //
    806         SHELL_FREE_NON_NULL(StringCopy);
    807         return (EFI_DEVICE_ERROR);
    808       }
    809     }
    810   } // for loop
    811 
    812   if (LineStart != NULL && *LineStart != CHAR_NULL) {
    813     ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
    814   }
    815 
    816   SHELL_FREE_NON_NULL(StringCopy);
    817   return (EFI_SUCCESS);
    818 }
    819 
    820 /**
    821   Write a Unicode string to the output device.
    822 
    823   @param[in] This                 Protocol instance pointer.
    824   @param[in] WString              The NULL-terminated Unicode string to be displayed on the output
    825                                   device(s). All output devices must also support the Unicode
    826                                   drawing defined in this file.
    827   @retval EFI_SUCCESS             The string was output to the device.
    828   @retval EFI_DEVICE_ERROR        The device reported an error while attempting to output
    829                                   the text.
    830   @retval EFI_UNSUPPORTED         The output device's mode is not currently in a
    831                                   defined text mode.
    832   @retval EFI_WARN_UNKNOWN_GLYPH  This warning code indicates that some of the
    833                                   characters in the Unicode string could not be
    834                                   rendered and were skipped.
    835 **/
    836 EFI_STATUS
    837 EFIAPI
    838 ConsoleLoggerOutputString (
    839   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
    840   IN  CHAR16                          *WString
    841   )
    842 {
    843   EFI_STATUS                        Status;
    844   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
    845   EFI_KEY_DATA                      KeyData;
    846   UINTN                             EventIndex;
    847   CONSOLE_LOGGER_PRIVATE_DATA       *ConsoleInfo;
    848 
    849   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
    850   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
    851     return (EFI_UNSUPPORTED);
    852   }
    853   ASSERT(ShellInfoObject.ConsoleInfo == ConsoleInfo);
    854 
    855   Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
    856   if (!EFI_ERROR (Status)) {
    857     while (ShellInfoObject.HaltOutput) {
    858 
    859       ShellInfoObject.HaltOutput = FALSE;
    860       //
    861       // just get some key
    862       //
    863       Status = gBS->WaitForEvent (1, &TxtInEx->WaitForKeyEx, &EventIndex);
    864       ASSERT_EFI_ERROR (Status);
    865       Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData);
    866       if (EFI_ERROR(Status)) {
    867         break;
    868       }
    869 
    870       if ((KeyData.Key.UnicodeChar == L's') && (KeyData.Key.ScanCode == SCAN_NULL) &&
    871           ((KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED)) ||
    872            (KeyData.KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID | EFI_RIGHT_CONTROL_PRESSED))
    873           )
    874          ) {
    875         ShellInfoObject.HaltOutput = TRUE;
    876       }
    877     }
    878   }
    879 
    880   if (!ShellInfoObject.ConsoleInfo->Enabled) {
    881     return (EFI_DEVICE_ERROR);
    882   } else if (ShellInfoObject.PageBreakEnabled) {
    883     return (ConsoleLoggerPrintWithPageBreak(WString, ConsoleInfo));
    884   } else {
    885     return (ConsoleLoggerOutputStringSplit(WString, ConsoleInfo));
    886   }
    887 }
    888 
    889 /**
    890   Verifies that all characters in a Unicode string can be output to the
    891   target device.
    892 
    893   @param[in] This     Protocol instance pointer.
    894   @param[in] WString  The NULL-terminated Unicode string to be examined for the output
    895                       device(s).
    896 
    897   @retval EFI_SUCCESS           The device(s) are capable of rendering the output string.
    898   @retval EFI_UNSUPPORTED       Some of the characters in the Unicode string cannot be
    899                                 rendered by one or more of the output devices mapped
    900                                 by the EFI handle.
    901 
    902 **/
    903 EFI_STATUS
    904 EFIAPI
    905 ConsoleLoggerTestString (
    906   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    907   IN  CHAR16                        *WString
    908   )
    909 {
    910   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
    911   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
    912   //
    913   // Forward the request to the original ConOut
    914   //
    915   return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString));
    916 }
    917 
    918 /**
    919   Returns information for an available text mode that the output device(s)
    920   supports.
    921 
    922   @param[in] This               Protocol instance pointer.
    923   @param[in] ModeNumber         The mode number to return information on.
    924   @param[out] Columns           Upon return, the number of columns in the selected geometry
    925   @param[out] Rows              Upon return, the number of rows in the selected geometry
    926 
    927   @retval EFI_SUCCESS           The requested mode information was returned.
    928   @retval EFI_DEVICE_ERROR      The device had an error and could not
    929                                 complete the request.
    930   @retval EFI_UNSUPPORTED       The mode number was not valid.
    931 **/
    932 EFI_STATUS
    933 EFIAPI
    934 ConsoleLoggerQueryMode (
    935   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    936   IN  UINTN                         ModeNumber,
    937   OUT UINTN                         *Columns,
    938   OUT UINTN                         *Rows
    939   )
    940 {
    941   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
    942   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
    943   //
    944   // Forward the request to the original ConOut
    945   //
    946   return (ConsoleInfo->OldConOut->QueryMode (
    947     ConsoleInfo->OldConOut,
    948     ModeNumber,
    949     Columns,
    950     Rows
    951    ));
    952 }
    953 
    954 /**
    955   Sets the output device(s) to a specified mode.
    956 
    957   @param[in] This               Protocol instance pointer.
    958   @param[in] ModeNumber         The mode number to set.
    959 
    960 
    961   @retval EFI_SUCCESS           The requested text mode was set.
    962   @retval EFI_DEVICE_ERROR      The device had an error and
    963                                 could not complete the request.
    964   @retval EFI_UNSUPPORTED       The mode number was not valid.
    965 **/
    966 EFI_STATUS
    967 EFIAPI
    968 ConsoleLoggerSetMode (
    969   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    970   IN  UINTN                             ModeNumber
    971   )
    972 {
    973   EFI_STATUS                  Status;
    974 
    975   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
    976   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
    977 
    978   //
    979   // Forward the request to the original ConOut
    980   //
    981   Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber);
    982 
    983   //
    984   // Check that the buffers are still correct for logging
    985   //
    986   if (!EFI_ERROR (Status)) {
    987     ConsoleInfo->OurConOut.Mode = ConsoleInfo->OldConOut->Mode;
    988     ConsoleLoggerResetBuffers(ConsoleInfo);
    989     ConsoleInfo->OriginalStartRow = 0;
    990     ConsoleInfo->CurrentStartRow = 0;
    991     ConsoleInfo->OurConOut.ClearScreen (&ConsoleInfo->OurConOut);
    992   }
    993 
    994   return Status;
    995 }
    996 
    997 /**
    998   Sets the background and foreground colors for the OutputString () and
    999   ClearScreen () functions.
   1000 
   1001   @param[in] This               Protocol instance pointer.
   1002   @param[in] Attribute          The attribute to set. Bits 0..3 are the foreground color, and
   1003                                 bits 4..6 are the background color. All other bits are undefined
   1004                                 and must be zero. The valid Attributes are defined in this file.
   1005 
   1006   @retval EFI_SUCCESS           The attribute was set.
   1007   @retval EFI_DEVICE_ERROR      The device had an error and
   1008                                 could not complete the request.
   1009   @retval EFI_UNSUPPORTED       The attribute requested is not defined.
   1010 
   1011 **/
   1012 EFI_STATUS
   1013 EFIAPI
   1014 ConsoleLoggerSetAttribute (
   1015   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
   1016   IN  UINTN                           Attribute
   1017   )
   1018 {
   1019   EFI_STATUS                  Status;
   1020 
   1021   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
   1022   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
   1023 
   1024   //
   1025   // Forward the request to the original ConOut
   1026   //
   1027   Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute);
   1028 
   1029   //
   1030   // Record console output history
   1031   //
   1032   if (!EFI_ERROR (Status)) {
   1033     ConsoleInfo->HistoryMode.Attribute = (INT32) Attribute;
   1034   }
   1035 
   1036   return Status;
   1037 }
   1038 
   1039 /**
   1040   Clears the output device(s) display to the currently selected background
   1041   color.
   1042 
   1043   @param[in] This               Protocol instance pointer.
   1044 
   1045   @retval EFI_SUCCESS           The operation completed successfully.
   1046   @retval EFI_DEVICE_ERROR      The device had an error and
   1047                                 could not complete the request.
   1048   @retval EFI_UNSUPPORTED       The output device is not in a valid text mode.
   1049 **/
   1050 EFI_STATUS
   1051 EFIAPI
   1052 ConsoleLoggerClearScreen (
   1053   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This
   1054   )
   1055 {
   1056   EFI_STATUS        Status;
   1057   CHAR16            *Screen;
   1058   INT32             *Attributes;
   1059   UINTN             Row;
   1060   UINTN             Column;
   1061   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
   1062 
   1063   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
   1064     return (EFI_UNSUPPORTED);
   1065   }
   1066 
   1067   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
   1068 
   1069   //
   1070   // Forward the request to the original ConOut
   1071   //
   1072   Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
   1073 
   1074   //
   1075   // Record console output history
   1076   //
   1077   if (!EFI_ERROR (Status)) {
   1078     Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
   1079     Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
   1080     for ( Row = ConsoleInfo->OriginalStartRow
   1081         ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)
   1082         ; Row++
   1083        ){
   1084       for ( Column = 0
   1085           ; Column < ConsoleInfo->ColsPerScreen
   1086           ; Column++
   1087           , Screen++
   1088           , Attributes++
   1089          ){
   1090         *Screen = L' ';
   1091         *Attributes = ConsoleInfo->OldConOut->Mode->Attribute;
   1092       }
   1093       //
   1094       // Skip the NULL on each column end in text buffer only
   1095       //
   1096       Screen += 2;
   1097     }
   1098     ConsoleInfo->HistoryMode.CursorColumn = 0;
   1099     ConsoleInfo->HistoryMode.CursorRow    = 0;
   1100   }
   1101 
   1102   return Status;
   1103 }
   1104 
   1105 /**
   1106   Sets the current coordinates of the cursor position
   1107 
   1108   @param[in] This               Protocol instance pointer.
   1109   @param[in] Column             Column to put the cursor in.  Must be between zero and Column returned from QueryMode
   1110   @param[in] Row                Row to put the cursor in.  Must be between zero and Row returned from QueryMode
   1111 
   1112   @retval EFI_SUCCESS           The operation completed successfully.
   1113   @retval EFI_DEVICE_ERROR      The device had an error and
   1114                                 could not complete the request.
   1115   @retval EFI_UNSUPPORTED       The output device is not in a valid text mode, or the
   1116                                 cursor position is invalid for the current mode.
   1117 **/
   1118 EFI_STATUS
   1119 EFIAPI
   1120 ConsoleLoggerSetCursorPosition (
   1121   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
   1122   IN  UINTN                         Column,
   1123   IN  UINTN                         Row
   1124   )
   1125 {
   1126   EFI_STATUS                  Status;
   1127   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
   1128 
   1129   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
   1130     return (EFI_UNSUPPORTED);
   1131   }
   1132 
   1133   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
   1134   //
   1135   // Forward the request to the original ConOut
   1136   //
   1137   Status = ConsoleInfo->OldConOut->SetCursorPosition (
   1138     ConsoleInfo->OldConOut,
   1139     Column,
   1140     Row
   1141    );
   1142 
   1143   //
   1144   // Record console output history
   1145   //
   1146   if (!EFI_ERROR (Status)) {
   1147     ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column;
   1148     ConsoleInfo->HistoryMode.CursorRow    = (INT32)(ConsoleInfo->OriginalStartRow + Row);
   1149   }
   1150 
   1151   return Status;
   1152 }
   1153 
   1154 /**
   1155   Makes the cursor visible or invisible
   1156 
   1157   @param[in] This       Protocol instance pointer.
   1158   @param[in] Visible    If TRUE, the cursor is set to be visible. If FALSE, the cursor is
   1159                         set to be invisible.
   1160 
   1161   @retval EFI_SUCCESS           The operation completed successfully.
   1162   @retval EFI_DEVICE_ERROR      The device had an error and could not complete the
   1163                                 request, or the device does not support changing
   1164                                 the cursor mode.
   1165   @retval EFI_UNSUPPORTED       The output device is not in a valid text mode.
   1166 **/
   1167 EFI_STATUS
   1168 EFIAPI
   1169 ConsoleLoggerEnableCursor (
   1170   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
   1171   IN  BOOLEAN                       Visible
   1172   )
   1173 {
   1174   EFI_STATUS                  Status;
   1175 
   1176   CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
   1177   ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
   1178   //
   1179   // Forward the request to the original ConOut
   1180   //
   1181   Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible);
   1182 
   1183   //
   1184   // Record console output history
   1185   //
   1186   if (!EFI_ERROR (Status)) {
   1187     ConsoleInfo->HistoryMode.CursorVisible = Visible;
   1188   }
   1189 
   1190   return Status;
   1191 }
   1192 
   1193 /**
   1194   Function to update and verify that the current buffers are correct.
   1195 
   1196   @param[in] ConsoleInfo  The pointer to the instance of the console logger information.
   1197 
   1198   This will be used when a mode has changed or a reset ocurred to verify all
   1199   history buffers.
   1200 **/
   1201 EFI_STATUS
   1202 ConsoleLoggerResetBuffers(
   1203   IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
   1204   )
   1205 {
   1206   EFI_STATUS Status;
   1207 
   1208   if (ConsoleInfo->Buffer != NULL) {
   1209     FreePool(ConsoleInfo->Buffer);
   1210     ConsoleInfo->Buffer     = NULL;
   1211     ConsoleInfo->BufferSize = 0;
   1212   }
   1213   if (ConsoleInfo->Attributes != NULL) {
   1214     FreePool(ConsoleInfo->Attributes);
   1215     ConsoleInfo->Attributes = NULL;
   1216     ConsoleInfo->AttribSize = 0;
   1217   }
   1218 
   1219   Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen);
   1220   if (EFI_ERROR(Status)){
   1221     return (Status);
   1222   }
   1223 
   1224   ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Buffer[0]);
   1225   ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Attributes[0]);
   1226 
   1227   ConsoleInfo->Buffer = (CHAR16*)AllocateZeroPool(ConsoleInfo->BufferSize);
   1228 
   1229   if (ConsoleInfo->Buffer == NULL) {
   1230     return (EFI_OUT_OF_RESOURCES);
   1231   }
   1232 
   1233   ConsoleInfo->Attributes = (INT32*)AllocateZeroPool(ConsoleInfo->AttribSize);
   1234   if (ConsoleInfo->Attributes == NULL) {
   1235     FreePool(ConsoleInfo->Buffer);
   1236     ConsoleInfo->Buffer     = NULL;
   1237     return (EFI_OUT_OF_RESOURCES);
   1238   }
   1239 
   1240   CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE));
   1241 
   1242   return (EFI_SUCCESS);
   1243 }
   1244