Patch for better boot logo/progress bar, fixed /SOS (debug) boot screen/output, remov...
[reactos.git] / reactos / ntoskrnl / inbv / inbv.c
1 /* INCLUDES ******************************************************************/
2
3 #include <ntoskrnl.h>
4 #define NDEBUG
5 #include <debug.h>
6 #include "bootvid/bootvid.h"
7
8 /* GLOBALS *******************************************************************/
9
10 KSPIN_LOCK BootDriverLock;
11 KIRQL InbvOldIrql;
12 INBV_DISPLAY_STATE InbvDisplayState;
13 BOOLEAN InbvBootDriverInstalled;
14 BOOLEAN InbvDisplayDebugStrings;
15 INBV_DISPLAY_STRING_FILTER InbvDisplayFilter;
16 ULONG ProgressBarLeft, ProgressBarTop;
17 BOOLEAN ShowProgressBar;
18 INBV_PROGRESS_STATE InbvProgressState;
19 INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters;
20 ULONG ResourceCount;
21 PUCHAR ResourceList[64];
22 BOOLEAN SysThreadCreated;
23 ROT_BAR_TYPE RotBarSelection;
24 ULONG PltRotBarStatus;
25 BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
26
27 /* FUNCTIONS *****************************************************************/
28
29 PVOID
30 NTAPI
31 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
32 IN ULONG ResourceId)
33 {
34 UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
35 UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
36 PLIST_ENTRY NextEntry, ListHead;
37 PLDR_DATA_TABLE_ENTRY LdrEntry;
38 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
39 LDR_RESOURCE_INFO ResourceInfo;
40 ULONG Size;
41 NTSTATUS Status;
42 PVOID Data = NULL;
43
44 /* Loop the driver list */
45 ListHead = &LoaderBlock->LoadOrderListHead;
46 NextEntry = ListHead->Flink;
47 while (NextEntry != ListHead)
48 {
49 /* Get the entry */
50 LdrEntry = CONTAINING_RECORD(NextEntry,
51 LDR_DATA_TABLE_ENTRY,
52 InLoadOrderLinks);
53
54 /* Check for a match */
55 if ((RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE)) ||
56 (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE)))
57 {
58 /* Break out */
59 break;
60 }
61 }
62
63 /* Check if we found it */
64 if (NextEntry != ListHead)
65 {
66 /* Try to find the resource */
67 ResourceInfo.Type = 2;
68 ResourceInfo.Name = ResourceId;
69 ResourceInfo.Language = 0;
70 Status = LdrFindResource_U(LdrEntry->DllBase,
71 &ResourceInfo,
72 RESOURCE_DATA_LEVEL,
73 &ResourceDataEntry);
74 if (NT_SUCCESS(Status))
75 {
76 /* Access the resource */
77 Status = LdrAccessResource(LdrEntry->DllBase,
78 ResourceDataEntry,
79 &Data,
80 &Size);
81 if (!NT_SUCCESS(Status)) Data = NULL;
82 }
83 }
84
85 /* Return the pointer */
86 return Data;
87 }
88
89 BOOLEAN
90 NTAPI
91 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
92 IN ULONG Count)
93 {
94 PCHAR CommandLine;
95 BOOLEAN CustomLogo = FALSE;
96 ULONG i;
97
98 /* Quit if we're already installed */
99 if (InbvBootDriverInstalled) return TRUE;
100
101 /* Initialize the lock and check the current display state */
102 KeInitializeSpinLock(&BootDriverLock);
103 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
104 {
105 /* Check if we have a custom boot logo */
106 CommandLine = _strupr(LoaderBlock->LoadOptions);
107 CustomLogo = strstr(CommandLine, "BOOTLOGO") ? TRUE: FALSE;
108 }
109
110 /* Initialize the video */
111 InbvBootDriverInstalled = VidInitialize(FALSE);
112 if (InbvBootDriverInstalled)
113 {
114 /* Now reset the display, but only if there's a custom boot logo */
115 VidResetDisplay(CustomLogo);
116
117 /* Find bitmap resources in the kernel */
118 ResourceCount = Count;
119 for (i = 0; i < Count; i++)
120 {
121 /* Do the lookup */
122 ResourceList[i] = FindBitmapResource(LoaderBlock, i);
123 }
124
125 /* Set the progress bar ranges */
126 InbvSetProgressBarSubset(0, 100);
127 }
128
129 /* Return install state */
130 return InbvBootDriverInstalled;
131 }
132
133 VOID
134 NTAPI
135 InbvAcquireLock(VOID)
136 {
137 /* Check if we're below dispatch level */
138 InbvOldIrql = KeGetCurrentIrql();
139 if (InbvOldIrql < DISPATCH_LEVEL)
140 {
141 /* Raise IRQL to dispatch level */
142 KeRaiseIrql(DISPATCH_LEVEL, &InbvOldIrql);
143 }
144
145 /* Acquire the lock */
146 KiAcquireSpinLock(&BootDriverLock);
147 }
148
149 VOID
150 NTAPI
151 InbvReleaseLock(VOID)
152 {
153 /* Release the driver lock */
154 KiReleaseSpinLock(&BootDriverLock);
155
156 /* If we were below dispatch level, lower IRQL back */
157 if (InbvOldIrql < DISPATCH_LEVEL) KeLowerIrql(InbvOldIrql);
158 }
159
160 VOID
161 NTAPI
162 InbvEnableBootDriver(IN BOOLEAN Enable)
163 {
164 /* Check if we're installed */
165 if (InbvBootDriverInstalled)
166 {
167 /* Check for lost state */
168 if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
169
170 /* Acquire the lock */
171 InbvAcquireLock();
172
173 /* Cleanup the screen if we own it */
174 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
175
176 /* Set the new display state */
177 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED:
178 INBV_DISPLAY_STATE_DISABLED;
179
180 /* Release the lock */
181 InbvReleaseLock();
182 }
183 else
184 {
185 /* Set the new display state */
186 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED:
187 INBV_DISPLAY_STATE_DISABLED;
188 }
189 }
190
191 VOID
192 NTAPI
193 InbvAcquireDisplayOwnership(VOID)
194 {
195 /* Check if we have a callback and we're just acquiring it now */
196 if ((InbvResetDisplayParameters) &&
197 (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
198 {
199 /* Call the callback */
200 InbvResetDisplayParameters(80, 50);
201 }
202
203 /* Acquire the display */
204 InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
205 }
206
207 VOID
208 NTAPI
209 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
210 {
211 /* Set the new display state */
212 InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED:
213 INBV_DISPLAY_STATE_LOST;
214 }
215
216 BOOLEAN
217 NTAPI
218 InbvCheckDisplayOwnership(VOID)
219 {
220 /* Return if we own it or not */
221 return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
222 }
223
224 INBV_DISPLAY_STATE
225 NTAPI
226 InbvGetDisplayState(VOID)
227 {
228 /* Return the actual state */
229 return InbvDisplayState;
230 }
231
232 BOOLEAN
233 NTAPI
234 InbvDisplayString(IN PCHAR String)
235 {
236 /* Make sure we own the display */
237 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
238 {
239 /* If we're not allowed, return success anyway */
240 if (!InbvDisplayDebugStrings) return TRUE;
241
242 /* Check if a filter is installed */
243 if (InbvDisplayFilter) InbvDisplayFilter(&String);
244
245 /* Acquire the lock */
246 InbvAcquireLock();
247
248 /* Make sure we're installed and display the string */
249 if (InbvBootDriverInstalled) VidDisplayString((PUCHAR) String);
250
251 /* Call Headless (We don't support headless for now)
252 HeadlessDispatch(DISPLAY_STRING); */
253
254 /* Release the lock */
255 InbvReleaseLock();
256
257 /* All done */
258 return TRUE;
259 }
260
261 /* We don't own it, fail */
262 return FALSE;
263 }
264
265 BOOLEAN
266 NTAPI
267 InbvEnableDisplayString(IN BOOLEAN Enable)
268 {
269 BOOLEAN OldSetting;
270
271 /* Get the old setting */
272 OldSetting = InbvDisplayDebugStrings;
273
274 /* Update it */
275 InbvDisplayDebugStrings = Enable;
276
277 /* Return the old setting */
278 return OldSetting;
279 }
280
281 VOID
282 NTAPI
283 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
284 {
285 /* Save the filter */
286 InbvDisplayFilter = Filter;
287 }
288
289 BOOLEAN
290 NTAPI
291 InbvIsBootDriverInstalled(VOID)
292 {
293 /* Return driver state */
294 return InbvBootDriverInstalled;
295 }
296
297 VOID
298 NTAPI
299 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
300 {
301 /* Check if we're installed */
302 if (InbvBootDriverInstalled)
303 {
304 /* Acquire the lock and cleanup if we own the screen */
305 InbvAcquireLock();
306 if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
307
308 /* Set the reset callback and display state */
309 InbvResetDisplayParameters = Callback;
310 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
311
312 /* Release the lock */
313 InbvReleaseLock();
314 }
315 else
316 {
317 /* Set the reset callback and display state */
318 InbvResetDisplayParameters = Callback;
319 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
320 }
321 }
322
323 BOOLEAN
324 NTAPI
325 InbvResetDisplay(VOID)
326 {
327 /* Check if we're installed and we own it */
328 if ((InbvBootDriverInstalled) &&
329 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
330 {
331 /* Do the reset */
332 VidResetDisplay(TRUE);
333 return TRUE;
334 }
335
336 /* Nothing to reset */
337 return FALSE;
338 }
339
340 VOID
341 NTAPI
342 InbvSetScrollRegion(IN ULONG Left,
343 IN ULONG Top,
344 IN ULONG Width,
345 IN ULONG Height)
346 {
347 /* Just call bootvid */
348 VidSetScrollRegion(Left, Top, Width, Height);
349 }
350
351 VOID
352 NTAPI
353 InbvSetTextColor(IN ULONG Color)
354 {
355 /* FIXME: Headless */
356
357 /* Update the text color */
358 VidSetTextColor(Color);
359 }
360
361 VOID
362 NTAPI
363 InbvSolidColorFill(IN ULONG Left,
364 IN ULONG Top,
365 IN ULONG Width,
366 IN ULONG Height,
367 IN ULONG Color)
368 {
369 /* Make sure we own it */
370 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
371 {
372 /* Acquire the lock */
373 InbvAcquireLock();
374
375 /* Check if we're installed */
376 if (InbvBootDriverInstalled)
377 {
378 /* Call bootvid */
379 VidSolidColorFill(Left, Top, Width, Height, (UCHAR)Color);
380 }
381
382 /* FIXME: Headless */
383
384 /* Release the lock */
385 InbvReleaseLock();
386 }
387 }
388
389 VOID
390 NTAPI
391 InbvUpdateProgressBar(IN ULONG Progress)
392 {
393 ULONG FillCount, BoundedProgress;
394
395 /* Make sure the progress bar is enabled, that we own and are installed */
396 if ((ShowProgressBar) &&
397 (InbvBootDriverInstalled) &&
398 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
399 {
400 /* Compute fill count */
401 BoundedProgress = (InbvProgressState.Floor / 100) + Progress;
402 FillCount = 121 * (InbvProgressState.Bias * BoundedProgress) / 1000000;
403
404 /* Acquire the lock */
405 InbvAcquireLock();
406
407 /* Fill the progress bar */
408 VidSolidColorFill(ProgressBarLeft,
409 ProgressBarTop,
410 ProgressBarLeft + FillCount,
411 ProgressBarTop + 12,
412 11);
413
414 /* Release the lock */
415 InbvReleaseLock();
416 }
417 }
418
419 VOID
420 NTAPI
421 InbvBufferToScreenBlt(IN PUCHAR Buffer,
422 IN ULONG X,
423 IN ULONG Y,
424 IN ULONG Width,
425 IN ULONG Height,
426 IN ULONG Delta)
427 {
428 /* Check if we're installed and we own it */
429 if ((InbvBootDriverInstalled) &&
430 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
431 {
432 /* Do the blit */
433 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
434 }
435 }
436
437 VOID
438 NTAPI
439 InbvBitBlt(IN PUCHAR Buffer,
440 IN ULONG X,
441 IN ULONG Y)
442 {
443 /* Check if we're installed and we own it */
444 if ((InbvBootDriverInstalled) &&
445 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
446 {
447 /* Acquire the lock */
448 InbvAcquireLock();
449
450 /* Do the blit */
451 VidBitBlt(Buffer, X, Y);
452
453 /* Release the lock */
454 InbvReleaseLock();
455 }
456 }
457
458 VOID
459 NTAPI
460 InbvScreenToBufferBlt(IN PUCHAR Buffer,
461 IN ULONG X,
462 IN ULONG Y,
463 IN ULONG Width,
464 IN ULONG Height,
465 IN ULONG Delta)
466 {
467 /* Check if we're installed and we own it */
468 if ((InbvBootDriverInstalled) &&
469 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
470 {
471 /* Do the blit */
472 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
473 }
474 }
475
476 VOID
477 NTAPI
478 InbvSetProgressBarCoordinates(IN ULONG Left,
479 IN ULONG Top)
480 {
481 /* Update the coordinates */
482 ProgressBarLeft = Left;
483 ProgressBarTop = Top;
484
485 /* Enable the progress bar */
486 ShowProgressBar = TRUE;
487 }
488
489 VOID
490 NTAPI
491 InbvSetProgressBarSubset(IN ULONG Floor,
492 IN ULONG Ceiling)
493 {
494 /* Sanity checks */
495 ASSERT(Floor < Ceiling);
496 ASSERT(Ceiling <= 100);
497
498 /* Update the progress bar state */
499 InbvProgressState.Floor = Floor * 100;
500 InbvProgressState.Ceiling = Ceiling * 100;
501 InbvProgressState.Bias = (Ceiling * 100) - Floor;
502 }
503
504 VOID
505 NTAPI
506 InbvIndicateProgress(VOID)
507 {
508 ULONG Percentage;
509
510 /* Increase progress */
511 InbvProgressIndicator.Count++;
512
513 /* Compute new percentage */
514 Percentage = min(100 * InbvProgressIndicator.Count /
515 InbvProgressIndicator.Expected,
516 99);
517 if (Percentage != InbvProgressIndicator.Percentage)
518 {
519 /* Percentage has moved, update the progress bar */
520 InbvProgressIndicator.Percentage = Percentage;
521 InbvUpdateProgressBar(Percentage);
522 }
523 }
524
525 PUCHAR
526 NTAPI
527 InbvGetResourceAddress(IN ULONG ResourceNumber)
528 {
529 /* Validate the resource number */
530 if (ResourceNumber > ResourceCount) return NULL;
531
532 /* Return the address */
533 return ResourceList[ResourceNumber--];
534 }
535
536 NTSTATUS
537 NTAPI
538 NtDisplayString(IN PUNICODE_STRING DisplayString)
539 {
540 OEM_STRING OemString;
541
542 /* Convert the string to OEM and display it */
543 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
544 InbvDisplayString(OemString.Buffer);
545 RtlFreeOemString(&OemString);
546
547 /* Return success */
548 return STATUS_SUCCESS;
549 }
550
551 VOID
552 NTAPI
553 DisplayBootBitmap(IN BOOLEAN SosMode)
554 {
555 PVOID Header, Band, Bar, Text, Screen;
556 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
557 UCHAR Buffer[64];
558
559 /* Check if the system thread has already been created */
560 if (SysThreadCreated)
561 {
562 /* Reset the progress bar */
563 InbvAcquireLock();
564 RotBarSelection = 0;
565 InbvReleaseLock();
566 }
567
568 /* Check if this is SOS mode */
569 ShowProgressBar = FALSE;
570 if (SosMode)
571 {
572 /* Check if this is a server OS */
573 if (SharedUserData->NtProductType == NtProductWinNt)
574 {
575 /* It's not, set workstation settings */
576 InbvSetTextColor(15);
577 InbvSolidColorFill(0, 0, 639, 479, 7);
578 InbvSolidColorFill(0, 421, 639, 479, 1);
579
580 /* Get resources */
581 Header = InbvGetResourceAddress(IDB_LOGO_HEADER);
582 Band = InbvGetResourceAddress(IDB_LOGO_BAND);
583 }
584 else
585 {
586 /* Set server settings */
587 InbvSetTextColor(14);
588 InbvSolidColorFill(0, 0, 639, 479, 6);
589 InbvSolidColorFill(0, 421, 639, 479, 1);
590
591 /* Get resources */
592 Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
593 Band = InbvGetResourceAddress(IDB_SERVER_BAND);
594 }
595
596 /* Set the scrolling region */
597 InbvSetScrollRegion(32, 80, 631, 400);
598
599 /* Make sure we have resources */
600 if ((Header) && (Band))
601 {
602 /* BitBlt them on the screen */
603 InbvBitBlt(Band, 0, 419);
604 InbvBitBlt(Header, 0, 0);
605 }
606 }
607 else
608 {
609 /* Is the boot driver installed? */
610 Text = NULL;
611 if (!InbvBootDriverInstalled) return;
612
613 /* Load the standard boot screen */
614 Screen = InbvGetResourceAddress(IDB_BOOT_LOGO);
615 if (SharedUserData->NtProductType == NtProductWinNt)
616 {
617 /* Workstation product, display appropriate status bar color */
618 Bar = InbvGetResourceAddress(IDB_BAR_PRO);
619 }
620 else
621 {
622 /* Display correct branding based on server suite */
623 if (ExVerifySuite(StorageServer))
624 {
625 /* Storage Server Edition */
626 Text = InbvGetResourceAddress(IDB_STORAGE_SERVER);
627 }
628 else if (ExVerifySuite(ComputeServer))
629 {
630 /* Compute Cluster Edition */
631 Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER);
632 }
633 else
634 {
635 /* Normal edition */
636 Text = InbvGetResourceAddress(IDB_SERVER_LOGO);
637 }
638
639 /* Server product, display appropriate status bar color */
640 Bar = InbvGetResourceAddress(IDB_BAR_SERVER);
641 }
642
643 /* Make sure we had a logo */
644 if (Screen)
645 {
646 /* Choose progress bar */
647 TempRotBarSelection = RB_SQUARE_CELLS;
648
649 /* Blit the background */
650 InbvBitBlt(Screen, 0, 0);
651
652 /* Set progress bar coordinates and display it */
653 InbvSetProgressBarCoordinates(257, 352);
654
655 /* Check for non-workstation products */
656 if (SharedUserData->NtProductType != NtProductWinNt)
657 {
658 /* Overwrite part of the logo for a server product */
659 InbvScreenToBufferBlt(Buffer, 413, 237, 7, 7, 8);
660 InbvSolidColorFill(418, 230, 454, 256, 0);
661 InbvBufferToScreenBlt(Buffer, 413, 237, 7, 7, 8);
662
663 /* In setup mode, you haven't selected a SKU yet */
664 if (ExpInTextModeSetup) Text = NULL;
665 }
666 }
667
668 /* Draw the SKU text if it exits */
669 if (Text) InbvBitBlt(Text, 180, 121);
670
671 /* Draw the progress bar bit */
672 // if (Bar) InbvBitBlt(Bar, 0, 0);
673 }
674
675 /* Do we have a system thread? */
676 if (SysThreadCreated)
677 {
678 /* We do, set the progress bar location */
679 InbvAcquireLock();
680 RotBarSelection = TempRotBarSelection;
681 //InbvRotBarInit();
682 InbvReleaseLock();
683 }
684 }
685
686 VOID
687 NTAPI
688 FinalizeBootLogo(VOID)
689 {
690 /* Acquire lock and check the display state */
691 InbvAcquireLock();
692 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
693 {
694 /* Clear the screen */
695 VidSolidColorFill(0, 0, 639, 479, 0);
696 }
697
698 /* Reset progress bar and lock */
699 PltRotBarStatus = 3;
700 InbvReleaseLock();
701 }