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