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