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