[FREELDR] Allow Freeloader to boot Vista revamp of PR #1905 (#6479)
[reactos.git] / ntoskrnl / inbv / inbv.c
index 45520c2..006f96a 100644 (file)
@@ -1,9 +1,16 @@
+/*
+ * PROJECT:     ReactOS Kernel
+ * LICENSE:     BSD - See COPYING.ARM in the top level directory
+ * PURPOSE:     Boot Video Driver support
+ * COPYRIGHT:   Copyright 2007 Alex Ionescu (alex.ionescu@reactos.org)
+ *              Copyright 2010 Aleksey Bragin (aleksey@reactos.org)
+ *              Copyright 2015-2022 Hermès Bélusca-Maïto
+ */
+
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-#include "bootvid/bootvid.h"
+#include "inbv/logo.h"
 
 /* GLOBALS *******************************************************************/
 
  */
 // #define INBV_HEADLESS_COLORS
 
-/*
- * ReactOS uses the same boot screen for all the products.
- * Also it doesn't use a parallel system thread for the
- * rotating "progress" bar.
- */
-
-/*
- * Enable this define when ReactOS will have different SKUs
- * (Workstation, Server, Storage Server, Cluster Server, etc...).
- */
-// #define REACTOS_SKUS
+typedef struct _INBV_PROGRESS_STATE
+{
+    ULONG Floor;
+    ULONG Ceiling;
+    ULONG Bias;
+} INBV_PROGRESS_STATE;
 
-/*
- * Enable this define when Inbv will support rotating progress bar.
- */
-#define INBV_ROTBAR_IMPLEMENTED
+typedef struct _BT_PROGRESS_INDICATOR
+{
+    ULONG Count;
+    ULONG Expected;
+    ULONG Percentage;
+} BT_PROGRESS_INDICATOR, *PBT_PROGRESS_INDICATOR;
 
 static KSPIN_LOCK BootDriverLock;
 static KIRQL InbvOldIrql;
 static INBV_DISPLAY_STATE InbvDisplayState = INBV_DISPLAY_STATE_DISABLED;
 BOOLEAN InbvBootDriverInstalled = FALSE;
+static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
+
 static BOOLEAN InbvDisplayDebugStrings = FALSE;
 static INBV_DISPLAY_STRING_FILTER InbvDisplayFilter = NULL;
-static ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
-static BOOLEAN ShowProgressBar = FALSE;
+
+ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
+BOOLEAN ShowProgressBar = FALSE;
 static INBV_PROGRESS_STATE InbvProgressState;
 static BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
-static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
-static ULONG ResourceCount = 0;
-static PUCHAR ResourceList[1 + IDB_MAX_RESOURCE]; // First entry == NULL, followed by 'ResourceCount' entries.
 
