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