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