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