-#ifdef INBV_ROTBAR_IMPLEMENTED
-/*
- * Change this to modify progress bar behaviour
- */
-#define ROT_BAR_DEFAULT_MODE  RB_PROGRESS_BAR
-static BOOLEAN RotBarThreadActive = FALSE;
-static ROT_BAR_TYPE RotBarSelection;
-static ULONG PltRotBarStatus;
-static PVOID RotBarThread = NULL;
-static UCHAR RotBarBuffer[24 * 9];
-static UCHAR RotLineBuffer[640 * 6];
-#endif
+static ULONG ResourceCount = 0;
+static PUCHAR ResourceList[1 + IDB_MAX_RESOURCES]; // First entry == NULL, followed by 'ResourceCount' entries.
 
 
 /*
@@ -95,111 +89,14 @@ static ULONG InbvTerminalTextColor = 37;
 static ULONG InbvTerminalBkgdColor = 40;
 
 
-/* FADING FUNCTION ***********************************************************/
-
-/** From include/psdk/wingdi.h **/
-typedef struct tagRGBQUAD
-{
-    UCHAR    rgbBlue;
-    UCHAR    rgbGreen;
-    UCHAR    rgbRed;
-    UCHAR    rgbReserved;
-} RGBQUAD,*LPRGBQUAD;
-/*******************************/
-
-static RGBQUAD MainPalette[16];
-
-#define PALETTE_FADE_STEPS  15
-#define PALETTE_FADE_TIME   20 * 1000 /* 20ms */
-
-/** From bootvid/precomp.h **/
-//
-// Bitmap Header
-//
-typedef struct tagBITMAPINFOHEADER
-{
-    ULONG biSize;
-    LONG biWidth;
-    LONG biHeight;
-    USHORT biPlanes;
-    USHORT biBitCount;
-    ULONG biCompression;
-    ULONG biSizeImage;
-    LONG biXPelsPerMeter;
-    LONG biYPelsPerMeter;
-    ULONG biClrUsed;
-    ULONG biClrImportant;
-} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
-/****************************/
-
-//
-// Needed prototypes
-//
-VOID NTAPI InbvAcquireLock(VOID);
-VOID NTAPI InbvReleaseLock(VOID);
-
-static VOID
-BootLogoFadeIn(VOID)
-{
-    UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)];
-    PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer;
-    LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER));
-
-    ULONG Iteration, Index, ClrUsed;
-
-    /* Check if we're installed and we own it */
-    if (InbvBootDriverInstalled &&
-        (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
-    {
-        /* Acquire the lock */
-        InbvAcquireLock();
-
-        /*
-         * Build a bitmap containing the fade in palette. The palette entries
-         * are then processed in a loop and set using VidBitBlt function.
-         */
-        ClrUsed = RTL_NUMBER_OF(MainPalette);
-        RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER));
-        PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER);
-        PaletteBitmap->biBitCount = 4;
-        PaletteBitmap->biClrUsed = ClrUsed;
-
-        /*
-         * Main animation loop.
-         */
-        for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration)
-        {
-            for (Index = 0; Index < ClrUsed; Index++)
-            {
-                Palette[Index].rgbRed = (UCHAR)
-                    (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS);
-                Palette[Index].rgbGreen = (UCHAR)
-                    (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS);
-                Palette[Index].rgbBlue = (UCHAR)
-                    (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS);
-            }
-
-            VidBitBlt(PaletteBitmapBuffer, 0, 0);
-
-            /* Wait for a bit */
-            KeStallExecutionProcessor(PALETTE_FADE_TIME);
-        }
-
-        /* Release the lock */
-        InbvReleaseLock();
-
-        /* Wait for a bit */
-        KeStallExecutionProcessor(PALETTE_FADE_TIME);
-    }
-}
-
 /* FUNCTIONS *****************************************************************/
 
+CODE_SEG("INIT")
+static
 PVOID
