[NTOS:INBV] Implement rotation bar for boot screen
[reactos.git] / ntoskrnl / inbv / inbv.c
1 /* INCLUDES ******************************************************************/
2
3 #include <ntoskrnl.h>
4 #define NDEBUG
5 #include <debug.h>
6 #include "bootvid/bootvid.h"
7
8 /* GLOBALS *******************************************************************/
9
10 /*
11 * Enable this define if you want Inbv to use coloured headless mode.
12 */
13 // #define INBV_HEADLESS_COLORS
14
15 /*
16 * ReactOS uses the same boot screen for all the products.
17 * Also it doesn't use a parallel system thread for the
18 * rotating "progress" bar.
19 */
20
21 /*
22 * Enable this define when ReactOS will have different SKUs
23 * (Workstation, Server, Storage Server, Cluster Server, etc...).
24 */
25 // #define REACTOS_SKUS
26
27 /*
28 * Enable this define when Inbv will support rotating progress bar.
29 */
30 #define INBV_ROTBAR_IMPLEMENTED
31
32 static KSPIN_LOCK BootDriverLock;
33 static KIRQL InbvOldIrql;
34 static INBV_DISPLAY_STATE InbvDisplayState = INBV_DISPLAY_STATE_DISABLED;
35 BOOLEAN InbvBootDriverInstalled = FALSE;
36 static BOOLEAN InbvDisplayDebugStrings = FALSE;
37 static INBV_DISPLAY_STRING_FILTER InbvDisplayFilter = NULL;
38 static ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
39 static BOOLEAN ShowProgressBar = FALSE;
40 static INBV_PROGRESS_STATE InbvProgressState;
41 static BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
42 static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
43 static ULONG ResourceCount = 0;
44 static PUCHAR ResourceList[1 + IDB_MAX_RESOURCE]; // First entry == NULL, followed by 'ResourceCount' entries.
45
46 #ifdef INBV_ROTBAR_IMPLEMENTED
47 /*
48 * Change this to modify progress bar behaviour
49 */
50 #define ROT_BAR_DEFAULT_MODE RB_PROGRESS_BAR
51 static BOOLEAN RotBarThreadActive = FALSE;
52 static ROT_BAR_TYPE RotBarSelection;
53 static ULONG PltRotBarStatus;
54 static UCHAR RotBarBuffer[24 * 9];
55 static UCHAR RotLineBuffer[640 * 6];
56 #endif
57
58
59 /*
60 * Headless terminal text colors
61 */
62
63 #ifdef INBV_HEADLESS_COLORS
64
65 // Conversion table CGA to ANSI color index
66 static const UCHAR CGA_TO_ANSI_COLOR_TABLE[16] =
67 {
68 0, // Black
69 4, // Blue
70 2, // Green
71 6, // Cyan
72 1, // Red
73 5, // Magenta
74 3, // Brown/Yellow
75 7, // Grey/White
76
77 60, // Bright Black
78 64, // Bright Blue
79 62, // Bright Green
80 66, // Bright Cyan
81 61, // Bright Red
82 65, // Bright Magenta
83 63, // Bright Yellow
84 67 // Bright Grey (White)
85 };
86
87 #define CGA_TO_ANSI_COLOR(CgaColor) \
88 CGA_TO_ANSI_COLOR_TABLE[CgaColor & 0x0F]
89
90 #endif
91
92 // Default colors: text in white, background in black
93 static ULONG InbvTerminalTextColor = 37;
94 static ULONG InbvTerminalBkgdColor = 40;
95
96
97 /* FADING FUNCTION ***********************************************************/
98
99 /** From include/psdk/wingdi.h **/
100 typedef struct tagRGBQUAD
101 {
102 UCHAR rgbBlue;
103 UCHAR rgbGreen;
104 UCHAR rgbRed;
105 UCHAR rgbReserved;
106 } RGBQUAD,*LPRGBQUAD;
107 /*******************************/
108
109 static RGBQUAD MainPalette[16];
110
111 #define PALETTE_FADE_STEPS 15
112 #define PALETTE_FADE_TIME 20 * 1000 /* 20ms */
113
114 /** From bootvid/precomp.h **/
115 //
116 // Bitmap Header
117 //
118 typedef struct tagBITMAPINFOHEADER
119 {
120 ULONG biSize;
121 LONG biWidth;
122 LONG biHeight;
123 USHORT biPlanes;
124 USHORT biBitCount;
125 ULONG biCompression;
126 ULONG biSizeImage;
127 LONG biXPelsPerMeter;
128 LONG biYPelsPerMeter;
129 ULONG biClrUsed;
130 ULONG biClrImportant;
131 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
132 /****************************/
133
134 //
135 // Needed prototypes
136 //
137 VOID NTAPI InbvAcquireLock(VOID);
138 VOID NTAPI InbvReleaseLock(VOID);
139
140 static VOID
141 BootLogoFadeIn(VOID)
142 {
143 UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)];
144 PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer;
145 LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER));
146
147 ULONG Iteration, Index, ClrUsed;
148
149 /* Check if we're installed and we own it */
150 if (InbvBootDriverInstalled &&
151 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
152 {
153 /* Acquire the lock */
154 InbvAcquireLock();
155
156 /*
157 * Build a bitmap containing the fade in palette. The palette entries
158 * are then processed in a loop and set using VidBitBlt function.
159 */
160 ClrUsed = RTL_NUMBER_OF(MainPalette);
161 RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER));
162 PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER);
163 PaletteBitmap->biBitCount = 4;
164 PaletteBitmap->biClrUsed = ClrUsed;
165
166 /*
167 * Main animation loop.
168 */
169 for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration)
170 {
171 for (Index = 0; Index < ClrUsed; Index++)
172 {
173 Palette[Index].rgbRed = (UCHAR)
174 (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS);
175 Palette[Index].rgbGreen = (UCHAR)
176 (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS);
177 Palette[Index].rgbBlue = (UCHAR)
178 (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS);
179 }
180
181 VidBitBlt(PaletteBitmapBuffer, 0, 0);
182
183 /* Wait for a bit */
184 KeStallExecutionProcessor(PALETTE_FADE_TIME);
185 }
186
187 /* Release the lock */
188 InbvReleaseLock();
189
190 /* Wait for a bit */
191 KeStallExecutionProcessor(PALETTE_FADE_TIME);
192 }
193 }
194
195 /* FUNCTIONS *****************************************************************/
196
197 PVOID
198 NTAPI
199 INIT_FUNCTION
200 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
201 IN ULONG ResourceId)
202 {
203 UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
204 UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
205 PLIST_ENTRY NextEntry, ListHead;
206 PLDR_DATA_TABLE_ENTRY LdrEntry;
207 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
208 LDR_RESOURCE_INFO ResourceInfo;
209 NTSTATUS Status;
210 PVOID Data = NULL;
211
212 /* Loop the driver list */
213 ListHead = &LoaderBlock->LoadOrderListHead;
214 NextEntry = ListHead->Flink;
215 while (NextEntry != ListHead)
216 {
217 /* Get the entry */
218 LdrEntry = CONTAINING_RECORD(NextEntry,
219 LDR_DATA_TABLE_ENTRY,
220 InLoadOrderLinks);
221
222 /* Check for a match */
223 if (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE) ||
224 RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE))
225 {
226 /* Break out */
227 break;
228 }
229 }
230
231 /* Check if we found it */
232 if (NextEntry != ListHead)
233 {
234 /* Try to find the resource */
235 ResourceInfo.Type = 2; // RT_BITMAP;
236 ResourceInfo.Name = ResourceId;
237 ResourceInfo.Language = 0;
238 Status = LdrFindResource_U(LdrEntry->DllBase,
239 &ResourceInfo,
240 RESOURCE_DATA_LEVEL,
241 &ResourceDataEntry);
242 if (NT_SUCCESS(Status))
243 {
244 /* Access the resource */
245 ULONG Size = 0;
246 Status = LdrAccessResource(LdrEntry->DllBase,
247 ResourceDataEntry,
248 &Data,
249 &Size);
250 if ((Data) && (ResourceId < 3))
251 {
252 KiBugCheckData[4] ^= RtlComputeCrc32(0, Data, Size);
253 }
254 if (!NT_SUCCESS(Status)) Data = NULL;
255 }
256 }
257
258 /* Return the pointer */
259 return Data;
260 }
261
262 BOOLEAN
263 NTAPI
264 INIT_FUNCTION
265 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
266 IN ULONG Count)
267 {
268 PCHAR CommandLine;
269 BOOLEAN ResetMode = FALSE; // By default do not reset the video mode
270 ULONG i;
271
272 /* Quit if we're already installed */
273 if (InbvBootDriverInstalled) return TRUE;
274
275 /* Initialize the lock and check the current display state */
276 KeInitializeSpinLock(&BootDriverLock);
277 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
278 {
279 /* Reset the video mode in case we do not have a custom boot logo */
280 CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL);
281 ResetMode = (CommandLine == NULL) || (strstr(CommandLine, "BOOTLOGO") == NULL);
282 }
283
284 /* Initialize the video */
285 InbvBootDriverInstalled = VidInitialize(ResetMode);
286 if (InbvBootDriverInstalled)
287 {
288 /* Find bitmap resources in the kernel */
289 ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1);
290 for (i = 1; i <= ResourceCount; i++)
291 {
292 /* Do the lookup */
293 ResourceList[i] = FindBitmapResource(LoaderBlock, i);
294 }
295
296 /* Set the progress bar ranges */
297 InbvSetProgressBarSubset(0, 100);
298 }
299
300 /* Return install state */
301 return InbvBootDriverInstalled;
302 }
303
304 VOID
305 NTAPI
306 InbvAcquireLock(VOID)
307 {
308 KIRQL OldIrql;
309
310 /* Check if we're at dispatch level or lower */
311 OldIrql = KeGetCurrentIrql();
312 if (OldIrql <= DISPATCH_LEVEL)
313 {
314 /* Loop until the lock is free */
315 while (!KeTestSpinLock(&BootDriverLock));
316
317 /* Raise IRQL to dispatch level */
318 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
319 }
320
321 /* Acquire the lock */
322 KiAcquireSpinLock(&BootDriverLock);
323 InbvOldIrql = OldIrql;
324 }
325
326 VOID
327 NTAPI
328 InbvReleaseLock(VOID)
329 {
330 KIRQL OldIrql;
331
332 /* Capture the old IRQL */
333 OldIrql = InbvOldIrql;
334
335 /* Release the driver lock */
336 KiReleaseSpinLock(&BootDriverLock);
337
338 /* If we were at dispatch level or lower, restore the old IRQL */
339 if (InbvOldIrql <= DISPATCH_LEVEL) KeLowerIrql(OldIrql);
340 }
341
342 VOID
343 NTAPI
344 INIT_FUNCTION
345 InbvEnableBootDriver(IN BOOLEAN Enable)
346 {
347 /* Check if we're installed */
348 if (InbvBootDriverInstalled)
349 {
350 /* Check for lost state */
351 if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
352
353 /* Acquire the lock */
354 InbvAcquireLock();
355
356 /* Cleanup the screen if we own it */
357 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
358
359 /* Set the new display state */
360 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
361 INBV_DISPLAY_STATE_DISABLED;
362
363 /* Release the lock */
364 InbvReleaseLock();
365 }
366 else
367 {
368 /* Set the new display state */
369 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
370 INBV_DISPLAY_STATE_DISABLED;
371 }
372 }
373
374 VOID
375 NTAPI
376 InbvAcquireDisplayOwnership(VOID)
377 {
378 /* Check if we have a callback and we're just acquiring it now */
379 if ((InbvResetDisplayParameters) &&
380 (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
381 {
382 /* Call the callback */
383 InbvResetDisplayParameters(80, 50);
384 }
385
386 /* Acquire the display */
387 InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
388 }
389
390 VOID
391 NTAPI
392 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
393 {
394 /* Set the new display state */
395 InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED :
396 INBV_DISPLAY_STATE_LOST;
397 }
398
399 BOOLEAN
400 NTAPI
401 InbvCheckDisplayOwnership(VOID)
402 {
403 /* Return if we own it or not */
404 return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
405 }
406
407 INBV_DISPLAY_STATE
408 NTAPI
409 InbvGetDisplayState(VOID)
410 {
411 /* Return the actual state */
412 return InbvDisplayState;
413 }
414
415 BOOLEAN
416 NTAPI
417 InbvDisplayString(IN PCHAR String)
418 {
419 /* Make sure we own the display */
420 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
421 {
422 /* If we're not allowed, return success anyway */
423 if (!InbvDisplayDebugStrings) return TRUE;
424
425 /* Check if a filter is installed */
426 if (InbvDisplayFilter) InbvDisplayFilter(&String);
427
428 /* Acquire the lock */
429 InbvAcquireLock();
430
431 /* Make sure we're installed and display the string */
432 if (InbvBootDriverInstalled) VidDisplayString((PUCHAR)String);
433
434 /* Print the string on the EMS port */
435 HeadlessDispatch(HeadlessCmdPutString,
436 String,
437 strlen(String) + sizeof(ANSI_NULL),
438 NULL,
439 NULL);
440
441 /* Release the lock */
442 InbvReleaseLock();
443
444 /* All done */
445 return TRUE;
446 }
447
448 /* We don't own it, fail */
449 return FALSE;
450 }
451
452 BOOLEAN
453 NTAPI
454 InbvEnableDisplayString(IN BOOLEAN Enable)
455 {
456 BOOLEAN OldSetting;
457
458 /* Get the old setting */
459 OldSetting = InbvDisplayDebugStrings;
460
461 /* Update it */
462 InbvDisplayDebugStrings = Enable;
463
464 /* Return the old setting */
465 return OldSetting;
466 }
467
468 VOID
469 NTAPI
470 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
471 {
472 /* Save the filter */
473 InbvDisplayFilter = Filter;
474 }
475
476 BOOLEAN
477 NTAPI
478 InbvIsBootDriverInstalled(VOID)
479 {
480 /* Return driver state */
481 return InbvBootDriverInstalled;
482 }
483
484 VOID
485 NTAPI
486 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
487 {
488 /* Check if we're installed */
489 if (InbvBootDriverInstalled)
490 {
491 /* Acquire the lock and cleanup if we own the screen */
492 InbvAcquireLock();
493 if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
494
495 /* Set the reset callback and display state */
496 InbvResetDisplayParameters = Callback;
497 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
498
499 /* Release the lock */
500 InbvReleaseLock();
501 }
502 else
503 {
504 /* Set the reset callback and display state */
505 InbvResetDisplayParameters = Callback;
506 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
507 }
508 }
509
510 BOOLEAN
511 NTAPI
512 InbvResetDisplay(VOID)
513 {
514 /* Check if we're installed and we own it */
515 if (InbvBootDriverInstalled &&
516 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
517 {
518 /* Do the reset */
519 VidResetDisplay(TRUE);
520 return TRUE;
521 }
522
523 /* Nothing to reset */
524 return FALSE;
525 }
526
527 VOID
528 NTAPI
529 InbvSetScrollRegion(IN ULONG Left,
530 IN ULONG Top,
531 IN ULONG Right,
532 IN ULONG Bottom)
533 {
534 /* Just call bootvid */
535 VidSetScrollRegion(Left, Top, Right, Bottom);
536 }
537
538 VOID
539 NTAPI
540 InbvSetTextColor(IN ULONG Color)
541 {
542 HEADLESS_CMD_SET_COLOR HeadlessSetColor;
543
544 /* Set color for EMS port */
545 #ifdef INBV_HEADLESS_COLORS
546 InbvTerminalTextColor = 30 + CGA_TO_ANSI_COLOR(Color);
547 #else
548 InbvTerminalTextColor = 37;
549 #endif
550 HeadlessSetColor.TextColor = InbvTerminalTextColor;
551 HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
552 HeadlessDispatch(HeadlessCmdSetColor,
553 &HeadlessSetColor,
554 sizeof(HeadlessSetColor),
555 NULL,
556 NULL);
557
558 /* Update the text color */
559 VidSetTextColor(Color);
560 }
561
562 VOID
563 NTAPI
564 InbvSolidColorFill(IN ULONG Left,
565 IN ULONG Top,
566 IN ULONG Right,
567 IN ULONG Bottom,
568 IN ULONG Color)
569 {
570 HEADLESS_CMD_SET_COLOR HeadlessSetColor;
571
572 /* Make sure we own it */
573 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
574 {
575 /* Acquire the lock */
576 InbvAcquireLock();
577
578 /* Check if we're installed */
579 if (InbvBootDriverInstalled)
580 {
581 /* Call bootvid */
582 VidSolidColorFill(Left, Top, Right, Bottom, (UCHAR)Color);
583 }
584
585 /* Set color for EMS port and clear display */
586 #ifdef INBV_HEADLESS_COLORS
587 InbvTerminalBkgdColor = 40 + CGA_TO_ANSI_COLOR(Color);
588 #else
589 InbvTerminalBkgdColor = 40;
590 #endif
591 HeadlessSetColor.TextColor = InbvTerminalTextColor;
592 HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
593 HeadlessDispatch(HeadlessCmdSetColor,
594 &HeadlessSetColor,
595 sizeof(HeadlessSetColor),
596 NULL,
597 NULL);
598 HeadlessDispatch(HeadlessCmdClearDisplay,
599 NULL, 0,
600 NULL, NULL);
601
602 /* Release the lock */
603 InbvReleaseLock();
604 }
605 }
606
607 VOID
608 NTAPI
609 INIT_FUNCTION
610 InbvUpdateProgressBar(IN ULONG Progress)
611 {
612 ULONG FillCount, BoundedProgress;
613
614 /* Make sure the progress bar is enabled, that we own and are installed */
615 if (ShowProgressBar &&
616 InbvBootDriverInstalled &&
617 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
618 {
619 /* Compute fill count */
620 BoundedProgress = (InbvProgressState.Floor / 100) + Progress;
621 FillCount = 121 * (InbvProgressState.Bias * BoundedProgress) / 1000000;
622
623 /* Acquire the lock */
624 InbvAcquireLock();
625
626 /* Fill the progress bar */
627 VidSolidColorFill(ProgressBarLeft,
628 ProgressBarTop,
629 ProgressBarLeft + FillCount,
630 ProgressBarTop + 12,
631 15);
632
633 /* Release the lock */
634 InbvReleaseLock();
635 }
636 }
637
638 VOID
639 NTAPI
640 InbvBufferToScreenBlt(IN PUCHAR Buffer,
641 IN ULONG X,
642 IN ULONG Y,
643 IN ULONG Width,
644 IN ULONG Height,
645 IN ULONG Delta)
646 {
647 /* Check if we're installed and we own it */
648 if (InbvBootDriverInstalled &&
649 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
650 {
651 /* Do the blit */
652 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
653 }
654 }
655
656 VOID
657 NTAPI
658 InbvBitBlt(IN PUCHAR Buffer,
659 IN ULONG X,
660 IN ULONG Y)
661 {
662 /* Check if we're installed and we own it */
663 if (InbvBootDriverInstalled &&
664 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
665 {
666 /* Acquire the lock */
667 InbvAcquireLock();
668
669 /* Do the blit */
670 VidBitBlt(Buffer, X, Y);
671
672 /* Release the lock */
673 InbvReleaseLock();
674 }
675 }
676
677 VOID
678 NTAPI
679 InbvScreenToBufferBlt(IN PUCHAR Buffer,
680 IN ULONG X,
681 IN ULONG Y,
682 IN ULONG Width,
683 IN ULONG Height,
684 IN ULONG Delta)
685 {
686 /* Check if we're installed and we own it */
687 if (InbvBootDriverInstalled &&
688 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
689 {
690 /* Do the blit */
691 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
692 }
693 }
694
695 VOID
696 NTAPI
697 InbvSetProgressBarCoordinates(IN ULONG Left,
698 IN ULONG Top)
699 {
700 /* Update the coordinates */
701 ProgressBarLeft = Left;
702 ProgressBarTop = Top;
703
704 /* Enable the progress bar */
705 ShowProgressBar = TRUE;
706 }
707
708 VOID
709 NTAPI
710 InbvSetProgressBarSubset(IN ULONG Floor,
711 IN ULONG Ceiling)
712 {
713 /* Sanity checks */
714 ASSERT(Floor < Ceiling);
715 ASSERT(Ceiling <= 100);
716
717 /* Update the progress bar state */
718 InbvProgressState.Floor = Floor * 100;
719 InbvProgressState.Ceiling = Ceiling * 100;
720 InbvProgressState.Bias = (Ceiling * 100) - Floor;
721 }
722
723 VOID
724 NTAPI
725 INIT_FUNCTION
726 InbvIndicateProgress(VOID)
727 {
728 ULONG Percentage;
729
730 /* Increase progress */
731 InbvProgressIndicator.Count++;
732
733 /* Compute new percentage */
734 Percentage = min(100 * InbvProgressIndicator.Count /
735 InbvProgressIndicator.Expected,
736 99);
737 if (Percentage != InbvProgressIndicator.Percentage)
738 {
739 /* Percentage has moved, update the progress bar */
740 InbvProgressIndicator.Percentage = Percentage;
741 InbvUpdateProgressBar(Percentage);
742 }
743 }
744
745 PUCHAR
746 NTAPI
747 InbvGetResourceAddress(IN ULONG ResourceNumber)
748 {
749 /* Validate the resource number */
750 if (ResourceNumber > ResourceCount) return NULL;
751
752 /* Return the address */
753 return ResourceList[ResourceNumber];
754 }
755
756 NTSTATUS
757 NTAPI
758 NtDisplayString(IN PUNICODE_STRING DisplayString)
759 {
760 OEM_STRING OemString;
761
762 /* Convert the string to OEM and display it */
763 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
764 InbvDisplayString(OemString.Buffer);
765 RtlFreeOemString(&OemString);
766
767 /* Return success */
768 return STATUS_SUCCESS;
769 }
770
771 #ifdef INBV_ROTBAR_IMPLEMENTED
772 static
773 VOID
774 NTAPI
775 InbvRotationThread(
776 _In_ PVOID Context)
777 {
778 ULONG X, Y, Index, Total;
779 LARGE_INTEGER Delay = {{0}};
780
781 InbvAcquireLock();
782 if (RotBarSelection == RB_SQUARE_CELLS)
783 {
784 Index = 0;
785 }
786 else
787 {
788 Index = 32;
789 }
790 X = ProgressBarLeft + 2;
791 Y = ProgressBarTop + 2;
792 InbvReleaseLock();
793
794 while (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
795 {
796 /* Wait for a bit */
797 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
798
799 InbvAcquireLock();
800
801 /* Unknown unexpected command */
802 ASSERT(PltRotBarStatus <= 3);
803
804 if (PltRotBarStatus == 3)
805 {
806 /* Stop the thread */
807 InbvReleaseLock();
808 break;
809 }
810
811 if (RotBarSelection == RB_SQUARE_CELLS)
812 {
813 Delay.QuadPart = -800000; // 80 ms
814 Total = 18;
815 Index %= Total;
816
817 if (Index >= 3)
818 {
819 /* Fill previous bar position */
820 VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, 0);
821 }
822 if (Index < Total - 1)
823 {
824 /* Draw the progress bar bit */
825 if (Index < 2)
826 {
827 /* Appearing from the left */
828 VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8 * (2 - Index), 9, 24);
829 }
830 else if (Index >= Total - 3)
831 {
832 /* Hiding to the right */
833 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 * (4 - (Total - Index)), 9, 24);
834 }
835 else
836 {
837 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9, 24);
838 }
839 }
840 Index++;
841 }
842 else if (RotBarSelection == RB_PROGRESS_BAR)
843 {
844 Delay.QuadPart = -600000; // 60 ms
845 Total = 640;
846 Index %= Total;
847
848 /* Right part */
849 VidBufferToScreenBlt(RotLineBuffer, Index, 474, 640 - Index, 6, 640);
850 if (Index > 0)
851 {
852 /* Left part */
853 VidBufferToScreenBlt(RotLineBuffer + (640 - Index) / 2, 0, 474, Index - 2, 6, 640);
854 }
855 Index += 32;
856 }
857
858 InbvReleaseLock();
859 }
860
861 PsTerminateSystemThread(STATUS_SUCCESS);
862 }
863
864 VOID
865 NTAPI
866 INIT_FUNCTION
867 InbvRotBarInit(VOID)
868 {
869 PltRotBarStatus = 1;
870 }
871 #endif
872
873 VOID
874 NTAPI
875 INIT_FUNCTION
876 DisplayBootBitmap(IN BOOLEAN TextMode)
877 {
878 PVOID Header = NULL, Footer = NULL, Screen = NULL;
879
880 #ifdef INBV_ROTBAR_IMPLEMENTED
881 UCHAR Buffer[24 * 9];
882 PVOID Bar = NULL, LineBmp = NULL;
883 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
884 NTSTATUS Status;
885 HANDLE ThreadHandle = NULL;
886 #endif
887
888 #ifdef REACTOS_SKUS
889 PVOID Text = NULL;
890 #endif
891
892 #ifdef INBV_ROTBAR_IMPLEMENTED
893 /* Check if the system thread has already been created */
894 if (RotBarThreadActive)
895 {
896 /* Reset the progress bar */
897 InbvAcquireLock();
898 RotBarSelection = RB_UNSPECIFIED;
899 InbvReleaseLock();
900 }
901 #endif
902
903 ShowProgressBar = FALSE;
904
905 /* Check if this is text mode */
906 if (TextMode)
907 {
908 /* Check the type of the OS: workstation or server */
909 if (SharedUserData->NtProductType == NtProductWinNt)
910 {
911 /* Workstation; set colors */
912 InbvSetTextColor(15);
913 InbvSolidColorFill(0, 0, 639, 479, 7);
914 InbvSolidColorFill(0, 421, 639, 479, 1);
915
916 /* Get resources */
917 Header = InbvGetResourceAddress(IDB_WKSTA_HEADER);
918 Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER);
919 }
920 else
921 {
922 /* Server; set colors */
923 InbvSetTextColor(14);
924 InbvSolidColorFill(0, 0, 639, 479, 6);
925 InbvSolidColorFill(0, 421, 639, 479, 1);
926
927 /* Get resources */
928 Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
929 Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER);
930 }
931
932 /* Set the scrolling region */
933 InbvSetScrollRegion(32, 80, 631, 400);
934
935 /* Make sure we have resources */
936 if (Header && Footer)
937 {
938 /* BitBlt them on the screen */
939 InbvBitBlt(Footer, 0, 419);
940 InbvBitBlt(Header, 0, 0);
941 }
942 }
943 else
944 {
945 /* Is the boot driver installed? */
946 if (!InbvBootDriverInstalled) return;
947
948 /* Load the standard boot screen */
949 Screen = InbvGetResourceAddress(IDB_BOOT_SCREEN);
950
951 #ifdef REACTOS_SKUS
952 Text = NULL;
953 if (SharedUserData->NtProductType == NtProductWinNt)
954 {
955 #ifdef INBV_ROTBAR_IMPLEMENTED
956 /* Workstation product, use appropriate status bar color */
957 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
958 #endif
959 }
960 else
961 {
962 /* Display correct branding based on server suite */
963 if (ExVerifySuite(StorageServer))
964 {
965 /* Storage Server Edition */
966 Text = InbvGetResourceAddress(IDB_STORAGE_SERVER);
967 }
968 else if (ExVerifySuite(ComputeServer))
969 {
970 /* Compute Cluster Edition */
971 Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER);
972 }
973 else
974 {
975 /* Normal edition */
976 Text = InbvGetResourceAddress(IDB_SERVER_LOGO);
977 }
978
979 #ifdef INBV_ROTBAR_IMPLEMENTED
980 /* Server product, use appropriate status bar color */
981 Bar = InbvGetResourceAddress(IDB_BAR_SERVER);
982 #endif
983 }
984 #else
985 /* Use default status bar */
986 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
987 #endif
988
989 /* Make sure we have a logo */
990 if (Screen)
991 {
992 PBITMAPINFOHEADER BitmapInfoHeader;
993 LPRGBQUAD Palette;
994
995 /*
996 * Save the main image palette and replace it with black palette,
997 * so that we can do fade in effect later.
998 */
999 BitmapInfoHeader = (PBITMAPINFOHEADER)Screen;
1000 Palette = (LPRGBQUAD)((PUCHAR)Screen + BitmapInfoHeader->biSize);
1001 RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette));
1002 RtlZeroMemory(Palette, sizeof(MainPalette));
1003
1004 /* Blit the background */
1005 InbvBitBlt(Screen, 0, 0);
1006
1007 #ifdef INBV_ROTBAR_IMPLEMENTED
1008 /* Choose progress bar */
1009 TempRotBarSelection = ROT_BAR_DEFAULT_MODE;
1010 #endif
1011
1012 /* Set progress bar coordinates and display it */
1013 InbvSetProgressBarCoordinates(259, 352);
1014
1015 #ifdef REACTOS_SKUS
1016 /* Check for non-workstation products */
1017 if (SharedUserData->NtProductType != NtProductWinNt)
1018 {
1019 /* Overwrite part of the logo for a server product */
1020 InbvScreenToBufferBlt(Buffer, 413, 237, 7, 7, 8);
1021 InbvSolidColorFill(418, 230, 454, 256, 0);
1022 InbvBufferToScreenBlt(Buffer, 413, 237, 7, 7, 8);
1023
1024 /* In setup mode, you haven't selected a SKU yet */
1025 if (ExpInTextModeSetup) Text = NULL;
1026 }
1027 #endif
1028 }
1029
1030 #ifdef REACTOS_SKUS
1031 /* Draw the SKU text if it exits */
1032 if (Text) InbvBitBlt(Text, 180, 121);
1033 #endif
1034
1035 #ifdef INBV_ROTBAR_IMPLEMENTED
1036 if (Bar)
1037 {
1038 /* Save previous screen pixels to buffer */
1039 InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24);
1040 /* Draw the progress bar bit */
1041 InbvBitBlt(Bar, 0, 0);
1042 /* Store it in global buffer */
1043 InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24);
1044 /* Restore screen pixels */
1045 InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24);
1046 }
1047
1048 if (TempRotBarSelection == RB_PROGRESS_BAR)
1049 {
1050 LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE);
1051 if (LineBmp)
1052 {
1053 /* Draw the line and store it in global buffer */
1054 InbvBitBlt(LineBmp, 0, 474);
1055 InbvScreenToBufferBlt(RotLineBuffer, 0, 474, 640, 6, 640);
1056 }
1057 }
1058 else
1059 {
1060 /* Hide the simple progress bar if not used */
1061 ShowProgressBar = FALSE;
1062 }
1063 #endif
1064
1065 /* Display the boot logo and fade it in */
1066 BootLogoFadeIn();
1067
1068 #ifdef INBV_ROTBAR_IMPLEMENTED
1069 if (!RotBarThreadActive && TempRotBarSelection != RB_UNSPECIFIED)
1070 {
1071 /* Start the animation thread */
1072 Status = PsCreateSystemThread(&ThreadHandle,
1073 0,
1074 NULL,
1075 NULL,
1076 NULL,
1077 InbvRotationThread,
1078 NULL);
1079 if (NT_SUCCESS(Status))
1080 {
1081 RotBarThreadActive = TRUE;
1082 ObCloseHandle(ThreadHandle, KernelMode);
1083 }
1084 }
1085 #endif
1086
1087 /* Set filter which will draw text display if needed */
1088 InbvInstallDisplayStringFilter(DisplayFilter);
1089 }
1090
1091 #ifdef INBV_ROTBAR_IMPLEMENTED
1092 /* Do we have a system thread? */
1093 if (RotBarThreadActive)
1094 {
1095 /* We do, initialize the progress bar */
1096 InbvAcquireLock();
1097 RotBarSelection = TempRotBarSelection;
1098 InbvRotBarInit();
1099 InbvReleaseLock();
1100
1101 // FIXME: This was added to allow animation start before the processor hangs
1102 if (TempRotBarSelection != RB_UNSPECIFIED)
1103 {
1104 LARGE_INTEGER Delay;
1105 Delay.QuadPart = -3000000; // 300 ms
1106 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
1107 }
1108 }
1109 #endif
1110 }
1111
1112 VOID
1113 NTAPI
1114 INIT_FUNCTION
1115 DisplayFilter(PCHAR *String)
1116 {
1117 /* Windows hack to skip first dots */
1118 static BOOLEAN DotHack = TRUE;
1119
1120 /* If "." is given set *String to empty string */
1121 if(DotHack && strcmp(*String, ".") == 0)
1122 *String = "";
1123
1124 if(**String)
1125 {
1126 /* Remove the filter */
1127 InbvInstallDisplayStringFilter(NULL);
1128
1129 DotHack = FALSE;
1130
1131 /* Draw text screen */
1132 DisplayBootBitmap(TRUE);
1133 }
1134 }
1135
1136 VOID
1137 NTAPI
1138 INIT_FUNCTION
1139 FinalizeBootLogo(VOID)
1140 {
1141 /* Acquire lock and check the display state */
1142 InbvAcquireLock();
1143 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
1144 {
1145 /* Clear the screen */
1146 VidSolidColorFill(0, 0, 639, 479, 0);
1147 }
1148
1149 /* Reset progress bar and lock */
1150 #ifdef INBV_ROTBAR_IMPLEMENTED
1151 PltRotBarStatus = 3;
1152 RotBarThreadActive = FALSE;
1153 #endif
1154 InbvReleaseLock();
1155 }