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