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