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