]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ConsoleLogger.c
ShellPkg: Make BOOLEAN variable not use explicit comparison.
[mirror_edk2.git] / ShellPkg / Application / Shell / ConsoleLogger.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }