xref: /reactos/boot/environ/lib/io/display/display.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING.ARM in the top level directory
3  * PROJECT:         ReactOS UEFI Boot Library
4  * FILE:            boot/environ/lib/platform/display.c
5  * PURPOSE:         Boot Library Display Management Routines
6  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "bl.h"
12 #include <bcd.h>
13 
14 /* DATA VARIABLES ************************************************************/
15 
16 PVOID BfiCachedStrikeData;
17 LIST_ENTRY BfiDeferredListHead;
18 LIST_ENTRY BfiFontFileListHead;
19 PVOID BfiGraphicsRectangle;
20 
21 ULONG ConsoleGraphicalResolutionListFlags;
22 BL_DISPLAY_MODE ConsoleGraphicalResolutionList[3] =
23 {
24     {1024, 768, 1024},
25     {800, 600, 800},
26     {1024, 600, 1024}
27 };
28 ULONG ConsoleGraphicalResolutionListSize = RTL_NUMBER_OF(ConsoleGraphicalResolutionList);
29 
30 BL_DISPLAY_MODE ConsoleTextResolutionList[1] =
31 {
32     {80, 25, 80}
33 };
34 
35 PVOID DspRemoteInputConsole;
36 PVOID DspTextConsole;
37 PVOID DspGraphicalConsole;
38 PVOID DspLocalInputConsole;
39 
40 /* FUNCTIONS *****************************************************************/
41 
42 BOOLEAN
43 DsppGraphicsDisabledByBcd (
44     VOID
45     )
46 {
47     BOOLEAN Disabled;
48     NTSTATUS Status;
49 
50     /* Get the boot option, and if present, return the result */
51     Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
52                                     BcdLibraryBoolean_GraphicsModeDisabled,
53                                     &Disabled);
54     return (NT_SUCCESS(Status) && (Disabled));
55 }
56 
57 NTSTATUS
58 DsppLoadFontFile (
59     _In_ PWCHAR FontFileName
60     )
61 {
62     PBL_DEVICE_DESCRIPTOR FontDevice;
63     NTSTATUS Status;
64     ULONG NameLength, DirectoryLength, TotalLength;
65     PWCHAR FontPath, FontDirectory;
66     BL_LIBRARY_PARAMETERS LibraryParameters;
67     BOOLEAN CustomDirectory, CustomDevice;
68 
69     /* Initialize locals */
70     CustomDirectory = TRUE;
71     CustomDevice = TRUE;
72     FontDevice = NULL;
73     FontPath = NULL;
74     FontDirectory = NULL;
75 
76     /* Check if a custom font path should be used */
77     Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
78                                    BcdLibraryString_FontPath,
79                                    &FontDirectory);
80     if (!NT_SUCCESS(Status))
81     {
82         /* Nope, use the one configured by the library */
83         CustomDirectory = FALSE;
84         RtlCopyMemory(&LibraryParameters,
85                       &BlpLibraryParameters,
86                       sizeof(LibraryParameters)),
87         FontDirectory = LibraryParameters.FontBaseDirectory;
88     }
89 
90     /* Do we still not have a font directory? */
91     if (!FontDirectory)
92     {
93         /* Use the boot device and boot directory */
94         FontDevice = BlpBootDevice;
95         FontDirectory = L"\\EFI\\Microsoft\\Boot\\Fonts";
96         CustomDevice = FALSE;
97     }
98     else
99     {
100         /* Otherwise, if we have a font directory, what device is the app on? */
101         Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
102                                        BcdLibraryDevice_ApplicationDevice,
103                                        &FontDevice,
104                                        NULL);
105         if (!NT_SUCCESS(Status))
106         {
107             /* If we don't know the device, we can't open the path */
108             goto Quickie;
109         }
110     }
111 
112     /* Figure out the length of the file name, and of the directory */
113     NameLength = wcslen(FontFileName);
114     DirectoryLength = wcslen(FontDirectory);
115 
116     /* Safely add them up*/
117     Status = RtlULongAdd(NameLength, DirectoryLength, &TotalLength);
118     if (!NT_SUCCESS(Status))
119     {
120         goto Quickie;
121     }
122 
123     /* Convert to bytes */
124     Status = RtlULongLongToULong(TotalLength * sizeof(WCHAR), &TotalLength);
125     if (!NT_SUCCESS(Status))
126     {
127         goto Quickie;
128     }
129 
130     /* Add a terminating NUL */
131     Status = RtlULongAdd(TotalLength, sizeof(UNICODE_NULL), &TotalLength);
132     if (!NT_SUCCESS(Status))
133     {
134         goto Quickie;
135     }
136 
137     /* Allocate the final buffer for it */
138     FontPath = BlMmAllocateHeap(TotalLength);
139     if (!FontPath)
140     {
141         Status = STATUS_NO_MEMORY;
142         goto Quickie;
143     }
144 
145     /* Concatenate the directory with the file name */
146     wcscpy(FontPath, FontDirectory);
147     wcscat(FontPath, FontFileName);
148 
149     /* Try to load this font */
150     Status = BfLoadFontFile(FontDevice, FontPath);
151 
152 Quickie:
153     /* Check if we had a custom font device allocated and free it */
154     if ((CustomDevice) && (FontDevice))
155     {
156         BlMmFreeHeap(FontDevice);
157     }
158 
159     /* Check if we had a custom font directory allocated and free it */
160     if ((FontDirectory) && (CustomDirectory))
161     {
162         BlMmFreeHeap(FontDirectory);
163     }
164 
165     /* Check if we had allocated a font path and free it */
166     if (FontPath)
167     {
168         BlMmFreeHeap(FontPath);
169     }
170 
171     /* Return back */
172     return Status;
173 }
174 
175 NTSTATUS
176 BlpDisplayRegisterLocale (
177     _In_ PWCHAR Locale
178     )
179 {
180     BOOLEAN StandardLocale;
181     NTSTATUS Status;
182     PWCHAR FontFileName;
183     PBL_DEFERRED_FONT_FILE DeferredFont;
184     PLIST_ENTRY NextEntry;
185     WCHAR Prefix[3];
186 
187     /* Assume custom locale */
188     StandardLocale = FALSE;
189 
190     /* Bail out if the locale string seems invalid */
191     if (wcslen(Locale) < 2)
192     {
193         return STATUS_INVALID_PARAMETER;
194     }
195 
196     /* Check the prefix first, then traditional vs. simplified */
197     Prefix[0] = Locale[0];
198     Prefix[1] = Locale[1];
199     Prefix[2] = UNICODE_NULL;
200     if (!_wcsicmp(Prefix, L"ja"))
201     {
202         FontFileName = L"\\jpn_boot.ttf";
203     }
204     else if (!_wcsicmp(Prefix, L"ko"))
205     {
206         FontFileName = L"\\kor_boot.ttf";
207     }
208     else if (!(_wcsicmp(Locale, L"zh-CN")) ||
209              !(_wcsicmp(Locale, L"zh-CHS")) ||
210              !(_wcsicmp(Locale, L"zh-Hans")))
211     {
212         FontFileName = L"\\chs_boot.ttf";
213     }
214     else if (!(_wcsicmp(Locale, L"zh-TW")) &&
215              !(_wcsicmp(Locale, L"zh-CHT")) &&
216              !(_wcsicmp(Locale, L"zh-HK")) &&
217              !(_wcsicmp(Locale, L"zh-Hant")))
218     {
219         FontFileName = L"\\cht_boot.ttf";
220     }
221     else
222     {
223         StandardLocale = TRUE;
224         FontFileName = L"\\wgl4_boot.ttf";
225     }
226 
227     /* Parse all the currently deferred fonts*/
228     NextEntry = BfiDeferredListHead.Flink;
229     while (NextEntry != &BfiDeferredListHead)
230     {
231         /* Grab the font */
232         DeferredFont = CONTAINING_RECORD(NextEntry, BL_DEFERRED_FONT_FILE, ListEntry);
233 
234         /* Move to the next entry, and remove this one */
235         NextEntry = NextEntry->Flink;
236         RemoveEntryList(&DeferredFont->ListEntry);
237 
238         /* Free the deferred font, we'll be loading a new one */
239         BfiFreeDeferredFontFile(DeferredFont);
240     }
241 
242     /* Load the primary font */
243     Status = DsppLoadFontFile(FontFileName);
244     if (NT_SUCCESS(Status) && !(StandardLocale))
245     {
246         /* Also load the standard US one if we loaded a different one */
247         Status = DsppLoadFontFile(L"\\wgl4_boot.ttf");
248     }
249 
250     /* Return back to caller */
251     return Status;
252 }
253 
254 NTSTATUS
255 DsppInitialize (
256     _In_ ULONG Flags
257     )
258 {
259     BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
260     BOOLEAN NoGraphics, HighestMode;
261     NTSTATUS Status;
262     PBL_DISPLAY_MODE DisplayMode;
263     ULONGLONG GraphicsResolution;
264     PBL_GRAPHICS_CONSOLE GraphicsConsole;
265     PBL_TEXT_CONSOLE TextConsole, RemoteConsole;
266 
267     /* Initialize font data */
268     BfiCachedStrikeData = 0;
269     InitializeListHead(&BfiDeferredListHead);
270     InitializeListHead(&BfiFontFileListHead);
271 
272     /* Allocate the font rectangle */
273     BfiGraphicsRectangle = BlMmAllocateHeap(90);
274     if (!BfiGraphicsRectangle)
275     {
276         return STATUS_NO_MEMORY;
277     }
278 
279     /* Check if display re-initialization is requested */
280     if (LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL)
281     {
282         /* Recreate a local input console */
283         ConsoleCreateLocalInputConsole();
284     }
285 
286     /* Check if no graphics console is needed */
287     if ((Flags & BL_LIBRARY_FLAG_NO_GRAPHICS_CONSOLE) ||
288         (DsppGraphicsDisabledByBcd()))
289     {
290         /* Remember this */
291         NoGraphics = TRUE;
292     }
293     else
294     {
295         /* No graphics -- remember this */
296         NoGraphics = FALSE;
297     }
298 
299     /* On first load, we always initialize a graphics display */
300     GraphicsConsole = NULL;
301     if (!(Flags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) || !(NoGraphics))
302     {
303         /* Default to mode 0 (1024x768) */
304         DisplayMode = &ConsoleGraphicalResolutionList[0];
305 
306         /* Check what resolution to use*/
307         Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
308                                         BcdLibraryInteger_GraphicsResolution,
309                                         &GraphicsResolution);
310         if (NT_SUCCESS(Status))
311         {
312             ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
313             EfiPrintf(L"Display selection not yet handled\r\n");
314             return STATUS_NOT_IMPLEMENTED;
315         }
316 
317         /* Check if the highest mode should be forced */
318         Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
319                                         BcdLibraryBoolean_GraphicsForceHighestMode,
320                                         &HighestMode);
321         if (NT_SUCCESS(Status))
322         {
323             ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
324             EfiPrintf(L"High res mode not yet handled\r\n");
325             return STATUS_NOT_IMPLEMENTED;
326         }
327 
328         /* Do we need graphics mode after all? */
329         if (!NoGraphics)
330         {
331             /* Yep -- go allocate it */
332             GraphicsConsole = BlMmAllocateHeap(sizeof(*GraphicsConsole));
333             if (GraphicsConsole)
334             {
335                 /* Construct it */
336                 Status = ConsoleGraphicalConstruct(GraphicsConsole);
337                 if (!NT_SUCCESS(Status))
338                 {
339                     EfiPrintf(L"GFX FAILED: %lx\r\n", Status);
340                     BlMmFreeHeap(GraphicsConsole);
341                     GraphicsConsole = NULL;
342                 }
343             }
344         }
345 
346         /* Are we using something else than the default mode? */
347         if (DisplayMode != &ConsoleGraphicalResolutionList[0])
348         {
349             EfiPrintf(L"Display path not handled\r\n");
350             return STATUS_NOT_SUPPORTED;
351         }
352 
353         /* Mask out all the flags now */
354         ConsoleGraphicalResolutionListFlags &= ~(BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG |
355                                                  BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG);
356     }
357 
358     /* Do we have a graphics console? */
359     TextConsole = NULL;
360     if (!GraphicsConsole)
361     {
362         /* Nope -- go allocate a text console */
363         TextConsole = BlMmAllocateHeap(sizeof(*TextConsole));
364         if (TextConsole)
365         {
366             /* Construct it */
367             Status = ConsoleTextLocalConstruct(TextConsole, TRUE);
368             if (!NT_SUCCESS(Status))
369             {
370                 BlMmFreeHeap(TextConsole);
371                 TextConsole = NULL;
372             }
373         }
374     }
375 
376     /* Initialize all globals to NULL */
377     DspRemoteInputConsole = NULL;
378     DspTextConsole = NULL;
379     DspGraphicalConsole = NULL;
380 
381     /* If we don't have a text console, go get a remote console */
382     RemoteConsole = NULL;
383     if (!TextConsole)
384     {
385         ConsoleCreateRemoteConsole(&RemoteConsole);
386     }
387 
388     /* Do we have a remote console? */
389     if (!RemoteConsole)
390     {
391         /* Nope -- what about a graphical one? */
392         if (GraphicsConsole)
393         {
394             /* Yes, use it for both graphics and text */
395             DspGraphicalConsole = GraphicsConsole;
396             DspTextConsole = GraphicsConsole;
397         }
398         else if (TextConsole)
399         {
400             /* Nope, but we have a text console */
401             DspTextConsole = TextConsole;
402         }
403 
404         /* Console has been setup */
405         return STATUS_SUCCESS;
406     }
407 
408     /* We have a remote console -- have to figure out how to use it*/
409     EfiPrintf(L"Display path not handled\r\n");
410     return STATUS_NOT_SUPPORTED;
411 }
412 
413 NTSTATUS
414 DsppReinitialize (
415     _In_ ULONG Flags
416     )
417 {
418     PBL_TEXT_CONSOLE TextConsole;
419     PBL_GRAPHICS_CONSOLE GraphicsConsole;
420     NTSTATUS Status;
421     ULONGLONG GraphicsResolution;
422     BOOLEAN HighestMode;
423     BL_DISPLAY_MODE CurrentResolution;
424 
425     /* Do we have local input yet? */
426     if (!DspLocalInputConsole)
427     {
428         /* Create it now */
429         ConsoleCreateLocalInputConsole();
430     }
431 
432     /* If a graphics console is present without a remote console... */
433     TextConsole = NULL;
434     if (!(DspRemoteInputConsole) && (DspGraphicalConsole))
435     {
436         /* Try to create a remote console */
437         ConsoleCreateRemoteConsole(&TextConsole);
438     }
439 
440     /* All good for now */
441     Status = STATUS_SUCCESS;
442 
443     /* Now check if we were able to create the remote console */
444     if (TextConsole)
445     {
446         EfiPrintf(L"EMS not supported\r\n");
447         return STATUS_NOT_IMPLEMENTED;
448     }
449 
450     /* Set a local for the right cast */
451     GraphicsConsole = DspGraphicalConsole;
452 
453     /* Nothing to do without a graphics console being reinitialized */
454     if (!(Flags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) ||
455         !(GraphicsConsole) ||
456         !(((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole)))
457     {
458         return Status;
459     }
460 
461     /* Check if graphics are disabled in the BCD */
462     if (DsppGraphicsDisabledByBcd())
463     {
464         /* Turn off the graphics console, switching back to text mode */
465         Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->Enable(GraphicsConsole, FALSE);
466     }
467 
468     /* Check if a custom graphics resolution is set */
469     if (MiscGetBootOption(BlpApplicationEntry.BcdData,
470                           BcdLibraryInteger_GraphicsResolution))
471     {
472         /* Check what it's set to */
473         Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
474                                         BcdLibraryInteger_GraphicsResolution,
475                                         &GraphicsResolution);
476         if (!NT_SUCCESS(Status))
477         {
478             return Status;
479         }
480 
481         /* Now check our current graphical resolution */
482         Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetGraphicalResolution(GraphicsConsole,
483                                                                                                                &CurrentResolution);
484         if (!NT_SUCCESS(Status))
485         {
486             return Status;
487         }
488 
489         /* Remember that we're forcing a video mode */
490         ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
491 
492         /* Check which resolution to set */
493         if (!GraphicsResolution)
494         {
495             /* 1024x768 */
496             EfiPrintf(L"Display selection not yet handled\r\n");
497             return STATUS_NOT_IMPLEMENTED;
498         }
499         else if (GraphicsResolution == 1)
500         {
501             /* 800x600 */
502             EfiPrintf(L"Display selection not yet handled\r\n");
503             return STATUS_NOT_IMPLEMENTED;
504         }
505         else if (GraphicsResolution == 2)
506         {
507             /* 1024x600 */
508             EfiPrintf(L"Display selection not yet handled\r\n");
509             return STATUS_NOT_IMPLEMENTED;
510         }
511     }
512 
513     /* Check if the force highest mode setting is present */
514     if (MiscGetBootOption(BlpApplicationEntry.BcdData,
515                           BcdLibraryBoolean_GraphicsForceHighestMode))
516     {
517         /* Check what it's set to */
518         Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
519                                         BcdLibraryBoolean_GraphicsForceHighestMode,
520                                         &HighestMode);
521         if ((NT_SUCCESS(Status)) && (HighestMode))
522         {
523             /* Remember that high rest mode is being forced */
524             ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
525 
526             /* Turn it on */
527             //((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->SetGraphicalResolution(GraphicsConsole, 0, 0);
528 
529             /* All done now */
530             ConsoleGraphicalResolutionListFlags |= ~BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
531             EfiPrintf(L"High res mode not yet handled\r\n");
532             Status = STATUS_NOT_IMPLEMENTED;
533         }
534     }
535 
536     /* Return back to the caller */
537     return Status;
538 }
539 
540 NTSTATUS
541 BlpDisplayReinitialize (
542     VOID
543     )
544 {
545     NTSTATUS Status = STATUS_SUCCESS;
546     PBL_TEXT_CONSOLE TextConsole;
547     PBL_INPUT_CONSOLE InputConsole;
548 
549     /* Do we have a local console? */
550     InputConsole = DspLocalInputConsole;
551     if (InputConsole)
552     {
553         /* Reinitialize it */
554         Status = InputConsole->Callbacks->Reinitialize((PBL_TEXT_CONSOLE)InputConsole);
555         if (!NT_SUCCESS(Status))
556         {
557             return Status;
558         }
559     }
560 
561     /* Do we have a text console? */
562     TextConsole = DspTextConsole;
563     if (TextConsole)
564     {
565         /* Reinitialize it */
566         Status = TextConsole->Callbacks->Reinitialize(TextConsole);
567     }
568 
569     /* Return status */
570     return Status;
571 }
572 
573 NTSTATUS
574 BlpDisplayInitialize (
575     _In_ ULONG Flags
576     )
577 {
578     NTSTATUS Status;
579 
580     /* Are we resetting or initializing? */
581     if (Flags & BL_LIBRARY_FLAG_REINITIALIZE)
582     {
583         /* This is a reset */
584         Status = DsppReinitialize(Flags);
585         if (NT_SUCCESS(Status))
586         {
587             /* Re-initialize the class as well */
588             Status = BlpDisplayReinitialize();
589         }
590     }
591     else
592     {
593         /* Initialize the display */
594         Status = DsppInitialize(Flags);
595     }
596 
597     /* Return display initialization state */
598     return Status;
599 }
600 
601 VOID
602 BlDisplayGetTextCellResolution (
603     _Out_ PULONG TextWidth,
604     _Out_ PULONG TextHeight
605     )
606 {
607     NTSTATUS Status;
608     PBL_GRAPHICS_CONSOLE GraphicsConsole;
609 
610     /* If the caller doesn't want anything, bail out */
611     if (!(TextWidth) || !(TextHeight))
612     {
613         return;
614     }
615 
616     /* Do we have a text console? */
617     Status = STATUS_UNSUCCESSFUL;
618     if (DspTextConsole)
619     {
620         /* Do we have a graphics console? */
621         GraphicsConsole = DspGraphicalConsole;
622         if (GraphicsConsole)
623         {
624             /* Is it currently active? */
625             if (((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole))
626             {
627                 /* Yep -- query it */
628                 EfiPrintf(L"GFX active, not supported query\r\n");
629                 Status = STATUS_NOT_IMPLEMENTED;
630                 //Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetTextCellResolution(GraphicsConsole);
631             }
632         }
633     }
634 
635     /* Check if we failed to get it from the graphics console */
636     if (!NT_SUCCESS(Status))
637     {
638         /* Set default text size */
639         *TextWidth = 8;
640         *TextHeight = 8;
641     }
642 }
643 
644 NTSTATUS
645 BlDisplaySetScreenResolution (
646     VOID
647     )
648 {
649     PBL_GRAPHICS_CONSOLE Console;
650     NTSTATUS Status;
651 
652     /* Assume success */
653     Status = STATUS_SUCCESS;
654 
655     /* Do we have a graphics console? */
656     Console = DspGraphicalConsole;
657     if (Console)
658     {
659         /* Is it currently active? */
660         if (((PBL_GRAPHICS_CONSOLE_VTABLE)Console->TextConsole.Callbacks)->IsEnabled(Console))
661         {
662             /* If so, disable it */
663             return ((PBL_GRAPHICS_CONSOLE_VTABLE)Console->TextConsole.Callbacks)->Enable(Console, FALSE);
664         }
665     }
666 
667     /* We should've now fallen back to text mode */
668     if (!DspTextConsole)
669     {
670         /* Then fail, as no display appears active */
671         Status = STATUS_UNSUCCESSFUL;
672     }
673 
674     /* Return back to the caller */
675     return Status;
676 }
677 
678 NTSTATUS
679 BlDisplayGetScreenResolution (
680     _Out_ PULONG HRes,
681     _Out_ PULONG VRes
682     )
683 {
684     NTSTATUS Status;
685     BL_DISPLAY_MODE Resolution;
686     PBL_GRAPHICS_CONSOLE GraphicsConsole;
687 
688     /* Assume failure if no consoles are active */
689     Status = STATUS_UNSUCCESSFUL;
690 
691     /* Do we have a text console? */
692     if (DspTextConsole)
693     {
694         /* Do we have an active graphics console? */
695         GraphicsConsole = DspGraphicalConsole;
696         if ((GraphicsConsole) &&
697             (((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole)))
698         {
699             /* Get the resolution */
700             Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetGraphicalResolution(GraphicsConsole, &Resolution);
701             if (NT_SUCCESS(Status))
702             {
703                 /* Return it back to the caller */
704                 *HRes = Resolution.HRes;
705                 *VRes = Resolution.VRes;
706             }
707         }
708         else
709         {
710             /* Return defaults */
711             *HRes = 640;
712             *VRes = 200;
713             Status = STATUS_SUCCESS;
714         }
715     }
716 
717     /* Return if we got a valid resolution back */
718     return Status;
719 }
720 
721 VOID
722 BlDisplayInvalidateOemBitmap (
723     VOID
724     )
725 {
726     PBGRT_TABLE BgrtTable;
727     NTSTATUS Status;
728 
729     /* Search for the BGRT */
730     Status = BlUtlGetAcpiTable((PVOID*)&BgrtTable, BGRT_SIGNATURE);
731     if (NT_SUCCESS(Status))
732     {
733         /* Mark the bitmap as invalid */
734         BgrtTable->Status &= ~BGRT_STATUS_IMAGE_VALID;
735 
736         /* Unmap the table */
737         BlMmUnmapVirtualAddressEx(BgrtTable, BgrtTable->Header.Length);
738     }
739 }
740 
741 PBITMAP
742 BlDisplayGetOemBitmap (
743     _In_opt_ PCOORD Offsets,
744     _Out_opt_ PULONG Flags
745     )
746 {
747     NTSTATUS Status;
748     ULONG Size;
749     PHYSICAL_ADDRESS PhysicalAddress;
750     PBGRT_TABLE BgrtTable;
751     PBITMAP Bitmap;
752     PBMP_HEADER Header;
753 
754     Bitmap = NULL;
755     BgrtTable = NULL;
756 
757     /* Search for the BGRT */
758     Status = BlUtlGetAcpiTable((PVOID*)&BgrtTable, BGRT_SIGNATURE);
759     if (!NT_SUCCESS(Status))
760     {
761         goto Quickie;
762     }
763 
764     /* Make sure this is really a BGRT */
765     if (BgrtTable->Header.Signature != BGRT_SIGNATURE)
766     {
767         Status = STATUS_ACPI_INVALID_TABLE;
768         goto Quickie;
769     }
770 
771     /* Make sure the BGRT table length is valid */
772     if (BgrtTable->Header.Length != sizeof(*BgrtTable))
773     {
774         Status = STATUS_ACPI_INVALID_TABLE;
775         goto Quickie;
776     }
777 
778     /* Make sure its a bitmap */
779     if (BgrtTable->ImageType != BgrtImageTypeBitmap)
780     {
781         Status = STATUS_ACPI_INVALID_TABLE;
782         goto Quickie;
783     }
784 
785     /* Make sure it's somewhere in RAM */
786     if (!BgrtTable->LogoAddress)
787     {
788         Status = STATUS_ACPI_INVALID_TABLE;
789         goto Quickie;
790     }
791 
792     /* Map the bitmap header only for now */
793     PhysicalAddress.QuadPart = BgrtTable->LogoAddress;
794     Status = BlMmMapPhysicalAddressEx((PVOID*)&Header,
795                                       0,
796                                       sizeof(BMP_HEADER),
797                                       PhysicalAddress);
798     if (!NT_SUCCESS(Status))
799     {
800         goto Quickie;
801     }
802 
803     /* Capture the real size of the header */
804     Size = Header->Size;
805 
806     /* Unmap the bitmap header */
807     BlMmUnmapVirtualAddressEx(BgrtTable, sizeof(BMP_HEADER));
808 
809     /* If the real size is smaller than at least a V3 bitmap, bail out */
810     if (Size < sizeof(BITMAP))
811     {
812         Status = STATUS_ACPI_INVALID_TABLE;
813         goto Quickie;
814     }
815 
816     /* Map the real size of the header */
817     Status = BlMmMapPhysicalAddressEx((PVOID*)&Bitmap,
818                                       0,
819                                       Size,
820                                       PhysicalAddress);
821     if (!NT_SUCCESS(Status))
822     {
823         goto Quickie;
824     }
825 
826     /* Make sure this is a non-compressed 24-bit or 32-bit V3 bitmap */
827     if ((Bitmap->BmpHeader.Signature != 'MB') ||
828         (Bitmap->DibHeader.Compression) ||
829         ((Bitmap->DibHeader.BitCount != 24) &&
830          (Bitmap->DibHeader.BitCount != 32)) ||
831         (Bitmap->DibHeader.Size != sizeof(DIB_HEADER)))
832     {
833         Status = STATUS_ACPI_INVALID_TABLE;
834         goto Quickie;
835     }
836 
837     /* Check if caller wants the offsets back */
838     if (Offsets)
839     {
840         /* Give them away */
841         Offsets->X = BgrtTable->OffsetX;
842         Offsets->Y = BgrtTable->OffsetY;
843     }
844 
845     /* Check if the caller wants flags */
846     if (Flags)
847     {
848         /* Return if the image is valid */
849         *Flags = BgrtTable->Status & BGRT_STATUS_IMAGE_VALID;
850     }
851 
852 Quickie:
853     /* Check if we had mapped the BGRT */
854     if (BgrtTable)
855     {
856         /* Unmap it */
857         BlMmUnmapVirtualAddressEx(BgrtTable, BgrtTable->Header.Length);
858     }
859 
860     /* Check if this is the failure path */
861     if (!NT_SUCCESS(Status))
862     {
863         /* Did we have the OEM bitmap mapped? */
864         if (Bitmap)
865         {
866             /* Unmap it */
867             BlMmUnmapVirtualAddressEx(Bitmap, Bitmap->BmpHeader.Size);
868         }
869 
870         /* No bitmap to return */
871         Bitmap = NULL;
872     }
873 
874     /* Return the bitmap back, if any */
875     return Bitmap;
876 }
877 
878 BOOLEAN
879 BlDisplayValidOemBitmap (
880     VOID
881     )
882 {
883     PBITMAP Bitmap;
884     ULONG HRes, VRes, Height, Width, Flags;
885     COORD Offsets;
886     BOOLEAN Result;
887     NTSTATUS Status;
888 
889     /* First check if mobile graphics are enabled */
890     Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
891                                     BcdLibraryBoolean_MobileGraphics,
892                                     &Result);
893     if ((NT_SUCCESS(Status)) && (Result))
894     {
895         /* Yes, so use the firmware image */
896         return TRUE;
897     }
898 
899     /* Nope, so we'll check the ACPI OEM bitmap */
900     Result = FALSE;
901     Bitmap = BlDisplayGetOemBitmap(&Offsets, &Flags);
902 
903     /* Is there one? */
904     if (Bitmap)
905     {
906         /* Is it valid? */
907         if (Flags & BGRT_STATUS_IMAGE_VALID)
908         {
909             /* Get the current screen resolution */
910             Status = BlDisplayGetScreenResolution(&HRes, &VRes);
911             if (NT_SUCCESS(Status))
912             {
913                 /* Is there a valid width? */
914                 Width = Bitmap->DibHeader.Width;
915                 if (Width)
916                 {
917                     /* Is there a valid height? */
918                     Height = Bitmap->DibHeader.Height;
919                     if (Height)
920                     {
921                         /* Will if fit on this screen? */
922                         if (((Width + Offsets.X) <= HRes) &&
923                             ((Height + Offsets.Y) <= VRes))
924                         {
925                             /* Then it's all good! */
926                             Result = TRUE;
927                         }
928                     }
929                 }
930             }
931         }
932 
933         /* Unmap the bitmap for now, it will be drawn later */
934         BlMmUnmapVirtualAddressEx(Bitmap, Bitmap->BmpHeader.Size);
935     }
936 
937     /* Return that a valid OEM bitmap exists */
938     return Result;
939 }
940 
941 NTSTATUS
942 BlDisplayClearScreen (
943     VOID
944     )
945 {
946     NTSTATUS Status;
947     PBL_TEXT_CONSOLE TextConsole;
948 
949     /* Nothing to do if there's no text console */
950     Status = STATUS_SUCCESS;
951     TextConsole = DspTextConsole;
952     if (TextConsole)
953     {
954         /* Otherwise, clear the whole screen */
955         Status = TextConsole->Callbacks->ClearText(TextConsole, FALSE);
956         if (NT_SUCCESS(Status))
957         {
958             /* Invalidate the OEM bitmap at this point */
959             BlDisplayInvalidateOemBitmap();
960         }
961     }
962 
963     /* All done */
964     return Status;
965 };
966 
967 NTSTATUS
968 BlDisplaySetCursorType (
969     _In_ ULONG Type
970     )
971 {
972     NTSTATUS Status;
973     PBL_TEXT_CONSOLE TextConsole;
974     BL_DISPLAY_STATE State;
975 
976     /* Nothing to do if there's no text console */
977     Status = STATUS_SUCCESS;
978     TextConsole = DspTextConsole;
979     if (TextConsole)
980     {
981         /* Write visibility state and call the function to change it */
982         State.CursorVisible = Type;
983         Status = TextConsole->Callbacks->SetTextState(TextConsole, 8, &State);
984     }
985 
986     /* All done */
987     return Status;
988 }
989