-NTAPI
-INIT_FUNCTION
-FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
-                   IN ULONG ResourceId)
+FindBitmapResource(
+    _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
+    _In_ ULONG ResourceId)
 {
     UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
     UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
@@ -212,8 +109,9 @@ FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
 
     /* Loop the driver list */
     ListHead = &LoaderBlock->LoadOrderListHead;
-    NextEntry = ListHead->Flink;
-    while (NextEntry != ListHead)
+    for (NextEntry = ListHead->Flink;
+         NextEntry != ListHead;
+         NextEntry = NextEntry->Flink)
     {
         /* Get the entry */
         LdrEntry = CONTAINING_RECORD(NextEntry,
@@ -260,11 +158,24 @@ FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
     return Data;
 }
 
+PUCHAR
+NTAPI
+InbvGetResourceAddress(
+    _In_ ULONG ResourceNumber)
+{
+    /* Validate the resource number */
+    if (ResourceNumber > ResourceCount) return NULL;
+
+    /* Return the address */
+    return ResourceList[ResourceNumber];
+}
+
+CODE_SEG("INIT")
 BOOLEAN
 NTAPI
-INIT_FUNCTION
-InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
-                     IN ULONG Count)
+InbvDriverInitialize(
+    _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
+    _In_ ULONG Count)
 {
     PCHAR CommandLine;
     BOOLEAN ResetMode = FALSE; // By default do not reset the video mode
@@ -296,6 +207,8 @@ InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
 
         /* Set the progress bar ranges */
         InbvSetProgressBarSubset(0, 100);
+
+        // BootAnimInitialize(LoaderBlock, Count);
     }
 
     /* Return install state */
@@ -342,8 +255,8 @@ InbvReleaseLock(VOID)
 
 VOID
 NTAPI
-INIT_FUNCTION
-InbvEnableBootDriver(IN BOOLEAN Enable)
+InbvEnableBootDriver(
+    _In_ BOOLEAN Enable)
 {
     /* Check if we're installed */
     if (InbvBootDriverInstalled)
@@ -390,7 +303,8 @@ InbvAcquireDisplayOwnership(VOID)
 
 VOID
 NTAPI
-InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
+InbvSetDisplayOwnership(
+    _In_ BOOLEAN DisplayOwned)
 {
     /* Set the new display state */
     InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED :
@@ -415,7 +329,8 @@ InbvGetDisplayState(VOID)
 
 BOOLEAN
 NTAPI
-InbvDisplayString(IN PCHAR String)
+InbvDisplayString(
+    _In_ PCHAR String)
 {
     /* Make sure we own the display */
     if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
@@ -452,7 +367,8 @@ InbvDisplayString(IN PCHAR String)
 
 BOOLEAN
 NTAPI
-InbvEnableDisplayString(IN BOOLEAN Enable)
+InbvEnableDisplayString(
+    _In_ BOOLEAN Enable)
 {
     BOOLEAN OldSetting;
 
@@ -468,10 +384,11 @@ InbvEnableDisplayString(IN BOOLEAN Enable)
 
 VOID
 NTAPI
-InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
+InbvInstallDisplayStringFilter(
+    _In_ INBV_DISPLAY_STRING_FILTER DisplayFilter)
 {
     /* Save the filter */
-    InbvDisplayFilter = Filter;
+    InbvDisplayFilter = DisplayFilter;
 }
 
 BOOLEAN
@@ -484,7 +401,8 @@ InbvIsBootDriverInstalled(VOID)
 
 VOID
 NTAPI
-InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
+InbvNotifyDisplayOwnershipLost(
+    _In_ INBV_RESET_DISPLAY_PARAMETERS Callback)
 {
     /* Check if we're installed */
     if (InbvBootDriverInstalled)
@@ -527,10 +445,11 @@ InbvResetDisplay(VOID)
 
 VOID
 NTAPI
-InbvSetScrollRegion(IN ULONG Left,
-                    IN ULONG Top,
-                    IN ULONG Right,
-                    IN ULONG Bottom)
+InbvSetScrollRegion(
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG Right,
+    _In_ ULONG Bottom)
 {
     /* Just call bootvid */
     VidSetScrollRegion(Left, Top, Right, Bottom);
@@ -538,7 +457,8 @@ InbvSetScrollRegion(IN ULONG Left,
 
 VOID
 NTAPI
-InbvSetTextColor(IN ULONG Color)
+InbvSetTextColor(
+    _In_ ULONG Color)
 {
     HEADLESS_CMD_SET_COLOR HeadlessSetColor;
 
@@ -562,11 +482,12 @@ InbvSetTextColor(IN ULONG Color)
 
 VOID
 NTAPI
-InbvSolidColorFill(IN ULONG Left,
-                   IN ULONG Top,
-                   IN ULONG Right,
-                   IN ULONG Bottom,
-                   IN ULONG Color)
+InbvSolidColorFill(
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG Right,
+    _In_ ULONG Bottom,
+    _In_ ULONG Color)
 {
     HEADLESS_CMD_SET_COLOR HeadlessSetColor;
 
@@ -607,29 +528,20 @@ InbvSolidColorFill(IN ULONG Left,
 
 VOID
 NTAPI
-INIT_FUNCTION
-InbvUpdateProgressBar(IN ULONG Progress)
+InbvBitBlt(
+    _In_ PUCHAR Buffer,
+    _In_ ULONG X,
+    _In_ ULONG Y)
 {
-    ULONG FillCount, BoundedProgress;
-
-    /* Make sure the progress bar is enabled, that we own and are installed */
-    if (ShowProgressBar &&
-        InbvBootDriverInstalled &&
+    /* Check if we're installed and we own it */
+    if (InbvBootDriverInstalled &&
         (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
     {
-        /* Compute fill count */
-        BoundedProgress = (InbvProgressState.Floor / 100) + Progress;
-        FillCount = 121 * (InbvProgressState.Bias * BoundedProgress) / 1000000;
-
         /* Acquire the lock */
         InbvAcquireLock();
 
-        /* Fill the progress bar */
-        VidSolidColorFill(ProgressBarLeft,
-                          ProgressBarTop,
-                          ProgressBarLeft + FillCount,
-                          ProgressBarTop + 12,
-                          15);
+        /* Do the blit */
+        VidBitBlt(Buffer, X, Y);
 
         /* Release the lock */
         InbvReleaseLock();
@@ -638,12 +550,13 @@ InbvUpdateProgressBar(IN ULONG Progress)
 
 VOID
 NTAPI
-InbvBufferToScreenBlt(IN PUCHAR Buffer,
-                      IN ULONG X,
-                      IN ULONG Y,
-                      IN ULONG Width,
-                      IN ULONG Height,
-                      IN ULONG Delta)
+InbvBufferToScreenBlt(
+    _In_ PUCHAR Buffer,
+    _In_ ULONG X,
+    _In_ ULONG Y,
+    _In_ ULONG Width,
+    _In_ ULONG Height,
+    _In_ ULONG Delta)
 {
     /* Check if we're installed and we own it */
     if (InbvBootDriverInstalled &&
@@ -656,33 +569,13 @@ InbvBufferToScreenBlt(IN PUCHAR Buffer,
 
 VOID
 NTAPI
-InbvBitBlt(IN PUCHAR Buffer,
-           IN ULONG X,
-           IN ULONG Y)
-{
-    /* Check if we're installed and we own it */
-    if (InbvBootDriverInstalled &&
-        (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
-    {
-        /* Acquire the lock */
-        InbvAcquireLock();
-
-        /* Do the blit */
-        VidBitBlt(Buffer, X, Y);
-
-        /* Release the lock */
-        InbvReleaseLock();
-    }
-}
-
-VOID
-NTAPI
-InbvScreenToBufferBlt(IN PUCHAR Buffer,
-                      IN ULONG X,
-                      IN ULONG Y,
-                      IN ULONG Width,
-                      IN ULONG Height,
-                      IN ULONG Delta)
+InbvScreenToBufferBlt(
+    _Out_ PUCHAR Buffer,
+    _In_ ULONG X,
+    _In_ ULONG Y,
+    _In_ ULONG Width,
+    _In_ ULONG Height,
+    _In_ ULONG Delta)
 {
     /* Check if we're installed and we own it */
     if (InbvBootDriverInstalled &&
@@ -693,10 +586,21 @@ InbvScreenToBufferBlt(IN PUCHAR Buffer,
     }
 }
 
+/**
+ * @brief
+ * Sets the screen coordinates of the loading progress bar and enable it.
+ *
+ * @param[in]   Left
+ * @param[in]   Top
+ * The left/top coordinates.
+ *
+ * @return None.
+ **/
 VOID
 NTAPI
-InbvSetProgressBarCoordinates(IN ULONG Left,
-                              IN ULONG Top)
+InbvSetProgressBarCoordinates(
+    _In_ ULONG Left,
+    _In_ ULONG Top)
 {
     /* Update the coordinates */
     ProgressBarLeft = Left;
@@ -706,24 +610,19 @@ InbvSetProgressBarCoordinates(IN ULONG Left,
     ShowProgressBar = TRUE;
 }
 
+/**
+ * @brief
+ * Gives some progress feedback, without specifying any explicit number
+ * of progress steps or percentage.
+ * The corresponding percentage is derived from the progress indicator's
+ * current count, capped to the number of expected calls to be made to
+ * this function (default: 25, see @b InbvProgressIndicator.Expected).
+ *
+ * @return None.
+ **/
+CODE_SEG("INIT")
 VOID
 NTAPI
-InbvSetProgressBarSubset(IN ULONG Floor,
-                         IN ULONG Ceiling)
-{
-    /* Sanity checks */
-    ASSERT(Floor < Ceiling);
-    ASSERT(Ceiling <= 100);
-
-    /* Update the progress bar state */
-    InbvProgressState.Floor = Floor * 100;
-    InbvProgressState.Ceiling = Ceiling * 100;
-    InbvProgressState.Bias = (Ceiling * 100) - Floor;
-}
-
-VOID
-NTAPI
-INIT_FUNCTION
 InbvIndicateProgress(VOID)
 {
     ULONG Percentage;
@@ -731,442 +630,148 @@ InbvIndicateProgress(VOID)
     /* Increase progress */
     InbvProgressIndicator.Count++;
 
-    /* Compute new percentage */
-    Percentage = min(100 * InbvProgressIndicator.Count /
-                           InbvProgressIndicator.Expected,
-                     99);
+    /* Compute the new percentage - Don't go over 100% */
+    Percentage = 100 * InbvProgressIndicator.Count /
+                       InbvProgressIndicator.Expected;
+    Percentage = min(Percentage, 99);
+
     if (Percentage != InbvProgressIndicator.Percentage)
     {
-        /* Percentage has moved, update the progress bar */
+        /* Percentage has changed, update the progress bar */
         InbvProgressIndicator.Percentage = Percentage;
         InbvUpdateProgressBar(Percentage);
     }
 }
 
-PUCHAR
-NTAPI
-InbvGetResourceAddress(IN ULONG ResourceNumber)
-{
-    /* Validate the resource number */
-    if (ResourceNumber > ResourceCount) return NULL;
-
-    /* Return the address */
-    return ResourceList[ResourceNumber];
-}
-
-NTSTATUS
+/**
+ * @brief
+ * Specifies a progress percentage sub-range.
+ * Further calls to InbvIndicateProgress() or InbvUpdateProgressBar()
+ * will update the progress percentage relative to this sub-range.
+ * In particular, the percentage provided to InbvUpdateProgressBar()
+ * is relative to this sub-range.
+ *
+ * @param[in]   Floor
+ * The lower bound percentage of the sub-range (default: 0).
+ *
+ * @param[in]   Ceiling
+ * The upper bound percentage of the sub-range (default: 100).
+ *
+ * @return None.
+ **/
+VOID
 NTAPI
-NtDisplayString(IN PUNICODE_STRING DisplayString)
+InbvSetProgressBarSubset(
+    _In_ ULONG Floor,
+    _In_ ULONG Ceiling)
 {
-    OEM_STRING OemString;
-
-    /* Convert the string to OEM and display it */
-    RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
-    InbvDisplayString(OemString.Buffer);
-    RtlFreeOemString(&OemString);
-
-    /* Return success */
-    return STATUS_SUCCESS;
-}
+    /* Sanity checks */
+    ASSERT(Floor < Ceiling);
+    ASSERT(Ceiling <= 100);
 
-#ifdef INBV_ROTBAR_IMPLEMENTED
-static
+    /* Update the progress bar state */
+    InbvProgressState.Floor = Floor * 100;
+    InbvProgressState.Ceiling = Ceiling * 100;
+    InbvProgressState.Bias = Ceiling - Floor;
+}
+
+/**
+ * @brief
+ * Updates the progress bar percentage, relative to the current
+ * percentage sub-range previously set by InbvSetProgressBarSubset().
+ *
+ * @param[in]   Percentage
+ * The progress percentage, relative to the current sub-range.
+ *
+ * @return None.
+ **/
 VOID
 NTAPI
-InbvRotationThread(
-    _In_ PVOID Context)
+InbvUpdateProgressBar(
+    _In_ ULONG Percentage)
 {
-    ULONG X, Y, Index, Total = 18;
-    LARGE_INTEGER Delay;
+    ULONG TotalProgress;
 
-    InbvAcquireLock();
-    if (RotBarSelection == RB_SQUARE_CELLS)
-    {
-        Delay.QuadPart = -800000; // 0.08 sec
-        Index = 0;
-    }
-    else
-    {
-        Delay.QuadPart = -600000; // 0.06 sec
-        Index = 32;
-    }
-    X = ProgressBarLeft + 2;
-    Y = ProgressBarTop + 2;
-    InbvReleaseLock();
-
-    while (InbvDisplayState == INBV_DISPLAY_STATE_OWNED && PltRotBarStatus != 3)
+    /* Make sure the progress bar is enabled, that we own and are installed */
+    if (ShowProgressBar &&
+        InbvBootDriverInstalled &&
+        (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
     {
-        InbvAcquireLock();
-
-        if (RotBarSelection == RB_SQUARE_CELLS)
-        {
-            if (Index >= 3)
-            {
-                /* Fill previous bar position */
-                VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, 0);
-            }
-            if (Index < Total - 1)
-            {
-                /* Draw the progress bar bit */
-                if (Index < 2)
-                {
-                    /* Appearing from the left */
-                    VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8 * (2 - Index), 9, 24);
-                }
-                else if (Index >= Total - 3)
-                {
-                    /* Hiding to the right */
-                    VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 * (4 - (Total - Index)), 9, 24);
-                }
-                else
-                {
-                    VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9, 24);
-                }
-            }
-            Index = (Index + 1) % Total;
-        }
-        else if (RotBarSelection == RB_PROGRESS_BAR)
-        {
-            /* Right part */
-            VidBufferToScreenBlt(RotLineBuffer, Index, 474, 640 - Index, 6, 640);
-            if (Index > 0)
-            {
-                /* Left part */
-                VidBufferToScreenBlt(RotLineBuffer + (640 - Index) / 2, 0, 474, Index - 2, 6, 640);
-            }
-            Index = (Index + 32) % 640;
-        }
-
-        InbvReleaseLock();
+        /* Compute the total progress and tick the progress bar */
+        TotalProgress = InbvProgressState.Floor + (Percentage * InbvProgressState.Bias);
+        // TotalProgress /= (100 * 100);
 
-        /* Wait for a bit */
-        KeDelayExecutionThread(KernelMode, FALSE, &Delay);
+        BootAnimTickProgressBar(TotalProgress);
     }
-    PsTerminateSystemThread(STATUS_SUCCESS);
 }
 
-VOID
+NTSTATUS
 NTAPI
-INIT_FUNCTION
-InbvRotBarInit(VOID)
+NtDisplayString(IN PUNICODE_STRING DisplayString)
 {
     NTSTATUS Status;
-    HANDLE ThreadHandle = NULL;
+    UNICODE_STRING CapturedString;
+    OEM_STRING OemString;
+    ULONG OemLength;
+    KPROCESSOR_MODE PreviousMode;
 
-    if (!InbvBootDriverInstalled || RotBarSelection == RB_UNSPECIFIED)
-        return;
+    PAGED_CODE();
 
-    RotBarThread = NULL;
-    PltRotBarStatus = 0;
+    PreviousMode = ExGetPreviousMode();
 
-    Status = PsCreateSystemThread(&ThreadHandle,
-                                  SYNCHRONIZE,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  InbvRotationThread,
-                                  NULL);
+    /* We require the TCB privilege */
+    if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+        return STATUS_PRIVILEGE_NOT_HELD;
 
-    if (NT_SUCCESS(Status))
-    {
-        Status = ObReferenceObjectByHandle(ThreadHandle,
-                                           SYNCHRONIZE,
-                                           PsThreadType,
-                                           KernelMode,
-                                           &RotBarThread,
-                                           NULL);
-        if (NT_SUCCESS(Status))
-        {
-            KeSetPriorityThread(RotBarThread, HIGH_PRIORITY);
-            RotBarThreadActive = TRUE;
-        }
-        ObCloseHandle(ThreadHandle, KernelMode);
-    }
-}
+    /* Capture the string */
+    Status = ProbeAndCaptureUnicodeString(&CapturedString, PreviousMode, DisplayString);
+    if (!NT_SUCCESS(Status))
+        return Status;
 
-VOID
-NTAPI
-INIT_FUNCTION
-InbvRotBarStop(VOID)
-{
-    if (!RotBarThread)
+    /* Do not display the string if it is empty */
+    if (CapturedString.Length == 0 || CapturedString.Buffer == NULL)
     {
-        RotBarThreadActive = FALSE;
-        return;
+        Status = STATUS_SUCCESS;
+        goto Quit;
     }
 
-    InbvAcquireLock();
-    PltRotBarStatus = 3;
-    InbvReleaseLock();
-
-    KeWaitForSingleObject(RotBarThread,
-                          Executive,
-                          KernelMode,
-                          FALSE,
-                          NULL);
-    ObDereferenceObject(RotBarThread);
-    RotBarThread = NULL;
-    RotBarThreadActive = FALSE;
-}
-#endif
-
-VOID
-NTAPI
-INIT_FUNCTION
-DisplayBootBitmap(IN BOOLEAN TextMode)
-{
-    PVOID Header = NULL, Footer = NULL, Screen = NULL;
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-    UCHAR Buffer[24 * 9];
-    PVOID Bar = NULL, LineBmp = NULL;
-    ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
-    LARGE_INTEGER Delay;
-#endif
-
-#ifdef REACTOS_SKUS
-    PVOID Text = NULL;
-#endif
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-    /* Check if the system thread has already been created */
-    if (RotBarThreadActive)
+    /*
+     * Convert the string since INBV understands only ANSI/OEM. Allocate the
+     * string buffer in non-paged pool because INBV passes it down to BOOTVID.
+     * We cannot perform the allocation using RtlUnicodeStringToOemString()
+     * since its allocator uses PagedPool.
+     */
+    OemLength = RtlUnicodeStringToOemSize(&CapturedString);
+    if (OemLength > MAXUSHORT)
     {
-        /* Reset the progress bar */
-        InbvRotBarStop();
+        Status = STATUS_BUFFER_OVERFLOW;
+        goto Quit;
     }
-#endif
-
-    ShowProgressBar = FALSE;
-
-    /* Check if this is text mode */
-    if (TextMode)
+    RtlInitEmptyAnsiString((PANSI_STRING)&OemString, NULL, (USHORT)OemLength);
+    OemString.Buffer = ExAllocatePoolWithTag(NonPagedPool, OemLength, TAG_OSTR);
+    if (OemString.Buffer == NULL)
     {
-        /* Check the type of the OS: workstation or server */
-        if (SharedUserData->NtProductType == NtProductWinNt)
-        {
-            /* Workstation; set colors */
-            InbvSetTextColor(15);
-            InbvSolidColorFill(0, 0, 639, 479, 7);
-            InbvSolidColorFill(0, 421, 639, 479, 1);
-
-            /* Get resources */
-            Header = InbvGetResourceAddress(IDB_WKSTA_HEADER);
-            Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER);
-        }
-        else
-        {
-            /* Server; set colors */
-            InbvSetTextColor(14);
-            InbvSolidColorFill(0, 0, 639, 479, 6);
-            InbvSolidColorFill(0, 421, 639, 479, 1);
-
-            /* Get resources */
-            Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
-            Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER);
-        }
-
-        /* Set the scrolling region */
-        InbvSetScrollRegion(32, 80, 631, 400);
-
-        /* Make sure we have resources */
-        if (Header && Footer)
-        {
-            /* BitBlt them on the screen */
-            InbvBitBlt(Footer, 0, 419);
-            InbvBitBlt(Header, 0, 0);
-        }
+        Status = STATUS_NO_MEMORY;
+        goto Quit;
     }
-    else
+    Status = RtlUnicodeStringToOemString(&OemString, &CapturedString, FALSE);
+    if (!NT_SUCCESS(Status))
     {
-        /* Is the boot driver installed? */
-        if (!InbvBootDriverInstalled) return;
-
-        /* Load the standard boot screen */
-        Screen = InbvGetResourceAddress(IDB_BOOT_SCREEN);
-
-#ifdef REACTOS_SKUS
-        Text = NULL;
-        if (SharedUserData->NtProductType == NtProductWinNt)
-        {
-#ifdef INBV_ROTBAR_IMPLEMENTED
-            /* Workstation product, use appropriate status bar color */
-            Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
-#endif
-        }
-        else
-        {
-            /* Display correct branding based on server suite */
-            if (ExVerifySuite(StorageServer))
-            {
-                /* Storage Server Edition */
-                Text = InbvGetResourceAddress(IDB_STORAGE_SERVER);
-            }
-            else if (ExVerifySuite(ComputeServer))
-            {
-                /* Compute Cluster Edition */
-                Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER);
-            }
-            else
-            {
-                /* Normal edition */
-                Text = InbvGetResourceAddress(IDB_SERVER_LOGO);
-            }
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-            /* Server product, use appropriate status bar color */
-            Bar = InbvGetResourceAddress(IDB_BAR_SERVER);
-#endif
-        }
-#else
-        /* Use default status bar */
-        Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
-#endif
-
-        /* Make sure we have a logo */
-        if (Screen)
-        {
-            PBITMAPINFOHEADER BitmapInfoHeader;
-            LPRGBQUAD Palette;
-
-            /*
-             * Save the main image palette and replace it with black palette,
-             * so that we can do fade in effect later.
-             */
-            BitmapInfoHeader = (PBITMAPINFOHEADER)Screen;
-            Palette = (LPRGBQUAD)((PUCHAR)Screen + BitmapInfoHeader->biSize);
-            RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette));
-            RtlZeroMemory(Palette, sizeof(MainPalette));
-
-            /* Blit the background */
-            InbvBitBlt(Screen, 0, 0);
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-            /* Choose progress bar */
-            TempRotBarSelection = ROT_BAR_DEFAULT_MODE;
-#endif
-
-            /* Set progress bar coordinates and display it */
-            InbvSetProgressBarCoordinates(259, 352);
-
-#ifdef REACTOS_SKUS
-            /* Check for non-workstation products */
-            if (SharedUserData->NtProductType != NtProductWinNt)
-            {
-                /* Overwrite part of the logo for a server product */
-                InbvScreenToBufferBlt(Buffer, 413, 237, 7, 7, 8);
-                InbvSolidColorFill(418, 230, 454, 256, 0);
-                InbvBufferToScreenBlt(Buffer, 413, 237, 7, 7, 8);
-
-                /* In setup mode, you haven't selected a SKU yet */
-                if (ExpInTextModeSetup) Text = NULL;
-            }
-#endif
-        }
-
-#ifdef REACTOS_SKUS
-        /* Draw the SKU text if it exits */
-        if (Text) InbvBitBlt(Text, 180, 121);
-#endif
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-        if (Bar)
-        {
-            /* Save previous screen pixels to buffer */
-            InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24);
-            /* Draw the progress bar bit */
-            InbvBitBlt(Bar, 0, 0);
-            /* Store it in global buffer */
-            InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24);
-            /* Restore screen pixels */
-            InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24);
-        }
-
-        LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE);
-        if (LineBmp && TempRotBarSelection == RB_PROGRESS_BAR)
-        {
-            /* Draw the line */
-            InbvBitBlt(LineBmp, 0, 474);
-            /* Store it in global buffer */
-            InbvScreenToBufferBlt(RotLineBuffer, 0, 474, 640, 6, 640);
-        }
-#endif
-
-        /* Display the boot logo and fade it in */
-        BootLogoFadeIn();
-
-#ifdef INBV_ROTBAR_IMPLEMENTED
-        if (TempRotBarSelection != RB_PROGRESS_BAR)
-        {
-            /* Hide simple progress bar if not used */
-            ShowProgressBar = FALSE;
-        }
-
-        /* Do we have a system thread? */
-        if (!RotBarThreadActive)
-        {
-            /* We don't, initialize the progress bar */
-            RotBarSelection = TempRotBarSelection;
-            InbvRotBarInit();
-        }
-
-        /* Start rotating bar */
-        InbvAcquireLock();
-        PltRotBarStatus = 1;
-        InbvReleaseLock();
-
-        if (TempRotBarSelection != RB_UNSPECIFIED)
-        {
-            Delay.QuadPart = -3000000; // 0.3 sec
-            KeDelayExecutionThread(KernelMode, FALSE, &Delay);
-        }
-#endif
-
-        /* Set filter which will draw text display if needed */
-        InbvInstallDisplayStringFilter(DisplayFilter);
+        ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
+        goto Quit;
     }
-}
 
-VOID
-NTAPI
-INIT_FUNCTION
-DisplayFilter(PCHAR *String)
-{
-    /* Windows hack to skip first dots */
-    static BOOLEAN DotHack = TRUE;
+    /* Display the string */
+    InbvDisplayString(OemString.Buffer);
 
-    /* If "." is given set *String to empty string */
-    if(DotHack && strcmp(*String, ".") == 0)
-        *String = "";
+    /* Free the string buffer */
+    ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
 
-    if(**String)
-    {
-        /* Remove the filter */
-        InbvInstallDisplayStringFilter(NULL);
+    Status = STATUS_SUCCESS;
 
-        DotHack = FALSE;
+Quit:
+    /* Free the captured string */
+    ReleaseCapturedUnicodeString(&CapturedString, PreviousMode);
 
-        /* Draw text screen */
-        DisplayBootBitmap(TRUE);
-    }
-}
-
-VOID
-NTAPI
-INIT_FUNCTION
-FinalizeBootLogo(VOID)
-{
-#ifdef INBV_ROTBAR_IMPLEMENTED
-    /* Reset rotation bar */
-    InbvRotBarStop();
-#endif
-    /* Acquire lock and check the display state */
-    InbvAcquireLock();
-    if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
-    {
-        /* Clear the screen */
-        VidSolidColorFill(0, 0, 639, 479, 0);
-    }
-    /* Reset lock */
-    InbvReleaseLock();
+    return Status;
 }