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 * 1000 /* 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
;
80 /* Check if we're installed and we own it */
81 if ((InbvBootDriverInstalled
) &&
82 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
84 /* Acquire the lock */
88 * Build a bitmap containing the fade in palette. The palette entries
89 * are then processed in a loop and set using VidBitBlt function.
91 ClrUsed
= sizeof(_MainPalette
) / sizeof(_MainPalette
[0]);
92 RtlZeroMemory(PaletteBitmap
, sizeof(BITMAPINFOHEADER
));
93 PaletteBitmap
->biSize
= sizeof(BITMAPINFOHEADER
);
94 PaletteBitmap
->biBitCount
= 4;
95 PaletteBitmap
->biClrUsed
= ClrUsed
;
98 * Main animation loop.
100 for (Iteration
= 0; Iteration
<= PALETTE_FADE_STEPS
; ++Iteration
)
102 for (Index
= 0; Index
< ClrUsed
; Index
++)
104 Palette
[Index
].rgbRed
= (UCHAR
)
105 (_MainPalette
[Index
].rgbRed
* Iteration
/ PALETTE_FADE_STEPS
);
106 Palette
[Index
].rgbGreen
= (UCHAR
)
107 (_MainPalette
[Index
].rgbGreen
* Iteration
/ PALETTE_FADE_STEPS
);
108 Palette
[Index
].rgbBlue
= (UCHAR
)
109 (_MainPalette
[Index
].rgbBlue
* Iteration
/ PALETTE_FADE_STEPS
);
112 VidBitBlt(PaletteBitmapBuffer
, 0, 0);
114 /* Wait for a bit. */
115 KeStallExecutionProcessor(PALETTE_FADE_TIME
);
118 /* Release the lock */
121 /* Wait for a bit. */
122 KeStallExecutionProcessor(PALETTE_FADE_TIME
);
126 /* FUNCTIONS *****************************************************************/
131 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
134 UNICODE_STRING UpString
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
135 UNICODE_STRING MpString
= RTL_CONSTANT_STRING(L
"ntkrnlmp.exe");
136 PLIST_ENTRY NextEntry
, ListHead
;
137 PLDR_DATA_TABLE_ENTRY LdrEntry
;
138 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
139 LDR_RESOURCE_INFO ResourceInfo
;
143 /* Loop the driver list */
144 ListHead
= &LoaderBlock
->LoadOrderListHead
;
145 NextEntry
= ListHead
->Flink
;
146 while (NextEntry
!= ListHead
)
149 LdrEntry
= CONTAINING_RECORD(NextEntry
,
150 LDR_DATA_TABLE_ENTRY
,
153 /* Check for a match */
154 if ((RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &UpString
, TRUE
)) ||
155 (RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &MpString
, TRUE
)))
162 /* Check if we found it */
163 if (NextEntry
!= ListHead
)
165 /* Try to find the resource */
166 ResourceInfo
.Type
= 2; //RT_BITMAP;
167 ResourceInfo
.Name
= ResourceId
;
168 ResourceInfo
.Language
= 0;
169 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
173 if (NT_SUCCESS(Status
))
175 /* Access the resource */
177 Status
= LdrAccessResource(LdrEntry
->DllBase
,
181 if ((Data
) && (ResourceId
< 3))
183 KiBugCheckData
[4] ^= RtlComputeCrc32(0, Data
, Size
);
185 if (!NT_SUCCESS(Status
)) Data
= NULL
;
189 /* Return the pointer */
196 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
200 BOOLEAN CustomLogo
= FALSE
;
203 /* Quit if we're already installed */
204 if (InbvBootDriverInstalled
) return TRUE
;
206 /* Initialize the lock and check the current display state */
207 KeInitializeSpinLock(&BootDriverLock
);
208 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
210 /* Check if we have a custom boot logo */
211 CommandLine
= _strupr(LoaderBlock
->LoadOptions
);
212 CustomLogo
= strstr(CommandLine
, "BOOTLOGO") ? TRUE
: FALSE
;
215 /* Initialize the video */
216 InbvBootDriverInstalled
= VidInitialize(FALSE
);
217 if (InbvBootDriverInstalled
)
219 /* Now reset the display, but only if there's a custom boot logo */
220 VidResetDisplay(CustomLogo
);
222 /* Find bitmap resources in the kernel */
223 ResourceCount
= min(IDB_CLUSTER_SERVER
, Count
);
224 for (i
= 1; i
<= Count
; i
++)
227 ResourceList
[i
] = FindBitmapResource(LoaderBlock
, i
);
230 /* Set the progress bar ranges */
231 InbvSetProgressBarSubset(0, 100);
234 /* Return install state */
235 return InbvBootDriverInstalled
;
240 InbvAcquireLock(VOID
)
244 /* Check if we're at dispatch level or lower */
245 OldIrql
= KeGetCurrentIrql();
246 if (OldIrql
<= DISPATCH_LEVEL
)
248 /* Loop until the lock is free */
249 while (!KeTestSpinLock(&BootDriverLock
));
251 /* Raise IRQL to dispatch level */
252 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
255 /* Acquire the lock */
256 KiAcquireSpinLock(&BootDriverLock
);
257 InbvOldIrql
= OldIrql
;
262 InbvReleaseLock(VOID
)
266 /* Capture the old IRQL */
267 OldIrql
= InbvOldIrql
;
269 /* Release the driver lock */
270 KiReleaseSpinLock(&BootDriverLock
);
272 /* If we were at dispatch level or lower, restore the old IRQL */
273 if (InbvOldIrql
<= DISPATCH_LEVEL
) KeLowerIrql(OldIrql
);
279 InbvEnableBootDriver(IN BOOLEAN Enable
)
281 /* Check if we're installed */
282 if (InbvBootDriverInstalled
)
284 /* Check for lost state */
285 if (InbvDisplayState
>= INBV_DISPLAY_STATE_LOST
) return;
287 /* Acquire the lock */
290 /* Cleanup the screen if we own it */
291 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
) VidCleanUp();
293 /* Set the new display state */
294 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
295 INBV_DISPLAY_STATE_DISABLED
;
297 /* Release the lock */
302 /* Set the new display state */
303 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
304 INBV_DISPLAY_STATE_DISABLED
;
310 InbvAcquireDisplayOwnership(VOID
)
312 /* Check if we have a callback and we're just acquiring it now */
313 if ((InbvResetDisplayParameters
) &&
314 (InbvDisplayState
== INBV_DISPLAY_STATE_LOST
))
316 /* Call the callback */
317 InbvResetDisplayParameters(80, 50);
320 /* Acquire the display */
321 InbvDisplayState
= INBV_DISPLAY_STATE_OWNED
;
326 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned
)
328 /* Set the new display state */
329 InbvDisplayState
= DisplayOwned
? INBV_DISPLAY_STATE_OWNED
:
330 INBV_DISPLAY_STATE_LOST
;
335 InbvCheckDisplayOwnership(VOID
)
337 /* Return if we own it or not */
338 return InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
;
343 InbvGetDisplayState(VOID
)
345 /* Return the actual state */
346 return InbvDisplayState
;
351 InbvDisplayString(IN PCHAR String
)
353 /* Make sure we own the display */
354 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
356 /* If we're not allowed, return success anyway */
357 if (!InbvDisplayDebugStrings
) return TRUE
;
359 /* Check if a filter is installed */
360 if (InbvDisplayFilter
) InbvDisplayFilter(&String
);
362 /* Acquire the lock */
365 /* Make sure we're installed and display the string */
366 if (InbvBootDriverInstalled
) VidDisplayString((PUCHAR
) String
);
368 /* Print the string on the EMS port */
369 HeadlessDispatch(HeadlessCmdPutString
,
371 strlen(String
) + sizeof(ANSI_NULL
),
375 /* Release the lock */
382 /* We don't own it, fail */
388 InbvEnableDisplayString(IN BOOLEAN Enable
)
392 /* Get the old setting */
393 OldSetting
= InbvDisplayDebugStrings
;
396 InbvDisplayDebugStrings
= Enable
;
398 /* Return the old setting */
404 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter
)
406 /* Save the filter */
407 InbvDisplayFilter
= Filter
;
412 InbvIsBootDriverInstalled(VOID
)
414 /* Return driver state */
415 return InbvBootDriverInstalled
;
420 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback
)
422 /* Check if we're installed */
423 if (InbvBootDriverInstalled
)
425 /* Acquire the lock and cleanup if we own the screen */
427 if (InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
) VidCleanUp();
429 /* Set the reset callback and display state */
430 InbvResetDisplayParameters
= Callback
;
431 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
433 /* Release the lock */
438 /* Set the reset callback and display state */
439 InbvResetDisplayParameters
= Callback
;
440 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
446 InbvResetDisplay(VOID
)
448 /* Check if we're installed and we own it */
449 if ((InbvBootDriverInstalled
) &&
450 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
453 VidResetDisplay(TRUE
);
457 /* Nothing to reset */
463 InbvSetScrollRegion(IN ULONG Left
,
468 /* Just call bootvid */
469 VidSetScrollRegion(Left
, Top
, Width
, Height
);
474 InbvSetTextColor(IN ULONG Color
)
476 /* FIXME: Headless */
478 /* Update the text color */
479 VidSetTextColor(Color
);
484 InbvSolidColorFill(IN ULONG Left
,
490 /* Make sure we own it */
491 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
493 /* Acquire the lock */
496 /* Check if we're installed */
497 if (InbvBootDriverInstalled
)
500 VidSolidColorFill(Left
, Top
, Width
, Height
, (UCHAR
)Color
);
503 /* FIXME: Headless */
505 /* Release the lock */
513 InbvUpdateProgressBar(IN ULONG Progress
)
515 ULONG FillCount
, BoundedProgress
;
517 /* Make sure the progress bar is enabled, that we own and are installed */
518 if ((ShowProgressBar
) &&
519 (InbvBootDriverInstalled
) &&
520 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
522 /* Compute fill count */
523 BoundedProgress
= (InbvProgressState
.Floor
/ 100) + Progress
;
524 FillCount
= 121 * (InbvProgressState
.Bias
* BoundedProgress
) / 1000000;
526 /* Acquire the lock */
529 /* Fill the progress bar */
530 VidSolidColorFill(ProgressBarLeft
,
532 ProgressBarLeft
+ FillCount
,
536 /* Release the lock */
543 InbvBufferToScreenBlt(IN PUCHAR Buffer
,
550 /* Check if we're installed and we own it */
551 if ((InbvBootDriverInstalled
) &&
552 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
555 VidBufferToScreenBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
561 InbvBitBlt(IN PUCHAR Buffer
,
565 /* Check if we're installed and we own it */
566 if ((InbvBootDriverInstalled
) &&
567 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
569 /* Acquire the lock */
573 VidBitBlt(Buffer
, X
, Y
);
575 /* Release the lock */
582 InbvScreenToBufferBlt(IN PUCHAR Buffer
,
589 /* Check if we're installed and we own it */
590 if ((InbvBootDriverInstalled
) &&
591 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
594 VidScreenToBufferBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
600 InbvSetProgressBarCoordinates(IN ULONG Left
,
603 /* Update the coordinates */
604 ProgressBarLeft
= Left
;
605 ProgressBarTop
= Top
;
607 /* Enable the progress bar */
608 ShowProgressBar
= TRUE
;
613 InbvSetProgressBarSubset(IN ULONG Floor
,
617 ASSERT(Floor
< Ceiling
);
618 ASSERT(Ceiling
<= 100);
620 /* Update the progress bar state */
621 InbvProgressState
.Floor
= Floor
* 100;
622 InbvProgressState
.Ceiling
= Ceiling
* 100;
623 InbvProgressState
.Bias
= (Ceiling
* 100) - Floor
;
629 InbvIndicateProgress(VOID
)
633 /* Increase progress */
634 InbvProgressIndicator
.Count
++;
636 /* Compute new percentage */
637 Percentage
= min(100 * InbvProgressIndicator
.Count
/
638 InbvProgressIndicator
.Expected
,
640 if (Percentage
!= InbvProgressIndicator
.Percentage
)
642 /* Percentage has moved, update the progress bar */
643 InbvProgressIndicator
.Percentage
= Percentage
;
644 InbvUpdateProgressBar(Percentage
);
650 InbvGetResourceAddress(IN ULONG ResourceNumber
)
652 /* Validate the resource number */
653 if (ResourceNumber
> ResourceCount
) return NULL
;
655 /* Return the address */
656 return ResourceList
[ResourceNumber
--];
661 NtDisplayString(IN PUNICODE_STRING DisplayString
)
663 OEM_STRING OemString
;
665 /* Convert the string to OEM and display it */
666 RtlUnicodeStringToOemString(&OemString
, DisplayString
, TRUE
);
667 InbvDisplayString(OemString
.Buffer
);
668 RtlFreeOemString(&OemString
);
671 return STATUS_SUCCESS
;
677 DisplayBootBitmap(IN BOOLEAN TextMode
)
679 PBITMAPINFOHEADER BitmapInfoHeader
;
682 PVOID Header
, Band
, Text
, Screen
;
683 ROT_BAR_TYPE TempRotBarSelection
= RB_UNSPECIFIED
;
685 #ifdef CORE_6781_resolved
689 /* Check if the system thread has already been created */
690 if (SysThreadCreated
)
692 /* Reset the progress bar */
694 RotBarSelection
= RB_UNSPECIFIED
;
698 /* Check if this is text mode */
699 ShowProgressBar
= FALSE
;
702 /* Check if this is a server OS */
703 if (SharedUserData
->NtProductType
== NtProductWinNt
)
705 /* It's not, set workstation settings */
706 InbvSetTextColor(15);
707 InbvSolidColorFill(0, 0, 639, 479, 7);
708 InbvSolidColorFill(0, 421, 639, 479, 1);
711 Header
= InbvGetResourceAddress(IDB_LOGO_HEADER
);
712 Band
= InbvGetResourceAddress(IDB_LOGO_BAND
);
716 /* Set server settings */
717 InbvSetTextColor(14);
718 InbvSolidColorFill(0, 0, 639, 479, 6);
719 InbvSolidColorFill(0, 421, 639, 479, 1);
722 Header
= InbvGetResourceAddress(IDB_SERVER_HEADER
);
723 Band
= InbvGetResourceAddress(IDB_SERVER_BAND
);
726 /* Set the scrolling region */
727 InbvSetScrollRegion(32, 80, 631, 400);
729 /* Make sure we have resources */
730 if ((Header
) && (Band
))
732 /* BitBlt them on the screen */
733 InbvBitBlt(Band
, 0, 419);
734 InbvBitBlt(Header
, 0, 0);
739 /* Is the boot driver installed? */
741 if (!InbvBootDriverInstalled
) return;
743 /* Load the standard boot screen */
744 Screen
= InbvGetResourceAddress(IDB_BOOT_LOGO
);
745 if (SharedUserData
->NtProductType
== NtProductWinNt
)
747 /* Workstation product, display appropriate status bar color */
748 InbvGetResourceAddress(IDB_BAR_PRO
);
752 /* Display correct branding based on server suite */
753 if (ExVerifySuite(StorageServer
))
755 /* Storage Server Edition */
756 Text
= InbvGetResourceAddress(IDB_STORAGE_SERVER
);
758 else if (ExVerifySuite(ComputeServer
))
760 /* Compute Cluster Edition */
761 Text
= InbvGetResourceAddress(IDB_CLUSTER_SERVER
);
766 Text
= InbvGetResourceAddress(IDB_SERVER_LOGO
);
769 /* Server product, display appropriate status bar color */
770 InbvGetResourceAddress(IDB_BAR_SERVER
);
773 /* Make sure we had a logo */
776 /* Choose progress bar */
777 TempRotBarSelection
= RB_SQUARE_CELLS
;
780 * Save the main image palette and replace it with black palette, so
781 * we can do fade in effect later.
783 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Screen
;
784 Palette
= (LPRGBQUAD
)((PUCHAR
)Screen
+ BitmapInfoHeader
->biSize
);
785 RtlCopyMemory(_MainPalette
, Palette
, sizeof(_MainPalette
));
786 RtlZeroMemory(Palette
, sizeof(_MainPalette
));
788 /* Blit the background */
789 InbvBitBlt(Screen
, 0, 0);
791 /* Set progress bar coordinates and display it */
792 InbvSetProgressBarCoordinates(257, 352);
794 /* Display the boot logo and fade it in */
797 #ifdef CORE_6781_resolved
798 /* Check for non-workstation products */
799 if (SharedUserData
->NtProductType
!= NtProductWinNt
)
801 /* Overwrite part of the logo for a server product */
802 InbvScreenToBufferBlt(Buffer
, 413, 237, 7, 7, 8);
803 InbvSolidColorFill(418, 230, 454, 256, 0);
804 InbvBufferToScreenBlt(Buffer
, 413, 237, 7, 7, 8);
806 /* In setup mode, you haven't selected a SKU yet */
807 if (ExpInTextModeSetup
) Text
= NULL
;
812 #ifdef CORE_6781_resolved
813 /* Draw the SKU text if it exits */
814 if (Text
) InbvBitBlt(Text
, 180, 121);
816 DBG_UNREFERENCED_LOCAL_VARIABLE(Text
);
819 /* Draw the progress bar bit */
820 // if (Bar) InbvBitBlt(Bar, 0, 0);
822 /* Set filter which will draw text display if needed */
823 InbvInstallDisplayStringFilter(DisplayFilter
);
826 /* Do we have a system thread? */
827 if (SysThreadCreated
)
829 /* We do, set the progress bar location */
831 RotBarSelection
= TempRotBarSelection
;
840 DisplayFilter(PCHAR
*String
)
842 /* Windows hack to skip first dots */
843 static BOOLEAN DotHack
= TRUE
;
845 /* If "." is given set *String to empty string */
846 if(DotHack
&& strcmp(*String
, ".") == 0)
851 /* Remove the filter */
852 InbvInstallDisplayStringFilter(NULL
);
856 /* Draw text screen */
857 DisplayBootBitmap(TRUE
);
864 FinalizeBootLogo(VOID
)
866 /* Acquire lock and check the display state */
868 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED
)
870 /* Clear the screen */
871 VidSolidColorFill(0, 0, 639, 479, 0);
874 /* Reset progress bar and lock */