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
ConsoleLoggerInstall(IN CONST UINTN ScreensToSave,OUT CONSOLE_LOGGER_PRIVATE_DATA ** ConsoleInfo)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
ConsoleLoggerUninstall(IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerDisplayHistory(IN CONST BOOLEAN Forward,IN CONST UINTN Rows,IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerStopHistory(IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
UpdateDisplayFromHistory(IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerReset(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
AppendStringToHistory(IN CONST CHAR16 * String,IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerOutputStringSplit(IN CONST CHAR16 * String,IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerDoPageBreak(VOID)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
ConsoleLoggerPrintWithPageBreak(IN CONST CHAR16 * String,IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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
ConsoleLoggerOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)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
ConsoleLoggerTestString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * WString)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
ConsoleLoggerQueryMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber,OUT UINTN * Columns,OUT UINTN * Rows)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
ConsoleLoggerSetMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber)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
ConsoleLoggerSetAttribute(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Attribute)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
ConsoleLoggerClearScreen(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This)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
ConsoleLoggerSetCursorPosition(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Column,IN UINTN Row)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
ConsoleLoggerEnableCursor(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN Visible)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
ConsoleLoggerResetBuffers(IN CONSOLE_LOGGER_PRIVATE_DATA * ConsoleInfo)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