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 /****************************/
66 BootImageFadeProc(VOID
)
68 UCHAR PaletteBitmapBuffer
[sizeof(BITMAPINFOHEADER
) + sizeof(_MainPalette
)];
69 PBITMAPINFOHEADER PaletteBitmap
= (PBITMAPINFOHEADER
)PaletteBitmapBuffer
;
70 LPRGBQUAD Palette
= (LPRGBQUAD
)(PaletteBitmapBuffer
+ sizeof(BITMAPINFOHEADER
));
72 ULONG Iteration
, Index
, ClrUsed
;
73 LARGE_INTEGER Interval
;
75 Interval
.QuadPart
= -PALETTE_FADE_TIME
;
78 * Build a bitmap containing the fade in palette. The palette entries
79 * are then processed in a loop and set using VidBitBlt function.
81 ClrUsed
= sizeof(_MainPalette
) / sizeof(_MainPalette
[0]);
82 RtlZeroMemory(PaletteBitmap
, sizeof(BITMAPINFOHEADER
));
83 PaletteBitmap
->biSize
= sizeof(BITMAPINFOHEADER
);
84 PaletteBitmap
->biBitCount
= 4;
85 PaletteBitmap
->biClrUsed
= ClrUsed
;
88 * Main animation loop.
90 for (Iteration
= 0; Iteration
<= PALETTE_FADE_STEPS
; ++Iteration
)
92 for (Index
= 0; Index
< ClrUsed
; Index
++)
94 Palette
[Index
].rgbRed
=
95 _MainPalette
[Index
].rgbRed
* Iteration
/ PALETTE_FADE_STEPS
;
96 Palette
[Index
].rgbGreen
=
97 _MainPalette
[Index
].rgbGreen
* Iteration
/ PALETTE_FADE_STEPS
;
98 Palette
[Index
].rgbBlue
=
99 _MainPalette
[Index
].rgbBlue
* Iteration
/ PALETTE_FADE_STEPS
;
102 VidBitBlt(PaletteBitmapBuffer
, 0, 0);
104 /* Wait for a bit. */
105 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
108 /* Wait for a bit. */
109 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
113 /* FUNCTIONS *****************************************************************/
118 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
121 UNICODE_STRING UpString
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
122 UNICODE_STRING MpString
= RTL_CONSTANT_STRING(L
"ntkrnlmp.exe");
123 PLIST_ENTRY NextEntry
, ListHead
;
124 PLDR_DATA_TABLE_ENTRY LdrEntry
;
125 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
126 LDR_RESOURCE_INFO ResourceInfo
;
130 /* Loop the driver list */
131 ListHead
= &LoaderBlock
->LoadOrderListHead
;
132 NextEntry
= ListHead
->Flink
;
133 while (NextEntry
!= ListHead
)
136 LdrEntry
= CONTAINING_RECORD(NextEntry
,
137 LDR_DATA_TABLE_ENTRY
,
140 /* Check for a match */
141 if ((RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &UpString
, TRUE
)) ||
142 (RtlEqualUnicodeString(&LdrEntry
->BaseDllName
, &MpString
, TRUE
)))
149 /* Check if we found it */
150 if (NextEntry
!= ListHead
)
152 /* Try to find the resource */
153 ResourceInfo
.Type
= 2; //RT_BITMAP;
154 ResourceInfo
.Name
= ResourceId
;
155 ResourceInfo
.Language
= 0;
156 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
160 if (NT_SUCCESS(Status
))
162 /* Access the resource */
164 Status
= LdrAccessResource(LdrEntry
->DllBase
,
168 if ((Data
) && (ResourceId
< 3))
170 KiBugCheckData
[4] ^= RtlComputeCrc32(0, Data
, Size
);
172 if (!NT_SUCCESS(Status
)) Data
= NULL
;
176 /* Return the pointer */
183 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
187 BOOLEAN CustomLogo
= FALSE
;
190 /* Quit if we're already installed */
191 if (InbvBootDriverInstalled
) return TRUE
;
193 /* Initialize the lock and check the current display state */
194 KeInitializeSpinLock(&BootDriverLock
);
195 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
197 /* Check if we have a custom boot logo */
198 CommandLine
= _strupr(LoaderBlock
->LoadOptions
);
199 CustomLogo
= strstr(CommandLine
, "BOOTLOGO") ? TRUE
: FALSE
;
202 /* Initialize the video */
203 InbvBootDriverInstalled
= VidInitialize(FALSE
);
204 if (InbvBootDriverInstalled
)
206 /* Now reset the display, but only if there's a custom boot logo */
207 VidResetDisplay(CustomLogo
);
209 /* Find bitmap resources in the kernel */
210 ResourceCount
= min(IDB_CLUSTER_SERVER
, Count
);
211 for (i
= 1; i
<= Count
; i
++)
214 ResourceList
[i
] = FindBitmapResource(LoaderBlock
, i
);
217 /* Set the progress bar ranges */
218 InbvSetProgressBarSubset(0, 100);
221 /* Return install state */
222 return InbvBootDriverInstalled
;
227 InbvAcquireLock(VOID
)
231 /* Check if we're at dispatch level or lower */
232 OldIrql
= KeGetCurrentIrql();
233 if (OldIrql
<= DISPATCH_LEVEL
)
235 /* Loop until the lock is free */
236 while (!KeTestSpinLock(&BootDriverLock
));
238 /* Raise IRQL to dispatch level */
239 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
242 /* Acquire the lock */
243 KiAcquireSpinLock(&BootDriverLock
);
244 InbvOldIrql
= OldIrql
;
249 InbvReleaseLock(VOID
)
253 /* Capture the old IRQL */
254 OldIrql
= InbvOldIrql
;
256 /* Release the driver lock */
257 KiReleaseSpinLock(&BootDriverLock
);
259 /* If we were at dispatch level or lower, restore the old IRQL */
260 if (InbvOldIrql
<= DISPATCH_LEVEL
) KeLowerIrql(OldIrql
);
266 InbvEnableBootDriver(IN BOOLEAN Enable
)
268 /* Check if we're installed */
269 if (InbvBootDriverInstalled
)
271 /* Check for lost state */
272 if (InbvDisplayState
>= INBV_DISPLAY_STATE_LOST
) return;
274 /* Acquire the lock */
277 /* Cleanup the screen if we own it */
278 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
) VidCleanUp();
280 /* Set the new display state */
281 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
282 INBV_DISPLAY_STATE_DISABLED
;
284 /* Release the lock */
289 /* Set the new display state */
290 InbvDisplayState
= Enable
? INBV_DISPLAY_STATE_OWNED
:
291 INBV_DISPLAY_STATE_DISABLED
;
297 InbvAcquireDisplayOwnership(VOID
)
299 /* Check if we have a callback and we're just acquiring it now */
300 if ((InbvResetDisplayParameters
) &&
301 (InbvDisplayState
== INBV_DISPLAY_STATE_LOST
))
303 /* Call the callback */
304 InbvResetDisplayParameters(80, 50);
307 /* Acquire the display */
308 InbvDisplayState
= INBV_DISPLAY_STATE_OWNED
;
313 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned
)
315 /* Set the new display state */
316 InbvDisplayState
= DisplayOwned
? INBV_DISPLAY_STATE_OWNED
:
317 INBV_DISPLAY_STATE_LOST
;
322 InbvCheckDisplayOwnership(VOID
)
324 /* Return if we own it or not */
325 return InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
;
330 InbvGetDisplayState(VOID
)
332 /* Return the actual state */
333 return InbvDisplayState
;
338 InbvDisplayString(IN PCHAR String
)
340 /* Make sure we own the display */
341 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
343 /* If we're not allowed, return success anyway */
344 if (!InbvDisplayDebugStrings
) return TRUE
;
346 /* Check if a filter is installed */
347 if (InbvDisplayFilter
) InbvDisplayFilter(&String
);
349 /* Acquire the lock */
352 /* Make sure we're installed and display the string */
353 if (InbvBootDriverInstalled
) VidDisplayString((PUCHAR
) String
);
355 /* Print the string on the EMS port */
356 HeadlessDispatch(HeadlessCmdPutString
,
358 strlen(String
) + sizeof(ANSI_NULL
),
362 /* Release the lock */
369 /* We don't own it, fail */
375 InbvEnableDisplayString(IN BOOLEAN Enable
)
379 /* Get the old setting */
380 OldSetting
= InbvDisplayDebugStrings
;
383 InbvDisplayDebugStrings
= Enable
;
385 /* Return the old setting */
391 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter
)
393 /* Save the filter */
394 InbvDisplayFilter
= Filter
;
399 InbvIsBootDriverInstalled(VOID
)
401 /* Return driver state */
402 return InbvBootDriverInstalled
;
407 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback
)
409 /* Check if we're installed */
410 if (InbvBootDriverInstalled
)
412 /* Acquire the lock and cleanup if we own the screen */
414 if (InbvDisplayState
!= INBV_DISPLAY_STATE_LOST
) VidCleanUp();
416 /* Set the reset callback and display state */
417 InbvResetDisplayParameters
= Callback
;
418 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
420 /* Release the lock */
425 /* Set the reset callback and display state */
426 InbvResetDisplayParameters
= Callback
;
427 InbvDisplayState
= INBV_DISPLAY_STATE_LOST
;
433 InbvResetDisplay(VOID
)
435 /* Check if we're installed and we own it */
436 if ((InbvBootDriverInstalled
) &&
437 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
440 VidResetDisplay(TRUE
);
444 /* Nothing to reset */
450 InbvSetScrollRegion(IN ULONG Left
,
455 /* Just call bootvid */
456 VidSetScrollRegion(Left
, Top
, Width
, Height
);
461 InbvSetTextColor(IN ULONG Color
)
463 /* FIXME: Headless */
465 /* Update the text color */
466 VidSetTextColor(Color
);
471 InbvSolidColorFill(IN ULONG Left
,
477 /* Make sure we own it */
478 if (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
)
480 /* Acquire the lock */
483 /* Check if we're installed */
484 if (InbvBootDriverInstalled
)
487 VidSolidColorFill(Left
, Top
, Width
, Height
, (UCHAR
)Color
);
490 /* FIXME: Headless */
492 /* Release the lock */
500 InbvUpdateProgressBar(IN ULONG Progress
)
502 ULONG FillCount
, BoundedProgress
;
504 /* Make sure the progress bar is enabled, that we own and are installed */
505 if ((ShowProgressBar
) &&
506 (InbvBootDriverInstalled
) &&
507 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
509 /* Compute fill count */
510 BoundedProgress
= (InbvProgressState
.Floor
/ 100) + Progress
;
511 FillCount
= 121 * (InbvProgressState
.Bias
* BoundedProgress
) / 1000000;
513 /* Acquire the lock */
516 /* Fill the progress bar */
517 VidSolidColorFill(ProgressBarLeft
,
519 ProgressBarLeft
+ FillCount
,
523 /* Release the lock */
530 InbvBufferToScreenBlt(IN PUCHAR Buffer
,
537 /* Check if we're installed and we own it */
538 if ((InbvBootDriverInstalled
) &&
539 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
542 VidBufferToScreenBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
548 InbvBitBlt(IN PUCHAR Buffer
,
552 /* Check if we're installed and we own it */
553 if ((InbvBootDriverInstalled
) &&
554 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
556 /* Acquire the lock */
560 VidBitBlt(Buffer
, X
, Y
);
562 /* Release the lock */
569 InbvScreenToBufferBlt(IN PUCHAR Buffer
,
576 /* Check if we're installed and we own it */
577 if ((InbvBootDriverInstalled
) &&
578 (InbvDisplayState
== INBV_DISPLAY_STATE_OWNED
))
581 VidScreenToBufferBlt(Buffer
, X
, Y
, Width
, Height
, Delta
);
587 InbvSetProgressBarCoordinates(IN ULONG Left
,
590 /* Update the coordinates */
591 ProgressBarLeft
= Left
;
592 ProgressBarTop
= Top
;
594 /* Enable the progress bar */
595 ShowProgressBar
= TRUE
;
600 InbvSetProgressBarSubset(IN ULONG Floor
,
604 ASSERT(Floor
< Ceiling
);
605 ASSERT(Ceiling
<= 100);
607 /* Update the progress bar state */
608 InbvProgressState
.Floor
= Floor
* 100;
609 InbvProgressState
.Ceiling
= Ceiling
* 100;
610 InbvProgressState
.Bias
= (Ceiling
* 100) - Floor
;
616 InbvIndicateProgress(VOID
)
620 /* Increase progress */
621 InbvProgressIndicator
.Count
++;
623 /* Compute new percentage */
624 Percentage
= min(100 * InbvProgressIndicator
.Count
/
625 InbvProgressIndicator
.Expected
,
627 if (Percentage
!= InbvProgressIndicator
.Percentage
)
629 /* Percentage has moved, update the progress bar */
630 InbvProgressIndicator
.Percentage
= Percentage
;
631 InbvUpdateProgressBar(Percentage
);
637 InbvGetResourceAddress(IN ULONG ResourceNumber
)
639 /* Validate the resource number */
640 if (ResourceNumber
> ResourceCount
) return NULL
;
642 /* Return the address */
643 return ResourceList
[ResourceNumber
--];
648 NtDisplayString(IN PUNICODE_STRING DisplayString
)
650 OEM_STRING OemString
;
652 /* Convert the string to OEM and display it */
653 RtlUnicodeStringToOemString(&OemString
, DisplayString
, TRUE
);
654 InbvDisplayString(OemString
.Buffer
);
655 RtlFreeOemString(&OemString
);
658 return STATUS_SUCCESS
;
664 DisplayBootBitmap(IN BOOLEAN TextMode
)
666 PBITMAPINFOHEADER BitmapInfoHeader
;
669 PVOID Header
, Band
, Text
, Screen
;
670 ROT_BAR_TYPE TempRotBarSelection
= RB_UNSPECIFIED
;
673 /* Check if the system thread has already been created */
674 if (SysThreadCreated
)
676 /* Reset the progress bar */
678 RotBarSelection
= RB_UNSPECIFIED
;
682 /* Check if this is text mode */
683 ShowProgressBar
= FALSE
;
686 /* Check if this is a server OS */
687 if (SharedUserData
->NtProductType
== NtProductWinNt
)
689 /* It's not, set workstation settings */
690 InbvSetTextColor(15);
691 InbvSolidColorFill(0, 0, 639, 479, 7);
692 InbvSolidColorFill(0, 421, 639, 479, 1);
695 Header
= InbvGetResourceAddress(IDB_LOGO_HEADER
);
696 Band
= InbvGetResourceAddress(IDB_LOGO_BAND
);
700 /* Set server settings */
701 InbvSetTextColor(14);
702 InbvSolidColorFill(0, 0, 639, 479, 6);
703 InbvSolidColorFill(0, 421, 639, 479, 1);
706 Header
= InbvGetResourceAddress(IDB_SERVER_HEADER
);
707 Band
= InbvGetResourceAddress(IDB_SERVER_BAND
);
710 /* Set the scrolling region */
711 InbvSetScrollRegion(32, 80, 631, 400);
713 /* Make sure we have resources */
714 if ((Header
) && (Band
))
716 /* BitBlt them on the screen */
717 InbvBitBlt(Band
, 0, 419);
718 InbvBitBlt(Header
, 0, 0);
723 /* Is the boot driver installed? */
725 if (!InbvBootDriverInstalled
) return;
727 /* Load the standard boot screen */
728 Screen
= InbvGetResourceAddress(IDB_BOOT_LOGO
);
729 if (SharedUserData
->NtProductType
== NtProductWinNt
)
731 /* Workstation product, display appropriate status bar color */
732 InbvGetResourceAddress(IDB_BAR_PRO
);
736 /* Display correct branding based on server suite */
737 if (ExVerifySuite(StorageServer
))
739 /* Storage Server Edition */
740 Text
= InbvGetResourceAddress(IDB_STORAGE_SERVER
);
742 else if (ExVerifySuite(ComputeServer
))
744 /* Compute Cluster Edition */
745 Text
= InbvGetResourceAddress(IDB_CLUSTER_SERVER
);
750 Text
= InbvGetResourceAddress(IDB_SERVER_LOGO
);
753 /* Server product, display appropriate status bar color */
754 InbvGetResourceAddress(IDB_BAR_SERVER
);
757 /* Make sure we had a logo */
760 /* Choose progress bar */
761 TempRotBarSelection
= RB_SQUARE_CELLS
;
764 * Save the main image palette and replace it with black palette, so
765 * we can do fade in effect later.
767 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Screen
;
768 Palette
= (LPRGBQUAD
)((PUCHAR
)Screen
+ BitmapInfoHeader
->biSize
);
769 RtlCopyMemory(_MainPalette
, Palette
, sizeof(_MainPalette
));
770 RtlZeroMemory(Palette
, sizeof(_MainPalette
));
772 /* Blit the background */
773 InbvBitBlt(Screen
, 0, 0);
775 /* Set progress bar coordinates and display it */
776 InbvSetProgressBarCoordinates(257, 352);
778 /* Display the boot logo and fade it in */
782 /* Check for non-workstation products */
783 if (SharedUserData
->NtProductType
!= NtProductWinNt
)
785 /* Overwrite part of the logo for a server product */
786 InbvScreenToBufferBlt(Buffer
, 413, 237, 7, 7, 8);
787 InbvSolidColorFill(418, 230, 454, 256, 0);
788 InbvBufferToScreenBlt(Buffer
, 413, 237, 7, 7, 8);
790 /* In setup mode, you haven't selected a SKU yet */
791 if (ExpInTextModeSetup
) Text
= NULL
;
796 /* Draw the SKU text if it exits */
797 // if (Text) InbvBitBlt(Text, 180, 121);
799 /* Draw the progress bar bit */
800 // if (Bar) InbvBitBlt(Bar, 0, 0);
802 /* Set filter which will draw text display if needed */
803 InbvInstallDisplayStringFilter(DisplayFilter
);
806 /* Do we have a system thread? */
807 if (SysThreadCreated
)
809 /* We do, set the progress bar location */
811 RotBarSelection
= TempRotBarSelection
;
820 DisplayFilter(PCHAR
*String
)
822 /* Windows hack to skip first dots */
823 static BOOLEAN DotHack
= TRUE
;
825 /* If "." is given set *String to empty string */
826 if(DotHack
&& strcmp(*String
, ".") == 0)
831 /* Remove the filter */
832 InbvInstallDisplayStringFilter(NULL
);
836 /* Draw text screen */
837 DisplayBootBitmap(TRUE
);
844 FinalizeBootLogo(VOID
)
846 /* Acquire lock and check the display state */
848 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED
)
850 /* Clear the screen */
851 VidSolidColorFill(0, 0, 639, 479, 0);
854 /* Reset progress bar and lock */