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