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