1 /* INCLUDES ******************************************************************/
6 #include "bootvid/bootvid.h"
8 /* GLOBALS *******************************************************************/
10 KSPIN_LOCK BootDriverLock
;
12 INBV_DISPLAY_STATE InbvDisplayState
;
13 BOOLEAN InbvBootDriverInstalled
= FALSE
;
14 BOOLEAN InbvDisplayDebugStrings
= FALSE
;
15 INBV_DISPLAY_STRING_FILTER InbvDisplayFilter
;
16 ULONG ProgressBarLeft
, ProgressBarTop
;
17 BOOLEAN ShowProgressBar
= FALSE
;
18 INBV_PROGRESS_STATE InbvProgressState
;
19 INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters
;
21 PUCHAR ResourceList
[64];
22 BOOLEAN SysThreadCreated
= FALSE
;
23 ROT_BAR_TYPE RotBarSelection
;
24 ULONG PltRotBarStatus
;
25 BT_PROGRESS_INDICATOR InbvProgressIndicator
= {0, 25, 0};
27 /* FADING FUNCTION ***********************************************************/
29 /** From include/psdk/wingdi.h **/
30 typedef struct tagRGBQUAD
37 /*******************************/
39 static RGBQUAD _MainPalette
[16];
41 #define PALETTE_FADE_STEPS 15
42 #define PALETTE_FADE_TIME 20 * 10000 /* 20ms */
44 /** From bootvid/precomp.h **/
48 typedef struct tagBITMAPINFOHEADER
61 } BITMAPINFOHEADER
, *PBITMAPINFOHEADER
;
62 /****************************/
67 VOID NTAPI
InbvAcquireLock(VOID
);
68 VOID NTAPI
InbvReleaseLock(VOID
);
74 UCHAR PaletteBitmapBuffer
[sizeof(BITMAPINFOHEADER
) + sizeof(_MainPalette
)];
75 PBITMAPINFOHEADER PaletteBitmap
= (PBITMAPINFOHEADER
)PaletteBitmapBuffer
;
76 LPRGBQUAD Palette
= (LPRGBQUAD
)(PaletteBitmapBuffer
+ sizeof(BITMAPINFOHEADER
));
78 ULONG Iteration
, Index
, ClrUsed
;
79 LARGE_INTEGER Interval
;
81 Interval
.QuadPart
= -PALETTE_FADE_TIME
;
83 /* Check if we're installed and we own it */
84 if ((InbvBootDriverInstalled
) &&
85 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
87 /* Acquire the lock */
91 * Build a bitmap containing the fade in palette. The palette entries
92 * are then processed in a loop and set using VidBitBlt function.
94 ClrUsed
= sizeof(_MainPalette
) / sizeof(_MainPalette
[0]);
95 RtlZeroMemory(PaletteBitmap
, sizeof(BITMAPINFOHEADER
));
96 PaletteBitmap
->biSize
= sizeof(BITMAPINFOHEADER
);
97 PaletteBitmap
->biBitCount
= 4;
98 PaletteBitmap
->biClrUsed
= ClrUsed
;
101 * Main animation loop.
103 for (Iteration
= 0; Iteration
<= PALETTE_FADE_STEPS
; ++Iteration
)
105 for (Index
= 0; Index
< ClrUsed
; Index
++)
107 Palette
[Index
].rgbRed
= (UCHAR
)
108 (_MainPalette
[Index
].rgbRed
* Iteration
/ PALETTE_FADE_STEPS
);
109 Palette
[Index
].rgbGreen
= (UCHAR
)
110 (_MainPalette
[Index
].rgbGreen
* Iteration
/ PALETTE_FADE_STEPS
);
111 Palette
[Index
].rgbBlue
= (UCHAR
)
112 (_MainPalette
[Index
].rgbBlue
* Iteration
/ PALETTE_FADE_STEPS
);
115 VidBitBlt(PaletteBitmapBuffer
, 0, 0);
117 /* Wait for a bit. */
118 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
121 /* Release the lock */
124 /* Wait for a bit. */
125 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
129 /* FUNCTIONS *****************************************************************/
134 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
137 UNICODE_STRING UpString
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
138 UNICODE_STRING MpString
= RTL_CONSTANT_STRING(L
"ntkrnlmp.exe");
139 PLIST_ENTRY NextEntry
, ListHead
;
140 PLDR_DATA_TABLE_ENTRY LdrEntry
;
141 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
142 LDR_RESOURCE_INFO ResourceInfo
;
146 /* Loop the driver list */
147 ListHead
= &LoaderBlock
->LoadOrderListHead
;
148 NextEntry
= ListHead
->Flink
;
149 while (NextEntry
!= ListHead
)
152 LdrEntry
= CONTAINING_RECORD(NextEntry
,
153 LDR_DATA_TABLE_ENTRY
,
156 /* Check for a match */
157 if ((RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &UpString
, TRUE
)) ||
158 (RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &MpString
, TRUE
)))
165 /* Check if we found it */
166 if (NextEntry
!= ListHead
)
168 /* Try to find the resource */
169 ResourceInfo
.Type
= 2; //RT_BITMAP;
170 ResourceInfo
.Name
= ResourceId
;
171 ResourceInfo
.Language
= 0;
172 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
176 if (NT_SUCCESS(Status
))
178 /* Access the resource */
180 Status
= LdrAccessResource(LdrEntry
->DllBase
,
184 if ((Data
) && (ResourceId
< 3))
186 KiBugCheckData
[4] ^= RtlComputeCrc32(0, Data
, Size
);
188 if (!NT_SUCCESS(Status
)) Data
= NULL
;
192 /* Return the pointer */
199 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
203 BOOLEAN CustomLogo
= FALSE
;
206 /* Quit if we're already installed */
207 if (InbvBootDriverInstalled
) return TRUE
;
209 /* Initialize the lock and check the current display state */
210 KeInitializeSpinLock(&BootDriverLock
);
211 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
213 /* Check if we have a custom boot logo */
214 CommandLine
= _strupr(LoaderBlock
->LoadOptions
);
215 CustomLogo
= strstr(CommandLine
, "BOOTLOGO") ? TRUE
: FALSE
;
218 /* Initialize the video */
219 InbvBootDriverInstalled
= VidInitialize(FALSE
);
220 if (InbvBootDriverInstalled
)
222 /* Now reset the display, but only if there's a custom boot logo */
223 VidResetDisplay(CustomLogo
);
225 /* Find bitmap resources in the kernel */
226 ResourceCount
= min(IDB_CLUSTER_SERVER
, Count
);
227 for (i
= 1; i
<= Count
; i
++)
230 ResourceList
[i
] = FindBitmapResource(LoaderBlock
, i
);
233 /* Set the progress bar ranges */
234 InbvSetProgressBarSubset(0, 100);
237 /* Return install state */
238 return InbvBootDriverInstalled
;
243 InbvAcquireLock(VOID
)
247 /* Check if we're at dispatch level or lower */
248 OldIrql
= KeGetCurrentIrql();
249 if (OldIrql
<= DISPATCH_LEVEL
)
251 /* Loop until the lock is free */
252 while (!KeTestSpinLock(&BootDriverLock
));
254 /* Raise IRQL to dispatch level */
255 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
258 /* Acquire the lock */
259 KiAcquireSpinLock(&BootDriverLock
);
260 InbvOldIrql
= OldIrql
;
265 InbvReleaseLock(VOID
)
269 /* Capture the old IRQL */
270 OldIrql
= InbvOldIrql
;
272 /* Release the driver lock */
273 KiReleaseSpinLock(&BootDriverLock
);
275 /* If we were at dispatch level or lower, restore the old IRQL */
276 if (InbvOldIrql
<= DISPATCH_LEVEL
) KeLowerIrql(OldIrql
);
282 InbvEnableBootDriver(IN BOOLEAN Enable
)
284 /* Check if we're installed */
285 if (InbvBootDriverInstalled
)
287 /* Check for lost state */
288 if (InbvDisplayState
>= INBV_DISPLAY_STATE_LOST
) return;
290 /* Acquire the lock */
293 /* Cleanup the screen if we own it */
294 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
) VidCleanUp();
296 /* Set the new display state */
297 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
298 INBV_DISPLAY_STATE_DISABLED
;
300 /* Release the lock */
305 /* Set the new display state */
306 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
307 INBV_DISPLAY_STATE_DISABLED
;
313 InbvAcquireDisplayOwnership(VOID
)
315 /* Check if we have a callback and we're just acquiring it now */
316 if ((InbvResetDisplayParameters
) &&
317 (InbvDisplayState
== INBV_DISPLAY_STATE_LOST
))
319 /* Call the callback */
320 InbvResetDisplayParameters(80, 50);
323 /* Acquire the display */
324 InbvDisplayState
= INBV_DISPLAY_STATE_OWNED
;
329 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned
)
331 /* Set the new display state */
332 InbvDisplayState
= DisplayOwned
? INBV_DISPLAY_STATE_OWNED
:
333 INBV_DISPLAY_STATE_LOST
;
338 InbvCheckDisplayOwnership(VOID
)
340 /* Return if we own it or not */
341 return InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
;
346 InbvGetDisplayState(VOID
)
348 /* Return the actual state */
349 return InbvDisplayState
;
354 InbvDisplayString(IN PCHAR String
)
356 /* Make sure we own the display */
357 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
359 /* If we're not allowed, return success anyway */
360 if (!InbvDisplayDebugStrings
) return TRUE
;
362 /* Check if a filter is installed */
363 if (InbvDisplayFilter
) InbvDisplayFilter(&String
);
365 /* Acquire the lock */
368 /* Make sure we're installed and display the string */
369 if (InbvBootDriverInstalled
) VidDisplayString((PUCHAR
) String
);
371 /* Print the string on the EMS port */
372 HeadlessDispatch(HeadlessCmdPutString
,
374 strlen(String
) + sizeof(ANSI_NULL
),
378 /* Release the lock */
385 /* We don't own it, fail */
391 InbvEnableDisplayString(IN BOOLEAN Enable
)
395 /* Get the old setting */
396 OldSetting
= InbvDisplayDebugStrings
;
399 InbvDisplayDebugStrings
= Enable
;
401 /* Return the old setting */
407 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter
)
409 /* Save the filter */
410 InbvDisplayFilter
= Filter
;
415 InbvIsBootDriverInstalled(VOID
)
417 /* Return driver state */
418 return InbvBootDriverInstalled
;
423 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback
)
425 /* Check if we're installed */
426 if (InbvBootDriverInstalled
)
428 /* Acquire the lock and cleanup if we own the screen */
430 if (InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
) VidCleanUp();
432 /* Set the reset callback and display state */
433 InbvResetDisplayParameters
= Callback
;
434 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
436 /* Release the lock */
441 /* Set the reset callback and display state */
442 InbvResetDisplayParameters
= Callback
;
443 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
449 InbvResetDisplay(VOID
)
451 /* Check if we're installed and we own it */
452 if ((InbvBootDriverInstalled
) &&
453 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
456 VidResetDisplay(TRUE
);
460 /* Nothing to reset */
466 InbvSetScrollRegion(IN ULONG Left
,
471 /* Just call bootvid */
472 VidSetScrollRegion(Left
, Top
, Width
, Height
);
477 InbvSetTextColor(IN ULONG Color
)
479 /* FIXME: Headless */
481 /* Update the text color */
482 VidSetTextColor(Color
);
487 InbvSolidColorFill(IN ULONG Left
,
493 /* Make sure we own it */
494 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
496 /* Acquire the lock */
499 /* Check if we're installed */
500 if (InbvBootDriverInstalled
)
503 VidSolidColorFill(Left
, Top
, Width
, Height
, (UCHAR
)Color
);
506 /* FIXME: Headless */
508 /* Release the lock */
516 InbvUpdateProgressBar(IN ULONG Progress
)
518 ULONG FillCount
, BoundedProgress
;
520 /* Make sure the progress bar is enabled, that we own and are installed */
521 if ((ShowProgressBar
) &&
522 (InbvBootDriverInstalled
) &&
523 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
525 /* Compute fill count */
526 BoundedProgress
= (InbvProgressState
.Floor
/ 100) + Progress
;
527 FillCount
= 121 * (InbvProgressState
.Bias
* BoundedProgress
) / 1000000;
529 /* Acquire the lock */
532 /* Fill the progress bar */
533 VidSolidColorFill(ProgressBarLeft
,
535 ProgressBarLeft
+ FillCount
,
539 /* Release the lock */
546 InbvBufferToScreenBlt(IN PUCHAR Buffer
,
553 /* Check if we're installed and we own it */
554 if ((InbvBootDriverInstalled
) &&
555 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
558 VidBufferToScreenBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
564 InbvBitBlt(IN PUCHAR Buffer
,
568 /* Check if we're installed and we own it */
569 if ((InbvBootDriverInstalled
) &&
570 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
572 /* Acquire the lock */
576 VidBitBlt(Buffer
, X
, Y
);
578 /* Release the lock */
585 InbvScreenToBufferBlt(IN PUCHAR Buffer
,
592 /* Check if we're installed and we own it */
593 if ((InbvBootDriverInstalled
) &&
594 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
597 VidScreenToBufferBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
603 InbvSetProgressBarCoordinates(IN ULONG Left
,
606 /* Update the coordinates */
607 ProgressBarLeft
= Left
;
608 ProgressBarTop
= Top
;
610 /* Enable the progress bar */
611 ShowProgressBar
= TRUE
;
616 InbvSetProgressBarSubset(IN ULONG Floor
,
620 ASSERT(Floor
< Ceiling
);
621 ASSERT(Ceiling
<= 100);
623 /* Update the progress bar state */
624 InbvProgressState
.Floor
= Floor
* 100;
625 InbvProgressState
.Ceiling
= Ceiling
* 100;
626 InbvProgressState
.Bias
= (Ceiling
* 100) - Floor
;
632 InbvIndicateProgress(VOID
)
636 /* Increase progress */
637 InbvProgressIndicator
.Count
++;
639 /* Compute new percentage */
640 Percentage
= min(100 * InbvProgressIndicator
.Count
/
641 InbvProgressIndicator
.Expected
,
643 if (Percentage
!= InbvProgressIndicator
.Percentage
)
645 /* Percentage has moved, update the progress bar */
646 InbvProgressIndicator
.Percentage
= Percentage
;
647 InbvUpdateProgressBar(Percentage
);
653 InbvGetResourceAddress(IN ULONG ResourceNumber
)
655 /* Validate the resource number */
656 if (ResourceNumber
> ResourceCount
) return NULL
;
658 /* Return the address */
659 return ResourceList
[ResourceNumber
--];
664 NtDisplayString(IN PUNICODE_STRING DisplayString
)
666 OEM_STRING OemString
;
668 /* Convert the string to OEM and display it */
669 RtlUnicodeStringToOemString(&OemString
, DisplayString
, TRUE
);
670 InbvDisplayString(OemString
.Buffer
);
671 RtlFreeOemString(&OemString
);
674 return STATUS_SUCCESS
;
680 DisplayBootBitmap(IN BOOLEAN TextMode
)
682 PBITMAPINFOHEADER BitmapInfoHeader
;
685 PVOID Header
, Band
, Text
, Screen
;
686 ROT_BAR_TYPE TempRotBarSelection
= RB_UNSPECIFIED
;
688 #ifdef CORE_6781_resolved
692 /* Check if the system thread has already been created */
693 if (SysThreadCreated
)
695 /* Reset the progress bar */
697 RotBarSelection
= RB_UNSPECIFIED
;
701 /* Check if this is text mode */
702 ShowProgressBar
= FALSE
;
705 /* Check if this is a server OS */
706 if (SharedUserData
->NtProductType
== NtProductWinNt
)
708 /* It's not, set workstation settings */
709 InbvSetTextColor(15);
710 InbvSolidColorFill(0, 0, 639, 479, 7);
711 InbvSolidColorFill(0, 421, 639, 479, 1);
714 Header
= InbvGetResourceAddress(IDB_LOGO_HEADER
);
715 Band
= InbvGetResourceAddress(IDB_LOGO_BAND
);
719 /* Set server settings */
720 InbvSetTextColor(14);
721 InbvSolidColorFill(0, 0, 639, 479, 6);
722 InbvSolidColorFill(0, 421, 639, 479, 1);
725 Header
= InbvGetResourceAddress(IDB_SERVER_HEADER
);
726 Band
= InbvGetResourceAddress(IDB_SERVER_BAND
);
729 /* Set the scrolling region */
730 InbvSetScrollRegion(32, 80, 631, 400);
732 /* Make sure we have resources */
733 if ((Header
) && (Band
))
735 /* BitBlt them on the screen */
736 InbvBitBlt(Band
, 0, 419);
737 InbvBitBlt(Header
, 0, 0);
742 /* Is the boot driver installed? */
744 if (!InbvBootDriverInstalled
) return;
746 /* Load the standard boot screen */
747 Screen
= InbvGetResourceAddress(IDB_BOOT_LOGO
);
748 if (SharedUserData
->NtProductType
== NtProductWinNt
)
750 /* Workstation product, display appropriate status bar color */
751 InbvGetResourceAddress(IDB_BAR_PRO
);
755 /* Display correct branding based on server suite */
756 if (ExVerifySuite(StorageServer
))
758 /* Storage Server Edition */
759 Text
= InbvGetResourceAddress(IDB_STORAGE_SERVER
);
761 else if (ExVerifySuite(ComputeServer
))
763 /* Compute Cluster Edition */
764 Text
= InbvGetResourceAddress(IDB_CLUSTER_SERVER
);
769 Text
= InbvGetResourceAddress(IDB_SERVER_LOGO
);
772 /* Server product, display appropriate status bar color */
773 InbvGetResourceAddress(IDB_BAR_SERVER
);
776 /* Make sure we had a logo */
779 /* Choose progress bar */
780 TempRotBarSelection
= RB_SQUARE_CELLS
;
783 * Save the main image palette and replace it with black palette, so
784 * we can do fade in effect later.
786 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Screen
;
787 Palette
= (LPRGBQUAD
)((PUCHAR
)Screen
+ BitmapInfoHeader
->biSize
);
788 RtlCopyMemory(_MainPalette
, Palette
, sizeof(_MainPalette
));
789 RtlZeroMemory(Palette
, sizeof(_MainPalette
));
791 /* Blit the background */
792 InbvBitBlt(Screen
, 0, 0);
794 /* Set progress bar coordinates and display it */
795 InbvSetProgressBarCoordinates(257, 352);
797 /* Display the boot logo and fade it in */
800 #ifdef CORE_6781_resolved
801 /* Check for non-workstation products */
802 if (SharedUserData
->NtProductType
!= NtProductWinNt
)
804 /* Overwrite part of the logo for a server product */
805 InbvScreenToBufferBlt(Buffer
, 413, 237, 7, 7, 8);
806 InbvSolidColorFill(418, 230, 454, 256, 0);
807 InbvBufferToScreenBlt(Buffer
, 413, 237, 7, 7, 8);
809 /* In setup mode, you haven't selected a SKU yet */
810 if (ExpInTextModeSetup
) Text
= NULL
;
815 #ifdef CORE_6781_resolved
816 /* Draw the SKU text if it exits */
817 if (Text
) InbvBitBlt(Text
, 180, 121);
820 /* Draw the progress bar bit */
821 // if (Bar) InbvBitBlt(Bar, 0, 0);
823 /* Set filter which will draw text display if needed */
824 InbvInstallDisplayStringFilter(DisplayFilter
);
827 /* Do we have a system thread? */
828 if (SysThreadCreated
)
830 /* We do, set the progress bar location */
832 RotBarSelection
= TempRotBarSelection
;
841 DisplayFilter(PCHAR
*String
)
843 /* Windows hack to skip first dots */
844 static BOOLEAN DotHack
= TRUE
;
846 /* If "." is given set *String to empty string */
847 if(DotHack
&& strcmp(*String
, ".") == 0)
852 /* Remove the filter */
853 InbvInstallDisplayStringFilter(NULL
);
857 /* Draw text screen */
858 DisplayBootBitmap(TRUE
);
865 FinalizeBootLogo(VOID
)
867 /* Acquire lock and check the display state */
869 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED
)
871 /* Clear the screen */
872 VidSolidColorFill(0, 0, 639, 479, 0);
875 /* Reset progress bar and lock */