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