OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
TextOutputBuiltin.c
Go to the documentation of this file.
1
16
17#include <Uefi.h>
18#include <Guid/AppleVariable.h>
19#include <Library/BaseLib.h>
20#include <Library/BaseMemoryLib.h>
21#include <Library/DebugLib.h>
22#include <Library/MemoryAllocationLib.h>
24#include <Library/OcMiscLib.h>
25#include <Library/UefiBootServicesTableLib.h>
26#include <Library/UefiRuntimeServicesTableLib.h>
28#include <Protocol/GraphicsOutput.h>
29
30STATIC BOOLEAN mIsDefaultFont;
32
33STATIC UINT32 mGraphicsEfiColors[16] = {
34 0x00000000, // BLACK
35 0x00000098, // LIGHTBLUE
36 0x00009800, // LIGHTGREEN
37 0x00009898, // LIGHTCYAN
38 0x00980000, // LIGHTRED
39 0x00980098, // MAGENTA
40 0x00989800, // BROWN
41 0x00bfbfbf, // LIGHTGRAY
42 0x00303030, // DARKGRAY - BRIGHT BLACK
43 0x000000ff, // BLUE
44 0x0000ff00, // LIME
45 0x0000ffff, // CYAN
46 0x00ff0000, // RED
47 0x00ff00ff, // FUCHSIA
48 0x00ffff00, // YELLOW
49 0x00ffffff // WHITE
50};
51
52STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL *mGraphicsOutput;
53STATIC UINTN mConsolePaddingX;
54STATIC UINTN mConsolePaddingY;
55STATIC UINTN mUserWidth;
56STATIC UINTN mUserHeight;
57STATIC UINTN mConsoleWidth;
58STATIC UINTN mConsoleHeight;
59STATIC UINTN mConsoleMaxPosX;
60STATIC UINTN mConsoleMaxPosY;
61STATIC BOOLEAN mConsoleUncontrolled;
62STATIC UINTN mPrivateColumn;
63STATIC UINTN mPrivateRow;
64STATIC UINT32 mConsoleGopMode;
65STATIC UINT8 mUIScale;
66STATIC UINT8 mFontScale;
67STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mBackgroundColor;
68STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mForegroundColor;
69STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *mCharacterBuffer;
71
72#define TGT_CHAR_WIDTH ((UINTN)(ISO_CHAR_WIDTH) * mFontScale)
73#define TGT_CHAR_HEIGHT ((UINTN)(ISO_CHAR_HEIGHT) * mFontScale)
74#define TGT_CHAR_AREA ((TGT_CHAR_WIDTH) * (TGT_CHAR_HEIGHT))
75#define TGT_PADD_WIDTH (mConsolePaddingX)
76#define TGT_PADD_HEIGHT (mConsolePaddingY)
77#define TGT_CURSOR_X mFontScale
78#define TGT_CURSOR_Y ((TGT_CHAR_HEIGHT) - mFontScale)
79#define TGT_CURSOR_WIDTH ((TGT_CHAR_WIDTH) - mFontScale * 2)
80#define TGT_CURSOR_HEIGHT (mFontScale)
81
82#define MIN_SUPPORTED_CONSOLE_WIDTH (80)
83#define MIN_SUPPORTED_CONSOLE_HEIGHT (25)
84
98STATIC
99EFI_STATUS
101 IN OC_CONSOLE_FONT *ConsoleFont,
102 IN CHAR16 Char,
103 OUT OC_CONSOLE_FONT_PAGE **Page,
104 OUT UINT8 *GlyphIndex,
105 IN BOOLEAN UseFallback
106 )
107{
108 EFI_STATUS Status;
109 UINT16 PageNumber;
110 UINT8 PageChar;
111 UINT16 PageIndex;
112
113 ASSERT (Page != NULL);
114 ASSERT (GlyphIndex != NULL);
115
116 PageNumber = (Char >> 7) & 0x1FF;
117 PageChar = Char & 0x7F;
118
119 *GlyphIndex = 0;
120
121 Status = EFI_SUCCESS;
122 do {
123 if ((PageNumber >= ConsoleFont->PageMin) && (PageNumber < ConsoleFont->PageMax)) {
124 PageIndex = PageNumber - ConsoleFont->PageMin + 1;
125 if (ConsoleFont->PageOffsets != NULL) {
126 PageIndex = ConsoleFont->PageOffsets[PageIndex - 1];
127 }
128
129 if (PageIndex != 0) {
130 *Page = &ConsoleFont->Pages[PageIndex - 1];
131 if ((PageChar >= (*Page)->CharMin) && (PageChar < (*Page)->CharMax)) {
132 ASSERT ((*Page)->Glyphs != NULL);
133 if ((*Page)->GlyphOffsets == NULL) {
134 *GlyphIndex = PageChar - (*Page)->CharMin + 1;
135 } else {
136 *GlyphIndex = (*Page)->GlyphOffsets[PageChar - (*Page)->CharMin];
137 }
138 }
139 }
140 }
141
142 if (*GlyphIndex == 0) {
143 //
144 // Give up and render nothing if fallback char is not present.
145 //
146 ASSERT (Status == EFI_SUCCESS);
147 if (!UseFallback || (Status != EFI_SUCCESS)) {
148 return EFI_LOAD_ERROR;
149 }
150
151 Status = EFI_WARN_UNKNOWN_GLYPH;
152
153 //
154 // For default font, render all unknown chars in provided page(s) as space (following the explicit
155 // spaces in free console font used in XNU); in other pages and in user fonts use underscore.
156 //
157 STATIC_ASSERT (ISO_FONT_MAX_PAGE == 1 || ISO_FONT_MAX_PAGE == 2, "Invalid ISO_FONT_MAX_PAGE value");
158 if (mIsDefaultFont && (PageNumber < ISO_FONT_MAX_PAGE)) {
159 PageChar = L' ';
160 } else {
162 }
163
164 PageNumber = 0;
165 }
166 } while (*GlyphIndex == 0);
167
168 return Status;
169}
170
171BOOLEAN
173 IN OC_CONSOLE_FONT *ConsoleFont,
174 IN CHAR16 Char
175 )
176{
177 EFI_STATUS Status;
179 UINT8 GlyphIndex;
180
181 Status = GetConsoleFontCharInfo (ConsoleFont, Char, &Page, &GlyphIndex, FALSE);
182
183 return !EFI_ERROR (Status);
184}
185
193STATIC
194VOID
196 IN CHAR16 Char,
197 IN UINTN PosX,
198 IN UINTN PosY
199 )
200{
201 UINT32 *DstBuffer;
202 UINT8 *SrcBuffer;
204 UINT8 Line;
205 UINT32 Index;
206 UINT32 Index2;
207 UINT8 Mask;
208 UINT8 FontHead;
209 UINT8 FontTail;
210 UINT8 GlyphIndex;
211 BOOLEAN LeftToRight;
212 EFI_STATUS Status;
213
214 DstBuffer = &mCharacterBuffer[0].Raw;
215
216 Status = GetConsoleFontCharInfo (mConsoleFont, Char, &Page, &GlyphIndex, TRUE);
217
218 if (EFI_ERROR (Status)) {
219 return;
220 }
221
222 FontHead = Page->FontHead;
223 FontTail = Page->FontTail;
224 LeftToRight = Page->LeftToRight;
225
226 SrcBuffer = Page->Glyphs + ((GlyphIndex - 1) * (ISO_CHAR_HEIGHT - FontHead - FontTail));
227
228 for (Line = 0; Line < FontHead; ++Line) {
229 //
230 // Apply scale twice, for width and height.
231 //
232 SetMem32 (DstBuffer, TGT_CHAR_WIDTH * mFontScale * sizeof (DstBuffer[0]), mBackgroundColor.Raw);
233 DstBuffer += TGT_CHAR_WIDTH * mFontScale;
234 }
235
236 for ( ; Line < ISO_CHAR_HEIGHT - FontTail; ++Line) {
237 //
238 // Iterate, while single bit scans font.
239 //
240 for (Index = 0; Index < mFontScale; ++Index) {
241 Mask = LeftToRight ? 0x80 : 1;
242 do {
243 for (Index2 = 0; Index2 < mFontScale; ++Index2) {
244 *DstBuffer = (*SrcBuffer & Mask) ? mForegroundColor.Raw : mBackgroundColor.Raw;
245 ++DstBuffer;
246 }
247
248 if (LeftToRight) {
249 Mask >>= 1U;
250 } else {
251 Mask <<= 1U;
252 }
253 } while (Mask != 0);
254 }
255
256 ++SrcBuffer;
257 }
258
259 for ( ; Line < ISO_CHAR_HEIGHT; ++Line) {
260 SetMem32 (DstBuffer, TGT_CHAR_WIDTH * mFontScale * sizeof (DstBuffer[0]), mBackgroundColor.Raw);
261 DstBuffer += TGT_CHAR_WIDTH * mFontScale;
262 }
263
264 ASSERT (DstBuffer - &mCharacterBuffer[0].Raw == (INTN)TGT_CHAR_AREA);
265
266 mGraphicsOutput->Blt (
268 &mCharacterBuffer[0].Pixel,
269 EfiBltBufferToVideo,
270 0,
271 0,
276 0
277 );
278}
279
287STATIC
288VOID
290 IN BOOLEAN Enabled,
291 IN UINTN PosX,
292 IN UINTN PosY
293 )
294{
295 EFI_STATUS Status;
296 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Colour;
297
298 if (!Enabled || (mConsoleMode != EfiConsoleControlScreenText)) {
299 return;
300 }
301
302 //
303 // UEFI only has one cursor at a time. UEFI Shell edit command has a cursor and a mouse
304 // pointer, which are not connected. To be able to draw both at a time UEFI Shell constantly
305 // redraws both the cursor and the mouse pointer. To do that it constantly flips bg and fg
306 // colours as well as cursor visibility.
307 // It seems that the Shell implementation relies on an undocumented feature (is that a bug?)
308 // of hiding an already drawn cursor with a space with inverted attributes.
309 // This is weird but EDK II implementation seems to match the logic, and as a result we
310 // track cursor visibility or easily optimise this logic.
311 //
312 Status = mGraphicsOutput->Blt (
314 &Colour.Pixel,
315 EfiBltVideoToBltBuffer,
318 0,
319 0,
320 1,
321 1,
322 0
323 );
324
325 if (EFI_ERROR (Status)) {
326 return;
327 }
328
329 mGraphicsOutput->Blt (
331 Colour.Raw == mForegroundColor.Raw ? &mBackgroundColor.Pixel : &mForegroundColor.Pixel,
332 EfiBltVideoFill,
333 0,
334 0,
339 0
340 );
341}
342
343STATIC
344VOID
346 VOID
347 )
348{
349 UINTN Width;
350
351 //
352 // Move used screen region.
353 //
354 Width = (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH;
355 mGraphicsOutput->Blt (
357 NULL,
358 EfiBltVideoToVideo,
363 Width,
365 0
366 );
367
368 //
369 // Erase last line.
370 //
371 mGraphicsOutput->Blt (
373 &mBackgroundColor.Pixel,
374 EfiBltVideoFill,
375 0,
376 0,
379 Width,
381 0
382 );
383}
384
385//
386// Resync - called on detected change of GOP mode and on reset.
387//
388STATIC
389EFI_STATUS
391 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
392 )
393{
394 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
395 UINTN MaxWidth;
396 UINTN MaxHeight;
397
398 Info = mGraphicsOutput->Mode->Info;
399
400 //
401 // Require space for at least 1x1 chars on the calculation below.
402 //
403 if ( (Info->HorizontalResolution < ISO_CHAR_WIDTH)
404 || (Info->VerticalResolution < ISO_CHAR_HEIGHT))
405 {
406 return EFI_LOAD_ERROR;
407 }
408
409 if (mCharacterBuffer != NULL) {
410 FreePool (mCharacterBuffer);
411 }
412
413 //
414 // Reset font scale and allocate for target size - may be over-allocated if we have to override below.
415 //
417 mCharacterBuffer = AllocatePool (TGT_CHAR_AREA * sizeof (mCharacterBuffer[0]));
418 if (mCharacterBuffer == NULL) {
419 return EFI_OUT_OF_RESOURCES;
420 }
421
422 mConsoleGopMode = mGraphicsOutput->Mode->Mode;
423
424 //
425 // Override font scale to reach minimum supported text resolution, if needed and possible.
426 //
427 while (TRUE) {
428 MaxWidth = Info->HorizontalResolution / TGT_CHAR_WIDTH;
429 MaxHeight = Info->VerticalResolution / TGT_CHAR_HEIGHT;
430 if ( (MaxWidth >= MIN_SUPPORTED_CONSOLE_WIDTH)
431 && (MaxHeight >= MIN_SUPPORTED_CONSOLE_HEIGHT))
432 {
433 break;
434 }
435
436 if (mFontScale == 1) {
437 break;
438 }
439
440 mFontScale = 1;
441 }
442
443 if ((mUserWidth == 0) || (mUserHeight == 0)) {
444 mConsoleWidth = MaxWidth;
445 mConsoleHeight = MaxHeight;
446 } else {
447 mConsoleWidth = MIN (MaxWidth, mUserWidth);
448 mConsoleHeight = MIN (MaxHeight, mUserHeight);
449 }
450
451 mConsolePaddingX = (Info->HorizontalResolution - (mConsoleWidth * TGT_CHAR_WIDTH)) / 2;
452 mConsolePaddingY = (Info->VerticalResolution - (mConsoleHeight * TGT_CHAR_HEIGHT)) / 2;
453 mConsoleMaxPosX = 0;
454 mConsoleMaxPosY = 0;
455 mConsoleUncontrolled = FALSE;
456
458 This->Mode->CursorColumn = This->Mode->CursorRow = 0;
459
460 //
461 // Avoid rendering any console content when in graphics mode.
462 //
464 mGraphicsOutput->Blt (
466 &mBackgroundColor.Pixel,
467 EfiBltVideoFill,
468 0,
469 0,
470 0,
471 0,
472 Info->HorizontalResolution,
473 Info->VerticalResolution,
474 0
475 );
476 }
477
478 return EFI_SUCCESS;
479}
480
481STATIC
482EFI_STATUS
483EFIAPI
485 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
486 IN BOOLEAN ExtendedVerification,
487 IN BOOLEAN Debug
488 )
489{
490 EFI_STATUS Status;
491 EFI_TPL OldTpl;
492
493 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
494
495 Status = OcHandleProtocolFallback (
496 gST->ConsoleOutHandle,
498 (VOID **)&mGraphicsOutput
499 );
500
501 if (EFI_ERROR (Status)) {
502 gBS->RestoreTPL (OldTpl);
503 if (Debug) {
504 DEBUG ((DEBUG_INFO, "OCC: ASCII Text Reset [HandleProtocolFallback] - %r\n", Status));
505 return Status;
506 }
507
508 return EFI_DEVICE_ERROR;
509 }
510
511 This->Mode->MaxMode = 1;
512 This->Mode->Attribute = ARRAY_SIZE (mGraphicsEfiColors) / 2 - 1;
515
516 Status = RenderResync (This);
517 gBS->RestoreTPL (OldTpl);
518 if (EFI_ERROR (Status)) {
519 if (Debug) {
520 DEBUG ((DEBUG_INFO, "OCC: ASCII Text Reset [RenderResync] - %r\n", Status));
521 return Status;
522 }
523
524 return EFI_DEVICE_ERROR;
525 }
526
527 return EFI_SUCCESS;
528}
529
530STATIC
531EFI_STATUS
532EFIAPI
534 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
535 IN BOOLEAN ExtendedVerification
536 )
537{
538 EFI_STATUS Status;
539
540 Status = AsciiTextResetEx (This, ExtendedVerification, FALSE);
541 return Status;
542}
543
544STATIC
545EFI_STATUS
546EFIAPI
548 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
549 IN CHAR16 *String
550 )
551{
552 UINTN Index;
553 EFI_TPL OldTpl;
554 EFI_STATUS Status;
555
556 //
557 // Do not print text in graphics mode.
558 //
560 return EFI_UNSUPPORTED;
561 }
562
563 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
564
565 //
566 // Do not print in different modes.
567 //
568 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
569 Status = RenderResync (This);
570 if (EFI_ERROR (Status)) {
571 gBS->RestoreTPL (OldTpl);
572 return EFI_DEVICE_ERROR;
573 }
574 }
575
576 //
577 // For whatever reason UEFI Shell trashes these values when executing commands like help -b.
578 //
579 This->Mode->CursorColumn = (INT32)mPrivateColumn;
580 This->Mode->CursorRow = (INT32)mPrivateRow;
581
582 FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
583
584 for (Index = 0; String[Index] != '\0'; ++Index) {
585 //
586 // Carriage return should just move the cursor back.
587 //
588 if (String[Index] == CHAR_CARRIAGE_RETURN) {
589 This->Mode->CursorColumn = 0;
590 continue;
591 }
592
593 if (String[Index] == CHAR_BACKSPACE) {
594 if ((This->Mode->CursorColumn == 0) && (This->Mode->CursorRow > 0)) {
595 This->Mode->CursorRow--;
596 This->Mode->CursorColumn = (INT32)(mConsoleWidth - 1);
597 RenderChar (' ', This->Mode->CursorColumn, This->Mode->CursorRow);
598 } else if (This->Mode->CursorColumn > 0) {
599 This->Mode->CursorColumn--;
600 RenderChar (' ', This->Mode->CursorColumn, This->Mode->CursorRow);
601 }
602
603 continue;
604 }
605
606 //
607 // Newline should move the cursor lower.
608 // In case we are out of room it should scroll instead.
609 //
610 if (String[Index] == CHAR_LINEFEED) {
611 if ((UINTN)This->Mode->CursorRow < mConsoleHeight - 1) {
612 ++This->Mode->CursorRow;
613 mConsoleMaxPosY = MAX (mConsoleMaxPosY, (UINTN)This->Mode->CursorRow);
614 } else {
615 RenderScroll ();
616 }
617
618 continue;
619 }
620
621 //
622 // Render normal symbol and decide on next cursor position.
623 //
624 RenderChar (String[Index] == CHAR_TAB ? L' ' : String[Index], This->Mode->CursorColumn, This->Mode->CursorRow);
625
626 if ((UINTN)This->Mode->CursorColumn < mConsoleWidth - 1) {
627 //
628 // Continues on the same line.
629 //
630 ++This->Mode->CursorColumn;
631 mConsoleMaxPosX = MAX (mConsoleMaxPosX, (UINTN)This->Mode->CursorColumn);
632 } else if ((UINTN)This->Mode->CursorRow < mConsoleHeight - 1) {
633 //
634 // New line without scroll.
635 //
636 This->Mode->CursorColumn = 0;
637 ++This->Mode->CursorRow;
638 mConsoleMaxPosY = MAX (mConsoleMaxPosY, (UINTN)This->Mode->CursorRow);
639 } else {
640 //
641 // New line with scroll.
642 //
643 RenderScroll ();
644 This->Mode->CursorColumn = 0;
645 }
646 }
647
648 FlushCursor (This->Mode->CursorVisible, This->Mode->CursorColumn, This->Mode->CursorRow);
649
650 mPrivateColumn = (UINTN)This->Mode->CursorColumn;
651 mPrivateRow = (UINTN)This->Mode->CursorRow;
652
653 gBS->RestoreTPL (OldTpl);
654
655 return EFI_SUCCESS;
656}
657
658STATIC
659EFI_STATUS
660EFIAPI
662 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
663 IN CHAR16 *String
664 )
665{
666 if (StrCmp (String, OC_CONSOLE_MARK_UNCONTROLLED) == 0) {
668 }
669
670 return EFI_SUCCESS;
671}
672
673STATIC
674EFI_STATUS
675EFIAPI
677 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
678 IN UINTN ModeNumber,
679 OUT UINTN *Columns,
680 OUT UINTN *Rows
681 )
682{
683 EFI_STATUS Status;
684 EFI_TPL OldTpl;
685
686 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
687
688 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
689 Status = RenderResync (This);
690 if (EFI_ERROR (Status)) {
691 gBS->RestoreTPL (OldTpl);
692 return EFI_DEVICE_ERROR;
693 }
694 }
695
696 if (ModeNumber == 0) {
697 *Columns = mConsoleWidth;
698 *Rows = mConsoleHeight;
699 Status = EFI_SUCCESS;
700 } else {
701 Status = EFI_UNSUPPORTED;
702 }
703
704 gBS->RestoreTPL (OldTpl);
705
706 return Status;
707}
708
709STATIC
710EFI_STATUS
711EFIAPI
713 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
714 IN UINTN ModeNumber
715 )
716{
717 EFI_STATUS Status;
718 EFI_TPL OldTpl;
719
720 if (ModeNumber != 0) {
721 return EFI_UNSUPPORTED;
722 }
723
724 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
725 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
726 Status = RenderResync (This);
727 gBS->RestoreTPL (OldTpl);
728 if (EFI_ERROR (Status)) {
729 return EFI_DEVICE_ERROR;
730 }
731 }
732
733 return EFI_SUCCESS;
734}
735
736STATIC
737EFI_STATUS
738EFIAPI
740 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
741 IN UINTN Attribute
742 )
743{
744 EFI_STATUS Status;
745 UINT32 FgColor;
746 UINT32 BgColor;
747 EFI_TPL OldTpl;
748
749 if ((Attribute & ~0x7FU) != 0) {
750 return EFI_UNSUPPORTED;
751 }
752
753 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
754
755 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
756 Status = RenderResync (This);
757 if (EFI_ERROR (Status)) {
758 gBS->RestoreTPL (OldTpl);
759 return EFI_DEVICE_ERROR;
760 }
761 }
762
763 if (Attribute != (UINTN)This->Mode->Attribute) {
764 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
765
766 FgColor = BitFieldRead32 ((UINT32)Attribute, 0, 3);
767 BgColor = BitFieldRead32 ((UINT32)Attribute, 4, 6);
768
769 //
770 // Once we change the background colour, any clear screen must cover the whole screen.
771 //
772 if (mGraphicsEfiColors[BgColor] != mBackgroundColor.Raw) {
774 }
775
778 This->Mode->Attribute = (UINT32)Attribute;
779
780 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
781 }
782
783 gBS->RestoreTPL (OldTpl);
784 return EFI_SUCCESS;
785}
786
787//
788// Note: This intentionally performs a partial screen clear, affecting only the
789// area containing text which has been written using our renderer, unless console
790// is marked uncontrolled prior to clearing.
791//
792STATIC
793EFI_STATUS
794EFIAPI
796 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
797 )
798{
799 EFI_STATUS Status;
800 UINTN Width;
801 UINTN Height;
802 EFI_TPL OldTpl;
803
804 //
805 // Note: We stay marked uncontrolled, if staying in graphics mode.
806 //
808 return EFI_UNSUPPORTED;
809 }
810
811 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
812
813 //
814 // No need to re-clear screen straight after resync; but note that the initial screen
815 // clear after resync, although of non-zero size, is intentionally very lightweight.
816 //
817 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
818 Status = RenderResync (This);
819 if (EFI_ERROR (Status)) {
820 gBS->RestoreTPL (OldTpl);
821 return EFI_DEVICE_ERROR;
822 }
823 } else {
824 //
825 // When controlled, we assume that only text which we rendered needs to be cleared.
826 // When marked uncontrolled anyone may have put content (in particular, graphics) anywhere
827 // so always clear full screen.
828 //
830 mGraphicsOutput->Blt (
832 &mBackgroundColor.Pixel,
833 EfiBltVideoFill,
834 0,
835 0,
836 0,
837 0,
838 mGraphicsOutput->Mode->Info->HorizontalResolution,
839 mGraphicsOutput->Mode->Info->VerticalResolution,
840 0
841 );
842
843 mConsoleUncontrolled = FALSE;
844 } else {
845 //
846 // mConsoleMaxPosX,Y coordinates are the top left coordinates of the of the greatest
847 // occupied character position. Because there is a cursor, there is always at least
848 // one character position occupied.
849 //
850 Width = (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH;
851 Height = (mConsoleMaxPosY + 1) * TGT_CHAR_HEIGHT;
852 ASSERT (TGT_PADD_WIDTH + Width <= mGraphicsOutput->Mode->Info->HorizontalResolution);
853 ASSERT (TGT_PADD_HEIGHT + Height <= mGraphicsOutput->Mode->Info->VerticalResolution);
854
855 mGraphicsOutput->Blt (
857 &mBackgroundColor.Pixel,
858 EfiBltVideoFill,
859 0,
860 0,
863 Width,
864 Height,
865 0
866 );
867 }
868 }
869
870 //
871 // Handle cursor.
872 //
874 This->Mode->CursorColumn = This->Mode->CursorRow = 0;
875 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
876
877 //
878 // After clear screen, shell may scroll through old text via page up/down buttons,
879 // but it is okay to reset max x/y here anyway, as any old text is brought on via
880 // full redraw.
881 //
882 mConsoleMaxPosX = 0;
883 mConsoleMaxPosY = 0;
884
885 gBS->RestoreTPL (OldTpl);
886 return EFI_SUCCESS;
887}
888
889STATIC
890EFI_STATUS
891EFIAPI
893 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
894 IN UINTN Column,
895 IN UINTN Row
896 )
897{
898 EFI_STATUS Status;
899 EFI_TPL OldTpl;
900
901 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
902
903 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
904 Status = RenderResync (This);
905 if (EFI_ERROR (Status)) {
906 gBS->RestoreTPL (OldTpl);
907 return EFI_DEVICE_ERROR;
908 }
909 }
910
911 //
912 // Clamping the row here successfully works round a bug in memtest86 where it
913 // does not re-read console text resolution when it changes the graphics mode.
914 // If changing between text resolutions >= 80x25, the issue is only visible
915 // in the position of the footer line on the text UI screen, and this fixes it.
916 //
917 if (Column >= mConsoleWidth) {
918 Column = mConsoleWidth - 1;
919 }
920
921 if (Row >= mConsoleHeight) {
922 Row = mConsoleHeight - 1;
923 }
924
925 if ((Column < mConsoleWidth) && (Row < mConsoleHeight)) {
926 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
927 mPrivateColumn = Column;
928 mPrivateRow = Row;
929 This->Mode->CursorColumn = (INT32)mPrivateColumn;
930 This->Mode->CursorRow = (INT32)mPrivateRow;
931 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
934 Status = EFI_SUCCESS;
935 } else {
936 Status = EFI_UNSUPPORTED;
937 }
938
939 gBS->RestoreTPL (OldTpl);
940 return Status;
941}
942
943STATIC
944EFI_STATUS
945EFIAPI
947 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
948 IN BOOLEAN Visible
949 )
950{
951 EFI_STATUS Status;
952 EFI_TPL OldTpl;
953
954 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
955
956 if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) {
957 Status = RenderResync (This);
958 if (EFI_ERROR (Status)) {
959 gBS->RestoreTPL (OldTpl);
960 return EFI_DEVICE_ERROR;
961 }
962 }
963
964 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
965 This->Mode->CursorVisible = Visible;
966 FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow);
967 gBS->RestoreTPL (OldTpl);
968 return EFI_SUCCESS;
969}
970
971STATIC
972EFI_SIMPLE_TEXT_OUTPUT_MODE
974
975STATIC
976EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
989
990STATIC
991EFI_STATUS
992EFIAPI
996 OUT BOOLEAN *GopUgaExists OPTIONAL,
997 OUT BOOLEAN *StdInLocked OPTIONAL
998 )
999{
1000 *Mode = mConsoleMode;
1001
1002 if (GopUgaExists != NULL) {
1003 *GopUgaExists = TRUE;
1004 }
1005
1006 if (StdInLocked != NULL) {
1007 *StdInLocked = FALSE;
1008 }
1009
1010 return EFI_SUCCESS;
1011}
1012
1013STATIC
1014EFI_STATUS
1015EFIAPI
1019 )
1020{
1021 if (mConsoleMode != Mode) {
1022 mConsoleMode = Mode;
1023
1024 //
1025 // If controlled, switching to graphics then back to text should change nothing.
1026 //
1029 {
1030 gST->ConOut->ClearScreen (gST->ConOut);
1031 }
1032 }
1033
1034 return EFI_SUCCESS;
1035}
1036
1037STATIC
1038EFI_STATUS
1039EFIAPI
1042 IN CHAR16 *Password
1043 )
1044{
1045 return EFI_DEVICE_ERROR;
1046}
1047
1048STATIC
1055
1056EFI_STATUS
1058 IN EFI_CONSOLE_CONTROL_SCREEN_MODE InitialMode,
1059 IN OC_STORAGE_CONTEXT *Storage OPTIONAL,
1060 IN CONST CHAR8 *Font OPTIONAL,
1062 IN UINT32 Width,
1063 IN UINT32 Height
1064 )
1065{
1066 EFI_STATUS Status;
1067 UINTN UiScaleSize;
1068 EFI_CONSOLE_CONTROL_PROTOCOL OriginalConsoleControlProtocol;
1069
1070 Status = EFI_NOT_FOUND;
1071 if ((Storage != NULL) && (Font != NULL) && (*Font != '\0')) {
1072 Status = OcLoadConsoleFont (Storage, Font, &mConsoleFont);
1073 DEBUG ((
1074 EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
1075 "OCC: Loading hex font %a - %r\n",
1076 Font,
1077 Status
1078 ));
1079 }
1080
1081 if (EFI_ERROR (Status)) {
1082 mIsDefaultFont = TRUE;
1084 }
1085
1086 UiScaleSize = sizeof (mUIScale);
1087
1088 Status = gRT->GetVariable (
1091 NULL,
1092 &UiScaleSize,
1093 (VOID *)&mUIScale
1094 );
1095
1096 if (EFI_ERROR (Status) || (mUIScale != 2)) {
1097 mUIScale = 1;
1098 }
1099
1101
1102 DEBUG ((DEBUG_INFO, "OCC: Using builtin text renderer with %d scale\n", mUIScale));
1103
1104 mUserWidth = Width;
1105 mUserHeight = Height;
1106 mConsoleMode = InitialMode;
1108 Status = OcConsoleControlInstallProtocol (&mConsoleControlProtocol, &OriginalConsoleControlProtocol, NULL);
1109 if (!EFI_ERROR (Status)) {
1110 Status = AsciiTextResetEx (&mAsciiTextOutputProtocol, TRUE, TRUE);
1111 if (EFI_ERROR (Status)) {
1112 OcConsoleControlRestoreProtocol (&OriginalConsoleControlProtocol);
1113 } else {
1114 gST->ConOut = &mAsciiTextOutputProtocol;
1115 gST->Hdr.CRC32 = 0;
1116
1117 gBS->CalculateCrc32 (
1118 gST,
1119 gST->Hdr.HeaderSize,
1120 &gST->Hdr.CRC32
1121 );
1122 }
1123 }
1124
1125 DEBUG ((DEBUG_INFO, "OCC: Setup ASCII Output - %r\n", Status));
1126
1127 return Status;
1128}
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
EFI_GUID gAppleVendorVariableGuid
#define APPLE_UI_SCALE_VARIABLE_NAME
EFI_STATUS OcConsoleControlInstallProtocol(IN EFI_CONSOLE_CONTROL_PROTOCOL *NewProtocol, OUT EFI_CONSOLE_CONTROL_PROTOCOL *OldProtocol OPTIONAL, IN OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *OldMode OPTIONAL)
EFI_STATUS OcConsoleControlRestoreProtocol(IN EFI_CONSOLE_CONTROL_PROTOCOL *OldProtocol)
EFI_CONSOLE_CONTROL_SCREEN_MODE
@ EfiConsoleControlScreenText
EFI_STATUS OcLoadConsoleFont(IN OC_STORAGE_CONTEXT *Storage, IN CONST CHAR8 *FontName, OUT OC_CONSOLE_FONT **Font)
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
EFI_CONSOLE_CONTROL_SCREEN_MODE OcConsoleControlSetMode(IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode)
#define OC_CONSOLE_FONT_FALLBACK_CHAR
OC_CONSOLE_FONT gDefaultConsoleFont
#define OC_CONSOLE_MARK_UNCONTROLLED
#define ISO_CHAR_WIDTH
#define ISO_CHAR_HEIGHT
#define ISO_FONT_MAX_PAGE
EFI_STATUS OcHandleProtocolFallback(IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, OUT VOID **Interface)
STATIC EFI_STATUS EFIAPI AsciiTextQueryMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN UINTN ModeNumber, OUT UINTN *Columns, OUT UINTN *Rows)
STATIC UINTN mConsoleMaxPosY
STATIC EFI_STATUS EFIAPI AsciiTextSetMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN UINTN ModeNumber)
STATIC EFI_STATUS EFIAPI AsciiTextReset(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN BOOLEAN ExtendedVerification)
STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mBackgroundColor
STATIC EFI_STATUS EFIAPI ConsoleControlSetMode(IN EFI_CONSOLE_CONTROL_PROTOCOL *This, IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode)
#define TGT_CURSOR_WIDTH
STATIC UINTN mConsoleWidth
#define TGT_CURSOR_Y
STATIC UINTN mConsoleHeight
STATIC UINT8 mFontScale
STATIC BOOLEAN mIsDefaultFont
STATIC EFI_CONSOLE_CONTROL_SCREEN_MODE mConsoleMode
#define TGT_CHAR_WIDTH
STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mForegroundColor
STATIC UINT32 mConsoleGopMode
STATIC EFI_STATUS EFIAPI AsciiTextSetCursorPosition(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN UINTN Column, IN UINTN Row)
BOOLEAN OcConsoleFontContainsChar(IN OC_CONSOLE_FONT *ConsoleFont, IN CHAR16 Char)
EFI_STATUS OcUseBuiltinTextOutput(IN EFI_CONSOLE_CONTROL_SCREEN_MODE InitialMode, IN OC_STORAGE_CONTEXT *Storage OPTIONAL, IN CONST CHAR8 *Font OPTIONAL, IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode, IN UINT32 Width, IN UINT32 Height)
STATIC VOID RenderScroll(VOID)
STATIC EFI_STATUS RenderResync(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This)
#define TGT_PADD_WIDTH
STATIC BOOLEAN mConsoleUncontrolled
#define TGT_CURSOR_X
STATIC UINTN mUserHeight
#define TGT_CURSOR_HEIGHT
#define TGT_CHAR_AREA
STATIC UINT32 mGraphicsEfiColors[16]
STATIC EFI_STATUS EFIAPI ConsoleControlLockStdIn(IN EFI_CONSOLE_CONTROL_PROTOCOL *This, IN CHAR16 *Password)
STATIC EFI_STATUS EFIAPI AsciiTextTestString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN CHAR16 *String)
STATIC EFI_STATUS EFIAPI AsciiTextClearScreen(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This)
#define MIN_SUPPORTED_CONSOLE_WIDTH
STATIC UINT8 mUIScale
STATIC EFI_STATUS EFIAPI AsciiTextSetAttribute(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN UINTN Attribute)
STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION * mCharacterBuffer
STATIC UINTN mConsolePaddingX
STATIC OC_CONSOLE_FONT * mConsoleFont
STATIC EFI_SIMPLE_TEXT_OUTPUT_MODE mAsciiTextOutputMode
STATIC UINTN mPrivateColumn
At least UEFI Shell trashes Mode values.
STATIC UINTN mUserWidth
STATIC EFI_STATUS EFIAPI AsciiTextOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN CHAR16 *String)
#define TGT_CHAR_HEIGHT
STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL * mGraphicsOutput
STATIC UINTN mPrivateRow
At least UEFI Shell trashes Mode values.
#define MIN_SUPPORTED_CONSOLE_HEIGHT
STATIC EFI_CONSOLE_CONTROL_PROTOCOL mConsoleControlProtocol
STATIC VOID FlushCursor(IN BOOLEAN Enabled, IN UINTN PosX, IN UINTN PosY)
STATIC EFI_STATUS EFIAPI AsciiTextEnableCursor(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN BOOLEAN Visible)
STATIC UINTN mConsoleMaxPosX
STATIC EFI_STATUS EFIAPI ConsoleControlGetMode(IN EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, OUT BOOLEAN *GopUgaExists OPTIONAL, OUT BOOLEAN *StdInLocked OPTIONAL)
STATIC UINTN mConsolePaddingY
#define TGT_PADD_HEIGHT
STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mAsciiTextOutputProtocol
STATIC EFI_STATUS GetConsoleFontCharInfo(IN OC_CONSOLE_FONT *ConsoleFont, IN CHAR16 Char, OUT OC_CONSOLE_FONT_PAGE **Page, OUT UINT8 *GlyphIndex, IN BOOLEAN UseFallback)
STATIC VOID RenderChar(IN CHAR16 Char, IN UINTN PosX, IN UINTN PosY)
STATIC EFI_STATUS EFIAPI AsciiTextResetEx(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN BOOLEAN ExtendedVerification, IN BOOLEAN Debug)
EFI_RUNTIME_SERVICES * gRT
EFI_GUID gEfiGraphicsOutputProtocolGuid
#define ASSERT(x)
Definition coder.h:55
#define MAX(a, b)
Definition coder.h:59
#define MIN(a, b)
Definition deflate.c:1673