xref: /reactos/ntoskrnl/inbv/inbv.c (revision 7fff216b)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     BSD - See COPYING.ARM in the top level directory
4  * PURPOSE:     Boot Video Driver support
5  * COPYRIGHT:   Copyright 2007 Alex Ionescu (alex.ionescu@reactos.org)
6  *              Copyright 2010 Aleksey Bragin (aleksey@reactos.org)
7  *              Copyright 2015-2022 Hermès Bélusca-Maïto
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include "inbv/logo.h"
14 
15 /* GLOBALS *******************************************************************/
16 
17 /*
18  * Enable this define if you want Inbv to use coloured headless mode.
19  */
20 // #define INBV_HEADLESS_COLORS
21 
22 typedef struct _INBV_PROGRESS_STATE
23 {
24     ULONG Floor;
25     ULONG Ceiling;
26     ULONG Bias;
27 } INBV_PROGRESS_STATE;
28 
29 typedef struct _BT_PROGRESS_INDICATOR
30 {
31     ULONG Count;
32     ULONG Expected;
33     ULONG Percentage;
34 } BT_PROGRESS_INDICATOR, *PBT_PROGRESS_INDICATOR;
35 
36 static KSPIN_LOCK BootDriverLock;
37 static KIRQL InbvOldIrql;
38 static INBV_DISPLAY_STATE InbvDisplayState = INBV_DISPLAY_STATE_DISABLED;
39 BOOLEAN InbvBootDriverInstalled = FALSE;
40 static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
41 
42 static BOOLEAN InbvDisplayDebugStrings = FALSE;
43 static INBV_DISPLAY_STRING_FILTER InbvDisplayFilter = NULL;
44 
45 ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
46 BOOLEAN ShowProgressBar = FALSE;
47 static INBV_PROGRESS_STATE InbvProgressState;
48 static BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
49 
50 static ULONG ResourceCount = 0;
51 static PUCHAR ResourceList[1 + IDB_MAX_RESOURCES]; // First entry == NULL, followed by 'ResourceCount' entries.
52 
53 
54 /*
55  * Headless terminal text colors
56  */
57 
58 #ifdef INBV_HEADLESS_COLORS
59 
60 // Conversion table CGA to ANSI color index
61 static const UCHAR CGA_TO_ANSI_COLOR_TABLE[16] =
62 {
63     0,  // Black
64     4,  // Blue
65     2,  // Green
66     6,  // Cyan
67     1,  // Red
68     5,  // Magenta
69     3,  // Brown/Yellow
70     7,  // Grey/White
71 
72     60, // Bright Black
73     64, // Bright Blue
74     62, // Bright Green
75     66, // Bright Cyan
76     61, // Bright Red
77     65, // Bright Magenta
78     63, // Bright Yellow
79     67  // Bright Grey (White)
80 };
81 
82 #define CGA_TO_ANSI_COLOR(CgaColor) \
83     CGA_TO_ANSI_COLOR_TABLE[CgaColor & 0x0F]
84 
85 #endif
86 
87 // Default colors: text in white, background in black
88 static ULONG InbvTerminalTextColor = 37;
89 static ULONG InbvTerminalBkgdColor = 40;
90 
91 
92 /* FUNCTIONS *****************************************************************/
93 
94 CODE_SEG("INIT")
95 static
96 PVOID
FindBitmapResource(_In_ PLOADER_PARAMETER_BLOCK LoaderBlock,_In_ ULONG ResourceId)97 FindBitmapResource(
98     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
99     _In_ ULONG ResourceId)
100 {
101     UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
102     UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
103     PLIST_ENTRY NextEntry, ListHead;
104     PLDR_DATA_TABLE_ENTRY LdrEntry;
105     PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
106     LDR_RESOURCE_INFO ResourceInfo;
107     NTSTATUS Status;
108     PVOID Data = NULL;
109 
110     /* Loop the driver list */
111     ListHead = &LoaderBlock->LoadOrderListHead;
112     for (NextEntry = ListHead->Flink;
113          NextEntry != ListHead;
114          NextEntry = NextEntry->Flink)
115     {
116         /* Get the entry */
117         LdrEntry = CONTAINING_RECORD(NextEntry,
118                                      LDR_DATA_TABLE_ENTRY,
119                                      InLoadOrderLinks);
120 
121         /* Check for a match */
122         if (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE) ||
123             RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE))
124         {
125             /* Break out */
126             break;
127         }
128     }
129 
130     /* Check if we found it */
131     if (NextEntry != ListHead)
132     {
133         /* Try to find the resource */
134         ResourceInfo.Type = 2; // RT_BITMAP;
135         ResourceInfo.Name = ResourceId;
136         ResourceInfo.Language = 0;
137         Status = LdrFindResource_U(LdrEntry->DllBase,
138                                    &ResourceInfo,
139                                    RESOURCE_DATA_LEVEL,
140                                    &ResourceDataEntry);
141         if (NT_SUCCESS(Status))
142         {
143             /* Access the resource */
144             ULONG Size = 0;
145             Status = LdrAccessResource(LdrEntry->DllBase,
146                                        ResourceDataEntry,
147                                        &Data,
148                                        &Size);
149             if ((Data) && (ResourceId < 3))
150             {
151                 KiBugCheckData[4] ^= RtlComputeCrc32(0, Data, Size);
152             }
153             if (!NT_SUCCESS(Status)) Data = NULL;
154         }
155     }
156 
157     /* Return the pointer */
158     return Data;
159 }
160 
161 PUCHAR
162 NTAPI
InbvGetResourceAddress(_In_ ULONG ResourceNumber)163 InbvGetResourceAddress(
164     _In_ ULONG ResourceNumber)
165 {
166     /* Validate the resource number */
167     if (ResourceNumber > ResourceCount) return NULL;
168 
169     /* Return the address */
170     return ResourceList[ResourceNumber];
171 }
172 
173 CODE_SEG("INIT")
174 BOOLEAN
175 NTAPI
InbvDriverInitialize(_In_ PLOADER_PARAMETER_BLOCK LoaderBlock,_In_ ULONG Count)176 InbvDriverInitialize(
177     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
178     _In_ ULONG Count)
179 {
180     PCHAR CommandLine;
181     BOOLEAN ResetMode = FALSE; // By default do not reset the video mode
182     ULONG i;
183 
184     /* Quit if we're already installed */
185     if (InbvBootDriverInstalled) return TRUE;
186 
187     /* Initialize the lock and check the current display state */
188     KeInitializeSpinLock(&BootDriverLock);
189     if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
190     {
191         /* Reset the video mode in case we do not have a custom boot logo */
192         CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL);
193         ResetMode   = (CommandLine == NULL) || (strstr(CommandLine, "BOOTLOGO") == NULL);
194     }
195 
196     /* Initialize the video */
197     InbvBootDriverInstalled = VidInitialize(ResetMode);
198     if (InbvBootDriverInstalled)
199     {
200         /* Find bitmap resources in the kernel */
201         ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1);
202         for (i = 1; i <= ResourceCount; i++)
203         {
204             /* Do the lookup */
205             ResourceList[i] = FindBitmapResource(LoaderBlock, i);
206         }
207 
208         /* Set the progress bar ranges */
209         InbvSetProgressBarSubset(0, 100);
210 
211         // BootAnimInitialize(LoaderBlock, Count);
212     }
213 
214     /* Return install state */
215     return InbvBootDriverInstalled;
216 }
217 
218 VOID
219 NTAPI
InbvAcquireLock(VOID)220 InbvAcquireLock(VOID)
221 {
222     KIRQL OldIrql;
223 
224     /* Check if we're at dispatch level or lower */
225     OldIrql = KeGetCurrentIrql();
226     if (OldIrql <= DISPATCH_LEVEL)
227     {
228         /* Loop until the lock is free */
229         while (!KeTestSpinLock(&BootDriverLock));
230 
231         /* Raise IRQL to dispatch level */
232         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
233     }
234 
235     /* Acquire the lock */
236     KiAcquireSpinLock(&BootDriverLock);
237     InbvOldIrql = OldIrql;
238 }
239 
240 VOID
241 NTAPI
InbvReleaseLock(VOID)242 InbvReleaseLock(VOID)
243 {
244     KIRQL OldIrql;
245 
246     /* Capture the old IRQL */
247     OldIrql = InbvOldIrql;
248 
249     /* Release the driver lock */
250     KiReleaseSpinLock(&BootDriverLock);
251 
252     /* If we were at dispatch level or lower, restore the old IRQL */
253     if (InbvOldIrql <= DISPATCH_LEVEL) KeLowerIrql(OldIrql);
254 }
255 
256 VOID
257 NTAPI
InbvEnableBootDriver(_In_ BOOLEAN Enable)258 InbvEnableBootDriver(
259     _In_ BOOLEAN Enable)
260 {
261     /* Check if we're installed */
262     if (InbvBootDriverInstalled)
263     {
264         /* Check for lost state */
265         if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
266 
267         /* Acquire the lock */
268         InbvAcquireLock();
269 
270         /* Cleanup the screen if we own it */
271         if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
272 
273         /* Set the new display state */
274         InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
275                                     INBV_DISPLAY_STATE_DISABLED;
276 
277         /* Release the lock */
278         InbvReleaseLock();
279     }
280     else
281     {
282         /* Set the new display state */
283         InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
284                                     INBV_DISPLAY_STATE_DISABLED;
285     }
286 }
287 
288 VOID
289 NTAPI
InbvAcquireDisplayOwnership(VOID)290 InbvAcquireDisplayOwnership(VOID)
291 {
292     /* Check if we have a callback and we're just acquiring it now */
293     if ((InbvResetDisplayParameters) &&
294         (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
295     {
296         /* Call the callback */
297         InbvResetDisplayParameters(80, 50);
298     }
299 
300     /* Acquire the display */
301     InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
302 }
303 
304 VOID
305 NTAPI
InbvSetDisplayOwnership(_In_ BOOLEAN DisplayOwned)306 InbvSetDisplayOwnership(
307     _In_ BOOLEAN DisplayOwned)
308 {
309     /* Set the new display state */
310     InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED :
311                                       INBV_DISPLAY_STATE_LOST;
312 }
313 
314 BOOLEAN
315 NTAPI
InbvCheckDisplayOwnership(VOID)316 InbvCheckDisplayOwnership(VOID)
317 {
318     /* Return if we own it or not */
319     return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
320 }
321 
322 INBV_DISPLAY_STATE
323 NTAPI
InbvGetDisplayState(VOID)324 InbvGetDisplayState(VOID)
325 {
326     /* Return the actual state */
327     return InbvDisplayState;
328 }
329 
330 BOOLEAN
331 NTAPI
InbvDisplayString(_In_ PCHAR String)332 InbvDisplayString(
333     _In_ PCHAR String)
334 {
335     /* Make sure we own the display */
336     if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
337     {
338         /* If we're not allowed, return success anyway */
339         if (!InbvDisplayDebugStrings) return TRUE;
340 
341         /* Check if a filter is installed */
342         if (InbvDisplayFilter) InbvDisplayFilter(&String);
343 
344         /* Acquire the lock */
345         InbvAcquireLock();
346 
347         /* Make sure we're installed and display the string */
348         if (InbvBootDriverInstalled) VidDisplayString((PUCHAR)String);
349 
350         /* Print the string on the EMS port */
351         HeadlessDispatch(HeadlessCmdPutString,
352                          String,
353                          strlen(String) + sizeof(ANSI_NULL),
354                          NULL,
355                          NULL);
356 
357         /* Release the lock */
358         InbvReleaseLock();
359 
360         /* All done */
361         return TRUE;
362     }
363 
364     /* We don't own it, fail */
365     return FALSE;
366 }
367 
368 BOOLEAN
369 NTAPI
InbvEnableDisplayString(_In_ BOOLEAN Enable)370 InbvEnableDisplayString(
371     _In_ BOOLEAN Enable)
372 {
373     BOOLEAN OldSetting;
374 
375     /* Get the old setting */
376     OldSetting = InbvDisplayDebugStrings;
377 
378     /* Update it */
379     InbvDisplayDebugStrings = Enable;
380 
381     /* Return the old setting */
382     return OldSetting;
383 }
384 
385 VOID
386 NTAPI
InbvInstallDisplayStringFilter(_In_ INBV_DISPLAY_STRING_FILTER DisplayFilter)387 InbvInstallDisplayStringFilter(
388     _In_ INBV_DISPLAY_STRING_FILTER DisplayFilter)
389 {
390     /* Save the filter */
391     InbvDisplayFilter = DisplayFilter;
392 }
393 
394 BOOLEAN
395 NTAPI
InbvIsBootDriverInstalled(VOID)396 InbvIsBootDriverInstalled(VOID)
397 {
398     /* Return driver state */
399     return InbvBootDriverInstalled;
400 }
401 
402 VOID
403 NTAPI
InbvNotifyDisplayOwnershipLost(_In_ INBV_RESET_DISPLAY_PARAMETERS Callback)404 InbvNotifyDisplayOwnershipLost(
405     _In_ INBV_RESET_DISPLAY_PARAMETERS Callback)
406 {
407     /* Check if we're installed */
408     if (InbvBootDriverInstalled)
409     {
410         /* Acquire the lock and cleanup if we own the screen */
411         InbvAcquireLock();
412         if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
413 
414         /* Set the reset callback and display state */
415         InbvResetDisplayParameters = Callback;
416         InbvDisplayState = INBV_DISPLAY_STATE_LOST;
417 
418         /* Release the lock */
419         InbvReleaseLock();
420     }
421     else
422     {
423         /* Set the reset callback and display state */
424         InbvResetDisplayParameters = Callback;
425         InbvDisplayState = INBV_DISPLAY_STATE_LOST;
426     }
427 }
428 
429 BOOLEAN
430 NTAPI
InbvResetDisplay(VOID)431 InbvResetDisplay(VOID)
432 {
433     /* Check if we're installed and we own it */
434     if (InbvBootDriverInstalled &&
435         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
436     {
437         /* Do the reset */
438         VidResetDisplay(TRUE);
439         return TRUE;
440     }
441 
442     /* Nothing to reset */
443     return FALSE;
444 }
445 
446 VOID
447 NTAPI
InbvSetScrollRegion(_In_ ULONG Left,_In_ ULONG Top,_In_ ULONG Right,_In_ ULONG Bottom)448 InbvSetScrollRegion(
449     _In_ ULONG Left,
450     _In_ ULONG Top,
451     _In_ ULONG Right,
452     _In_ ULONG Bottom)
453 {
454     /* Just call bootvid */
455     VidSetScrollRegion(Left, Top, Right, Bottom);
456 }
457 
458 VOID
459 NTAPI
InbvSetTextColor(_In_ ULONG Color)460 InbvSetTextColor(
461     _In_ ULONG Color)
462 {
463     HEADLESS_CMD_SET_COLOR HeadlessSetColor;
464 
465     /* Set color for EMS port */
466 #ifdef INBV_HEADLESS_COLORS
467     InbvTerminalTextColor = 30 + CGA_TO_ANSI_COLOR(Color);
468 #else
469     InbvTerminalTextColor = 37;
470 #endif
471     HeadlessSetColor.TextColor = InbvTerminalTextColor;
472     HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
473     HeadlessDispatch(HeadlessCmdSetColor,
474                      &HeadlessSetColor,
475                      sizeof(HeadlessSetColor),
476                      NULL,
477                      NULL);
478 
479     /* Update the text color */
480     VidSetTextColor(Color);
481 }
482 
483 VOID
484 NTAPI
InbvSolidColorFill(_In_ ULONG Left,_In_ ULONG Top,_In_ ULONG Right,_In_ ULONG Bottom,_In_ ULONG Color)485 InbvSolidColorFill(
486     _In_ ULONG Left,
487     _In_ ULONG Top,
488     _In_ ULONG Right,
489     _In_ ULONG Bottom,
490     _In_ ULONG Color)
491 {
492     HEADLESS_CMD_SET_COLOR HeadlessSetColor;
493 
494     /* Make sure we own it */
495     if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
496     {
497         /* Acquire the lock */
498         InbvAcquireLock();
499 
500         /* Check if we're installed */
501         if (InbvBootDriverInstalled)
502         {
503             /* Call bootvid */
504             VidSolidColorFill(Left, Top, Right, Bottom, (UCHAR)Color);
505         }
506 
507         /* Set color for EMS port and clear display */
508 #ifdef INBV_HEADLESS_COLORS
509         InbvTerminalBkgdColor = 40 + CGA_TO_ANSI_COLOR(Color);
510 #else
511         InbvTerminalBkgdColor = 40;
512 #endif
513         HeadlessSetColor.TextColor = InbvTerminalTextColor;
514         HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
515         HeadlessDispatch(HeadlessCmdSetColor,
516                          &HeadlessSetColor,
517                          sizeof(HeadlessSetColor),
518                          NULL,
519                          NULL);
520         HeadlessDispatch(HeadlessCmdClearDisplay,
521                          NULL, 0,
522                          NULL, NULL);
523 
524         /* Release the lock */
525         InbvReleaseLock();
526     }
527 }
528 
529 VOID
530 NTAPI
InbvBitBlt(_In_ PUCHAR Buffer,_In_ ULONG X,_In_ ULONG Y)531 InbvBitBlt(
532     _In_ PUCHAR Buffer,
533     _In_ ULONG X,
534     _In_ ULONG Y)
535 {
536     /* Check if we're installed and we own it */
537     if (InbvBootDriverInstalled &&
538         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
539     {
540         /* Acquire the lock */
541         InbvAcquireLock();
542 
543         /* Do the blit */
544         VidBitBlt(Buffer, X, Y);
545 
546         /* Release the lock */
547         InbvReleaseLock();
548     }
549 }
550 
551 VOID
552 NTAPI
InbvBufferToScreenBlt(_In_ PUCHAR Buffer,_In_ ULONG X,_In_ ULONG Y,_In_ ULONG Width,_In_ ULONG Height,_In_ ULONG Delta)553 InbvBufferToScreenBlt(
554     _In_ PUCHAR Buffer,
555     _In_ ULONG X,
556     _In_ ULONG Y,
557     _In_ ULONG Width,
558     _In_ ULONG Height,
559     _In_ ULONG Delta)
560 {
561     /* Check if we're installed and we own it */
562     if (InbvBootDriverInstalled &&
563         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
564     {
565         /* Do the blit */
566         VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
567     }
568 }
569 
570 VOID
571 NTAPI
InbvScreenToBufferBlt(_Out_ PUCHAR Buffer,_In_ ULONG X,_In_ ULONG Y,_In_ ULONG Width,_In_ ULONG Height,_In_ ULONG Delta)572 InbvScreenToBufferBlt(
573     _Out_ PUCHAR Buffer,
574     _In_ ULONG X,
575     _In_ ULONG Y,
576     _In_ ULONG Width,
577     _In_ ULONG Height,
578     _In_ ULONG Delta)
579 {
580     /* Check if we're installed and we own it */
581     if (InbvBootDriverInstalled &&
582         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
583     {
584         /* Do the blit */
585         VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
586     }
587 }
588 
589 /**
590  * @brief
591  * Sets the screen coordinates of the loading progress bar and enable it.
592  *
593  * @param[in]   Left
594  * @param[in]   Top
595  * The left/top coordinates.
596  *
597  * @return None.
598  **/
599 VOID
600 NTAPI
InbvSetProgressBarCoordinates(_In_ ULONG Left,_In_ ULONG Top)601 InbvSetProgressBarCoordinates(
602     _In_ ULONG Left,
603     _In_ ULONG Top)
604 {
605     /* Update the coordinates */
606     ProgressBarLeft = Left;
607     ProgressBarTop  = Top;
608 
609     /* Enable the progress bar */
610     ShowProgressBar = TRUE;
611 }
612 
613 /**
614  * @brief
615  * Gives some progress feedback, without specifying any explicit number
616  * of progress steps or percentage.
617  * The corresponding percentage is derived from the progress indicator's
618  * current count, capped to the number of expected calls to be made to
619  * this function (default: 25, see @b InbvProgressIndicator.Expected).
620  *
621  * @return None.
622  **/
623 CODE_SEG("INIT")
624 VOID
625 NTAPI
InbvIndicateProgress(VOID)626 InbvIndicateProgress(VOID)
627 {
628     ULONG Percentage;
629 
630     /* Increase progress */
631     InbvProgressIndicator.Count++;
632 
633     /* Compute the new percentage - Don't go over 100% */
634     Percentage = 100 * InbvProgressIndicator.Count /
635                        InbvProgressIndicator.Expected;
636     Percentage = min(Percentage, 99);
637 
638     if (Percentage != InbvProgressIndicator.Percentage)
639     {
640         /* Percentage has changed, update the progress bar */
641         InbvProgressIndicator.Percentage = Percentage;
642         InbvUpdateProgressBar(Percentage);
643     }
644 }
645 
646 /**
647  * @brief
648  * Specifies a progress percentage sub-range.
649  * Further calls to InbvIndicateProgress() or InbvUpdateProgressBar()
650  * will update the progress percentage relative to this sub-range.
651  * In particular, the percentage provided to InbvUpdateProgressBar()
652  * is relative to this sub-range.
653  *
654  * @param[in]   Floor
655  * The lower bound percentage of the sub-range (default: 0).
656  *
657  * @param[in]   Ceiling
658  * The upper bound percentage of the sub-range (default: 100).
659  *
660  * @return None.
661  **/
662 VOID
663 NTAPI
InbvSetProgressBarSubset(_In_ ULONG Floor,_In_ ULONG Ceiling)664 InbvSetProgressBarSubset(
665     _In_ ULONG Floor,
666     _In_ ULONG Ceiling)
667 {
668     /* Sanity checks */
669     ASSERT(Floor < Ceiling);
670     ASSERT(Ceiling <= 100);
671 
672     /* Update the progress bar state */
673     InbvProgressState.Floor = Floor * 100;
674     InbvProgressState.Ceiling = Ceiling * 100;
675     InbvProgressState.Bias = Ceiling - Floor;
676 }
677 
678 /**
679  * @brief
680  * Updates the progress bar percentage, relative to the current
681  * percentage sub-range previously set by InbvSetProgressBarSubset().
682  *
683  * @param[in]   Percentage
684  * The progress percentage, relative to the current sub-range.
685  *
686  * @return None.
687  **/
688 VOID
689 NTAPI
InbvUpdateProgressBar(_In_ ULONG Percentage)690 InbvUpdateProgressBar(
691     _In_ ULONG Percentage)
692 {
693     ULONG TotalProgress;
694 
695     /* Make sure the progress bar is enabled, that we own and are installed */
696     if (ShowProgressBar &&
697         InbvBootDriverInstalled &&
698         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
699     {
700         /* Compute the total progress and tick the progress bar */
701         TotalProgress = InbvProgressState.Floor + (Percentage * InbvProgressState.Bias);
702         // TotalProgress /= (100 * 100);
703 
704         BootAnimTickProgressBar(TotalProgress);
705     }
706 }
707 
708 NTSTATUS
709 NTAPI
NtDisplayString(IN PUNICODE_STRING DisplayString)710 NtDisplayString(IN PUNICODE_STRING DisplayString)
711 {
712     NTSTATUS Status;
713     UNICODE_STRING CapturedString;
714     OEM_STRING OemString;
715     ULONG OemLength;
716     KPROCESSOR_MODE PreviousMode;
717 
718     PAGED_CODE();
719 
720     PreviousMode = ExGetPreviousMode();
721 
722     /* We require the TCB privilege */
723     if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
724         return STATUS_PRIVILEGE_NOT_HELD;
725 
726     /* Capture the string */
727     Status = ProbeAndCaptureUnicodeString(&CapturedString, PreviousMode, DisplayString);
728     if (!NT_SUCCESS(Status))
729         return Status;
730 
731     /* Do not display the string if it is empty */
732     if (CapturedString.Length == 0 || CapturedString.Buffer == NULL)
733     {
734         Status = STATUS_SUCCESS;
735         goto Quit;
736     }
737 
738     /*
739      * Convert the string since INBV understands only ANSI/OEM. Allocate the
740      * string buffer in non-paged pool because INBV passes it down to BOOTVID.
741      * We cannot perform the allocation using RtlUnicodeStringToOemString()
742      * since its allocator uses PagedPool.
743      */
744     OemLength = RtlUnicodeStringToOemSize(&CapturedString);
745     if (OemLength > MAXUSHORT)
746     {
747         Status = STATUS_BUFFER_OVERFLOW;
748         goto Quit;
749     }
750     RtlInitEmptyAnsiString((PANSI_STRING)&OemString, NULL, (USHORT)OemLength);
751     OemString.Buffer = ExAllocatePoolWithTag(NonPagedPool, OemLength, TAG_OSTR);
752     if (OemString.Buffer == NULL)
753     {
754         Status = STATUS_NO_MEMORY;
755         goto Quit;
756     }
757     Status = RtlUnicodeStringToOemString(&OemString, &CapturedString, FALSE);
758     if (!NT_SUCCESS(Status))
759     {
760         ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
761         goto Quit;
762     }
763 
764     /* Display the string */
765     InbvDisplayString(OemString.Buffer);
766 
767     /* Free the string buffer */
768     ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
769 
770     Status = STATUS_SUCCESS;
771 
772 Quit:
773     /* Free the captured string */
774     ReleaseCapturedUnicodeString(&CapturedString, PreviousMode);
775 
776     return Status;
777 }
778