9fcba6a7579ae48f0d785ca680d1e5c4dfa1fad5
[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 //
9 // Bitmap Header
10 //
11 typedef struct tagBITMAPINFOHEADER
12 {
13 ULONG biSize;
14 LONG biWidth;
15 LONG biHeight;
16 USHORT biPlanes;
17 USHORT biBitCount;
18 ULONG biCompression;
19 ULONG biSizeImage;
20 LONG biXPelsPerMeter;
21 LONG biYPelsPerMeter;
22 ULONG biClrUsed;
23 ULONG biClrImportant;
24 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
25
26 /* GLOBALS *******************************************************************/
27
28 KSPIN_LOCK BootDriverLock;
29 KIRQL InbvOldIrql;
30 INBV_DISPLAY_STATE InbvDisplayState;
31 BOOLEAN InbvBootDriverInstalled;
32 BOOLEAN InbvDisplayDebugStrings;
33 INBV_DISPLAY_STRING_FILTER InbvDisplayFilter;
34 ULONG ProgressBarLeft, ProgressBarTop;
35 BOOLEAN ShowProgressBar;
36 INBV_PROGRESS_STATE InbvProgressState;
37 INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters;
38 ULONG ResourceCount;
39 PUCHAR ResourceList[64];
40 BOOLEAN SysThreadCreated;
41 ROT_BAR_TYPE RotBarSelection;
42 ULONG PltRotBarStatus;
43
44 /* FUNCTIONS *****************************************************************/
45
46 PVOID
47 NTAPI
48 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
49 IN ULONG ResourceId)
50 {
51 UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
52 UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
53 PLIST_ENTRY NextEntry, ListHead;
54 PLDR_DATA_TABLE_ENTRY LdrEntry;
55 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
56 LDR_RESOURCE_INFO ResourceInfo;
57 ULONG Size;
58 NTSTATUS Status;
59 PVOID Data = NULL;
60
61 /* Loop the driver list */
62 ListHead = &LoaderBlock->LoadOrderListHead;
63 NextEntry = ListHead->Flink;
64 while (NextEntry != ListHead)
65 {
66 /* Get the entry */
67 LdrEntry = CONTAINING_RECORD(NextEntry,
68 LDR_DATA_TABLE_ENTRY,
69 InLoadOrderLinks);
70
71 /* Check for a match */
72 if ((RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE)) ||
73 (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE)))
74 {
75 /* Break out */
76 break;
77 }
78 }
79
80 /* Check if we found it */
81 if (NextEntry != ListHead)
82 {
83 /* Try to find the resource */
84 ResourceInfo.Type = 2;
85 ResourceInfo.Name = ResourceId;
86 ResourceInfo.Language = 0;
87 Status = LdrFindResource_U(LdrEntry->DllBase,
88 &ResourceInfo,
89 RESOURCE_DATA_LEVEL,
90 &ResourceDataEntry);
91 if (NT_SUCCESS(Status))
92 {
93 /* Access the resource */
94 Status = LdrAccessResource(LdrEntry->DllBase,
95 ResourceDataEntry,
96 &Data,
97 &Size);
98 if (!NT_SUCCESS(Status)) Data = NULL;
99 }
100 }
101
102 /* Return the pointer */
103 return Data;
104 }
105
106 BOOLEAN
107 NTAPI
108 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
109 IN ULONG Count)
110 {
111 PCHAR CommandLine;
112 BOOLEAN CustomLogo = FALSE;
113 ULONG i;
114 extern BOOLEAN ExpInTextModeSetup;
115
116 /* Quit if we're already installed */
117 if (InbvBootDriverInstalled) return TRUE;
118
119 /* Initialize the lock and check the current display state */
120 KeInitializeSpinLock(&BootDriverLock);
121 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
122 {
123 /* Check if we have a custom boot logo */
124 CommandLine = _strupr(LoaderBlock->LoadOptions);
125 CustomLogo = strstr(CommandLine, "BOOTLOGO") ? TRUE: FALSE;
126 }
127
128 /* For SetupLDR, don't reset the BIOS Display -- FIXME! */
129 if (ExpInTextModeSetup) CustomLogo = TRUE;
130
131 /* Initialize the video */
132 InbvBootDriverInstalled = VidInitialize(!CustomLogo);
133 if (InbvBootDriverInstalled)
134 {
135 /* Find bitmap resources in the kernel */
136 ResourceCount = Count;
137 for (i = 0; i < Count; i++)
138 {
139 /* Do the lookup */
140 ResourceList[i] = FindBitmapResource(LoaderBlock, i);
141 }
142
143 /* Set the progress bar ranges */
144 InbvSetProgressBarSubset(0, 100);
145 }
146
147 /* Return install state */
148 return InbvBootDriverInstalled;
149 }
150
151 VOID
152 NTAPI
153 InbvAcquireLock(VOID)
154 {
155 /* Check if we're below dispatch level */
156 InbvOldIrql = KeGetCurrentIrql();
157 if (InbvOldIrql < DISPATCH_LEVEL)
158 {
159 /* Raise IRQL to dispatch level */
160 InbvOldIrql = KfRaiseIrql(DISPATCH_LEVEL);
161 }
162
163 /* Acquire the lock */
164 KiAcquireSpinLock(&BootDriverLock);
165 }
166
167 VOID
168 NTAPI
169 InbvReleaseLock(VOID)
170 {
171 /* Release the driver lock */
172 KiReleaseSpinLock(&BootDriverLock);
173
174 /* If we were below dispatch level, lower IRQL back */
175 if (InbvOldIrql < DISPATCH_LEVEL) KfLowerIrql(InbvOldIrql);
176 }
177
178 VOID
179 NTAPI
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 /* Call Headless (We don't support headless for now)
270 HeadlessDispatch(DISPLAY_STRING); */
271
272 /* Release the lock */
273 InbvReleaseLock();
274
275 /* All done */
276 return TRUE;
277 }
278
279 /* We don't own it, fail */
280 return FALSE;
281 }
282
283 BOOLEAN
284 NTAPI
285 InbvEnableDisplayString(IN BOOLEAN Enable)
286 {
287 BOOLEAN OldSetting;
288
289 /* Get the old setting */
290 OldSetting = InbvDisplayDebugStrings;
291
292 /* Update it */
293 InbvDisplayDebugStrings = Enable;
294
295 /* Return the old setting */
296 return OldSetting;
297 }
298
299 VOID
300 NTAPI
301 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
302 {
303 /* Save the filter */
304 InbvDisplayFilter = Filter;
305 }
306
307 BOOLEAN
308 NTAPI
309 InbvIsBootDriverInstalled(VOID)
310 {
311 /* Return driver state */
312 return InbvBootDriverInstalled;
313 }
314
315 VOID
316 NTAPI
317 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
318 {
319 /* Check if we're installed */
320 if (InbvBootDriverInstalled)
321 {
322 /* Acquire the lock and cleanup if we own the screen */
323 InbvAcquireLock();
324 if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
325
326 /* Set the reset callback and display state */
327 InbvResetDisplayParameters = Callback;
328 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
329
330 /* Release the lock */
331 InbvReleaseLock();
332 }
333 else
334 {
335 /* Set the reset callback and display state */
336 InbvResetDisplayParameters = Callback;
337 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
338 }
339 }
340
341 BOOLEAN
342 NTAPI
343 InbvResetDisplay(VOID)
344 {
345 /* Check if we're installed and we own it */
346 if ((InbvBootDriverInstalled) &&
347 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
348 {
349 /* Do the reset */
350 VidResetDisplay(TRUE);
351 return TRUE;
352 }
353
354 /* Nothing to reset */
355 return FALSE;
356 }
357
358 VOID
359 NTAPI
360 InbvSetScrollRegion(IN ULONG Left,
361 IN ULONG Top,
362 IN ULONG Width,
363 IN ULONG Height)
364 {
365 /* Just call bootvid */
366 VidSetScrollRegion(Left, Top, Width, Height);
367 }
368
369 VOID
370 NTAPI
371 InbvSetTextColor(IN ULONG Color)
372 {
373 /* FIXME: Headless */
374
375 /* Update the text color */
376 VidSetTextColor(Color);
377 }
378
379 VOID
380 NTAPI
381 InbvSolidColorFill(IN ULONG Left,
382 IN ULONG Top,
383 IN ULONG Width,
384 IN ULONG Height,
385 IN ULONG Color)
386 {
387 /* Make sure we own it */
388 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
389 {
390 /* Acquire the lock */
391 InbvAcquireLock();
392
393 /* Check if we're installed */
394 if (InbvBootDriverInstalled)
395 {
396 /* Call bootvid */
397 VidSolidColorFill(Left, Top, Width, Height, (UCHAR)Color);
398 }
399
400 /* FIXME: Headless */
401
402 /* Release the lock */
403 InbvReleaseLock();
404 }
405 }
406
407 VOID
408 NTAPI
409 InbvUpdateProgressBar(IN ULONG Progress)
410 {
411 ULONG FillCount, Left = 0;
412
413 /* Make sure the progress bar is enabled, that we own and are installed */
414 if ((ShowProgressBar) &&
415 (InbvBootDriverInstalled) &&
416 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
417 {
418 /* Calculate the fill count */
419 FillCount = InbvProgressState.Bias * Progress + InbvProgressState.Floor;
420 FillCount *= 18;
421 FillCount /= 10000;
422
423 /* Start fill loop */
424 while (FillCount)
425 {
426 /* Acquire the lock */
427 InbvAcquireLock();
428
429 /* Fill the progress bar */
430 VidSolidColorFill(Left + ProgressBarLeft,
431 ProgressBarTop,
432 Left + ProgressBarLeft + 7,
433 ProgressBarTop + 7,
434 11);
435
436 /* Release the lock */
437 InbvReleaseLock();
438
439 /* Update the X position */
440 Left += 9;
441 FillCount--;
442 }
443 }
444 }
445
446 VOID
447 NTAPI
448 InbvBufferToScreenBlt(IN PUCHAR Buffer,
449 IN ULONG X,
450 IN ULONG Y,
451 IN ULONG Width,
452 IN ULONG Height,
453 IN ULONG Delta)
454 {
455 /* Check if we're installed and we own it */
456 if ((InbvBootDriverInstalled) &&
457 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
458 {
459 /* Do the blit */
460 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
461 }
462 }
463
464 VOID
465 NTAPI
466 InbvBitBlt(IN PUCHAR Buffer,
467 IN ULONG X,
468 IN ULONG Y)
469 {
470 /* Check if we're installed and we own it */
471 if ((InbvBootDriverInstalled) &&
472 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
473 {
474 /* Acquire the lock */
475 InbvAcquireLock();
476
477 /* Do the blit */
478 VidBitBlt(Buffer, X, Y);
479
480 /* Release the lock */
481 InbvReleaseLock();
482 }
483 }
484
485 VOID
486 NTAPI
487 InbvScreenToBufferBlt(IN PUCHAR Buffer,
488 IN ULONG X,
489 IN ULONG Y,
490 IN ULONG Width,
491 IN ULONG Height,
492 IN ULONG Delta)
493 {
494 /* Check if we're installed and we own it */
495 if ((InbvBootDriverInstalled) &&
496 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
497 {
498 /* Do the blit */
499 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
500 }
501 }
502
503 VOID
504 NTAPI
505 InbvSetProgressBarCoordinates(IN ULONG Left,
506 IN ULONG Top)
507 {
508 /* Update the coordinates */
509 ProgressBarLeft = Left;
510 ProgressBarTop = Top;
511
512 /* Enable the progress bar */
513 ShowProgressBar = TRUE;
514 }
515
516 VOID
517 NTAPI
518 InbvSetProgressBarSubset(IN ULONG Floor,
519 IN ULONG Ceiling)
520 {
521 /* Sanity checks */
522 ASSERT(Floor < Ceiling);
523 ASSERT(Ceiling <= 100);
524
525 /* Update the progress bar state */
526 InbvProgressState.Floor = Floor * 100;
527 InbvProgressState.Ceiling = Ceiling * 100;
528 InbvProgressState.Bias = (Ceiling * 100) - Floor;
529 }
530
531 PUCHAR
532 NTAPI
533 InbvGetResourceAddress(IN ULONG ResourceNumber)
534 {
535 /* Validate the resource number */
536 if (ResourceNumber > ResourceCount) return NULL;
537
538 /* Return the address */
539 return ResourceList[ResourceNumber--];
540 }
541
542 NTSTATUS
543 NTAPI
544 NtDisplayString(IN PUNICODE_STRING DisplayString)
545 {
546 OEM_STRING OemString;
547
548 /* Convert the string to OEM and display it */
549 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
550 InbvDisplayString(OemString.Buffer);
551 RtlFreeOemString(&OemString);
552
553 /* Return success */
554 return STATUS_SUCCESS;
555 }
556
557 VOID
558 NTAPI
559 DisplayBootBitmap(IN BOOLEAN SosMode)
560 {
561 PVOID Bitmap, Header;
562 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
563
564 /* Check if the system thread has already been created */
565 if (SysThreadCreated)
566 {
567 /* Reset the progress bar */
568 InbvAcquireLock();
569 RotBarSelection = 0;
570 InbvReleaseLock();
571 }
572
573 /* Check if this is SOS mode */
574 ShowProgressBar = FALSE;
575 if (SosMode)
576 {
577 /* Check if this is a server OS */
578 if (SharedUserData->NtProductType == NtProductWinNt)
579 {
580 /* It's not, set workstation settings */
581 InbvSetTextColor(15);
582 InbvSolidColorFill(0, 0, 639, 479, 7);
583 InbvSolidColorFill(0, 421, 639, 479, 1);
584
585 /* Get resources */
586 Bitmap = InbvGetResourceAddress(6);
587 Header = InbvGetResourceAddress(7);
588 }
589 else
590 {
591 /* Set server settings */
592 InbvSetTextColor(14);
593 InbvSolidColorFill(0, 0, 639, 479, 6);
594 InbvSolidColorFill(0, 421, 639, 479, 1);
595
596 /* Get resources */
597 Bitmap = InbvGetResourceAddress(6);
598 Header = InbvGetResourceAddress(15);
599 }
600
601 /* Set the scrolling region */
602 InbvSetScrollRegion(32, 80, 631, 400);
603
604 /* Make sure we have resources */
605 if ((Bitmap) && (Header))
606 {
607 /* BitBlt them on the screen */
608 InbvBitBlt(Header, 0, 419);
609 InbvBitBlt(Bitmap, 0, 0);
610 }
611 }
612 else
613 {
614 /* Is the boot driver installed? */
615 if (!InbvBootDriverInstalled) return;
616
617 /* FIXME: TODO, display full-screen bitmap */
618 Bitmap = InbvGetResourceAddress(5);
619 if (Bitmap)
620 {
621 PBITMAPINFOHEADER BitmapInfoHeader = (PBITMAPINFOHEADER)Bitmap;
622 ULONG Top, Left;
623
624 Left = (640 - BitmapInfoHeader->biWidth) / 2;
625 if (BitmapInfoHeader->biHeight < 0)
626 Top = (480 + BitmapInfoHeader->biHeight) / 2;
627 else
628 Top = (480 - BitmapInfoHeader->biHeight) / 2;
629 InbvBitBlt(Bitmap, Left, Top);
630 }
631 }
632
633 /* Do we have a system thread? */
634 if (SysThreadCreated)
635 {
636 /* We do, set the progress bar location */
637 InbvAcquireLock();
638 RotBarSelection = TempRotBarSelection;
639 //InbvRotBarInit();
640 InbvReleaseLock();
641 }
642 }
643
644 VOID
645 NTAPI
646 FinalizeBootLogo(VOID)
647 {
648 /* Acquire lock and check the display state */
649 InbvAcquireLock();
650 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
651 {
652 /* Clear the screen */
653 VidSolidColorFill(0, 0, 639, 479, 0);
654 }
655
656 /* Reset progress bar and lock */
657 PltRotBarStatus = 3;
658 InbvReleaseLock();
659 }