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