]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
Add BootlogoOnly feature in BDS for BGRT
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsConsole.c
1 /** @file
2 BDS Lib functions which contain all the code to connect console device
3
4 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "InternalBdsLib.h"
16 #include <IndustryStandard/Bmp.h>
17
18
19 /**
20 Check if we need to save the EFI variable with "ConVarName" as name
21 as NV type
22 If ConVarName is NULL, then ASSERT().
23
24 @param ConVarName The name of the EFI variable.
25
26 @retval TRUE Set the EFI variable as NV type.
27 @retval FALSE EFI variable as NV type can be set NonNV.
28 **/
29 BOOLEAN
30 IsNvNeed (
31 IN CHAR16 *ConVarName
32 )
33 {
34 CHAR16 *Ptr;
35
36 ASSERT (ConVarName != NULL);
37
38 Ptr = ConVarName;
39
40 //
41 // If the variable includes "Dev" at last, we consider
42 // it does not support NV attribute.
43 //
44 while (*Ptr != L'\0') {
45 Ptr++;
46 }
47
48 if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
49 return TRUE;
50 }
51
52 if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
53 return FALSE;
54 } else {
55 return TRUE;
56 }
57 }
58
59 /**
60 Fill console handle in System Table if there are no valid console handle in.
61
62 Firstly, check the validation of console handle in System Table. If it is invalid,
63 update it by the first console device handle from EFI console variable.
64
65 @param VarName The name of the EFI console variable.
66 @param ConsoleGuid Specified Console protocol GUID.
67 @param ConsoleHandle On IN, console handle in System Table to be checked.
68 On OUT, new console hanlde in system table.
69 @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
70 On OUT, new console protocol on new console hanlde in system table.
71
72 @retval TRUE System Table has been updated.
73 @retval FALSE System Table hasn't been updated.
74
75 **/
76 BOOLEAN
77 UpdateSystemTableConsole (
78 IN CHAR16 *VarName,
79 IN EFI_GUID *ConsoleGuid,
80 IN OUT EFI_HANDLE *ConsoleHandle,
81 IN OUT VOID **ProtocolInterface
82 )
83 {
84 EFI_STATUS Status;
85 UINTN DevicePathSize;
86 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
87 EFI_DEVICE_PATH_PROTOCOL *VarConsole;
88 EFI_DEVICE_PATH_PROTOCOL *Instance;
89 VOID *Interface;
90 EFI_HANDLE NewHandle;
91
92 ASSERT (VarName != NULL);
93 ASSERT (ConsoleHandle != NULL);
94 ASSERT (ConsoleGuid != NULL);
95 ASSERT (ProtocolInterface != NULL);
96
97 if (*ConsoleHandle != NULL) {
98 Status = gBS->HandleProtocol (
99 *ConsoleHandle,
100 ConsoleGuid,
101 &Interface
102 );
103 if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
104 //
105 // If ConsoleHandle is valid and console protocol on this handle also
106 // also matched, just return.
107 //
108 return FALSE;
109 }
110 }
111
112 //
113 // Get all possible consoles device path from EFI variable
114 //
115 VarConsole = BdsLibGetVariableAndSize (
116 VarName,
117 &gEfiGlobalVariableGuid,
118 &DevicePathSize
119 );
120 if (VarConsole == NULL) {
121 //
122 // If there is no any console device, just return.
123 //
124 return FALSE;
125 }
126
127 FullDevicePath = VarConsole;
128
129 do {
130 //
131 // Check every instance of the console variable
132 //
133 Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
134 if (Instance == NULL) {
135 FreePool (FullDevicePath);
136 ASSERT (FALSE);
137 }
138
139 //
140 // Find console device handle by device path instance
141 //
142 Status = gBS->LocateDevicePath (
143 ConsoleGuid,
144 &Instance,
145 &NewHandle
146 );
147 if (!EFI_ERROR (Status)) {
148 //
149 // Get the console protocol on this console device handle
150 //
151 Status = gBS->HandleProtocol (
152 NewHandle,
153 ConsoleGuid,
154 &Interface
155 );
156 if (!EFI_ERROR (Status)) {
157 //
158 // Update new console handle in System Table.
159 //
160 *ConsoleHandle = NewHandle;
161 *ProtocolInterface = Interface;
162 return TRUE;
163 }
164 }
165
166 } while (Instance != NULL);
167
168 //
169 // No any available console devcie found.
170 //
171 return FALSE;
172 }
173
174 /**
175 This function update console variable based on ConVarName, it can
176 add or remove one specific console device path from the variable
177
178 @param ConVarName Console related variable name, ConIn, ConOut,
179 ErrOut.
180 @param CustomizedConDevicePath The console device path which will be added to
181 the console variable ConVarName, this parameter
182 can not be multi-instance.
183 @param ExclusiveDevicePath The console device path which will be removed
184 from the console variable ConVarName, this
185 parameter can not be multi-instance.
186
187 @retval EFI_UNSUPPORTED The added device path is same to the removed one.
188 @retval EFI_SUCCESS Success add or remove the device path from the
189 console variable.
190
191 **/
192 EFI_STATUS
193 EFIAPI
194 BdsLibUpdateConsoleVariable (
195 IN CHAR16 *ConVarName,
196 IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
197 IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
198 )
199 {
200 EFI_STATUS Status;
201 EFI_DEVICE_PATH_PROTOCOL *VarConsole;
202 UINTN DevicePathSize;
203 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
204 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
205 UINT32 Attributes;
206
207 VarConsole = NULL;
208 DevicePathSize = 0;
209
210 //
211 // Notes: check the device path point, here should check
212 // with compare memory
213 //
214 if (CustomizedConDevicePath == ExclusiveDevicePath) {
215 return EFI_UNSUPPORTED;
216 }
217 //
218 // Delete the ExclusiveDevicePath from current default console
219 //
220 VarConsole = BdsLibGetVariableAndSize (
221 ConVarName,
222 &gEfiGlobalVariableGuid,
223 &DevicePathSize
224 );
225
226 //
227 // Initialize NewDevicePath
228 //
229 NewDevicePath = VarConsole;
230
231 //
232 // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
233 // In the end, NewDevicePath is the final device path.
234 //
235 if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
236 NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
237 }
238 //
239 // Try to append customized device path to NewDevicePath.
240 //
241 if (CustomizedConDevicePath != NULL) {
242 if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
243 //
244 // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
245 //
246 NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
247 //
248 // In the first check, the default console variable will be _ModuleEntryPoint,
249 // just append current customized device path
250 //
251 TempNewDevicePath = NewDevicePath;
252 NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
253 if (TempNewDevicePath != NULL) {
254 FreePool(TempNewDevicePath);
255 }
256 }
257 }
258
259 //
260 // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
261 //
262 if (IsNvNeed(ConVarName)) {
263 //
264 // ConVarName has NV attribute.
265 //
266 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
267 } else {
268 //
269 // ConVarName does not have NV attribute.
270 //
271 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
272 }
273
274 //
275 // Finally, Update the variable of the default console by NewDevicePath
276 //
277 DevicePathSize = GetDevicePathSize (NewDevicePath);
278 Status = gRT->SetVariable (
279 ConVarName,
280 &gEfiGlobalVariableGuid,
281 Attributes,
282 DevicePathSize,
283 NewDevicePath
284 );
285 if ((DevicePathSize == 0) && (Status == EFI_NOT_FOUND)) {
286 Status = EFI_SUCCESS;
287 }
288 ASSERT_EFI_ERROR (Status);
289
290 if (VarConsole == NewDevicePath) {
291 if (VarConsole != NULL) {
292 FreePool(VarConsole);
293 }
294 } else {
295 if (VarConsole != NULL) {
296 FreePool(VarConsole);
297 }
298 if (NewDevicePath != NULL) {
299 FreePool(NewDevicePath);
300 }
301 }
302
303 return Status;
304
305 }
306
307
308 /**
309 Connect the console device base on the variable ConVarName, if
310 device path of the ConVarName is multi-instance device path, if
311 anyone of the instances is connected success, then this function
312 will return success.
313
314 @param ConVarName Console related variable name, ConIn, ConOut,
315 ErrOut.
316
317 @retval EFI_NOT_FOUND There is not any console devices connected
318 success
319 @retval EFI_SUCCESS Success connect any one instance of the console
320 device path base on the variable ConVarName.
321
322 **/
323 EFI_STATUS
324 EFIAPI
325 BdsLibConnectConsoleVariable (
326 IN CHAR16 *ConVarName
327 )
328 {
329 EFI_STATUS Status;
330 EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
331 UINTN VariableSize;
332 EFI_DEVICE_PATH_PROTOCOL *Instance;
333 EFI_DEVICE_PATH_PROTOCOL *Next;
334 EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
335 UINTN Size;
336 BOOLEAN DeviceExist;
337
338 Status = EFI_SUCCESS;
339 DeviceExist = FALSE;
340
341 //
342 // Check if the console variable exist
343 //
344 StartDevicePath = BdsLibGetVariableAndSize (
345 ConVarName,
346 &gEfiGlobalVariableGuid,
347 &VariableSize
348 );
349 if (StartDevicePath == NULL) {
350 return EFI_UNSUPPORTED;
351 }
352
353 CopyOfDevicePath = StartDevicePath;
354 do {
355 //
356 // Check every instance of the console variable
357 //
358 Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
359 if (Instance == NULL) {
360 FreePool (StartDevicePath);
361 return EFI_UNSUPPORTED;
362 }
363
364 Next = Instance;
365 while (!IsDevicePathEndType (Next)) {
366 Next = NextDevicePathNode (Next);
367 }
368
369 SetDevicePathEndNode (Next);
370 //
371 // Connect the USB console
372 // USB console device path is a short-form device path that
373 // starts with the first element being a USB WWID
374 // or a USB Class device path
375 //
376 if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
377 ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
378 || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
379 )) {
380 Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance);
381 if (!EFI_ERROR (Status)) {
382 DeviceExist = TRUE;
383 }
384 } else {
385 //
386 // Connect the instance device path
387 //
388 Status = BdsLibConnectDevicePath (Instance);
389 if (EFI_ERROR (Status)) {
390 //
391 // Delete the instance from the console varialbe
392 //
393 BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
394 } else {
395 DeviceExist = TRUE;
396 }
397 }
398 FreePool(Instance);
399 } while (CopyOfDevicePath != NULL);
400
401 FreePool (StartDevicePath);
402
403 if (!DeviceExist) {
404 return EFI_NOT_FOUND;
405 }
406
407 return EFI_SUCCESS;
408 }
409
410
411 /**
412 This function will search every simpletext device in current system,
413 and make every simpletext device as pertantial console device.
414
415 **/
416 VOID
417 EFIAPI
418 BdsLibConnectAllConsoles (
419 VOID
420 )
421 {
422 UINTN Index;
423 EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
424 UINTN HandleCount;
425 EFI_HANDLE *HandleBuffer;
426
427 Index = 0;
428 HandleCount = 0;
429 HandleBuffer = NULL;
430 ConDevicePath = NULL;
431
432 //
433 // Update all the console variables
434 //
435 gBS->LocateHandleBuffer (
436 ByProtocol,
437 &gEfiSimpleTextInProtocolGuid,
438 NULL,
439 &HandleCount,
440 &HandleBuffer
441 );
442
443 for (Index = 0; Index < HandleCount; Index++) {
444 gBS->HandleProtocol (
445 HandleBuffer[Index],
446 &gEfiDevicePathProtocolGuid,
447 (VOID **) &ConDevicePath
448 );
449 BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
450 }
451
452 if (HandleBuffer != NULL) {
453 FreePool(HandleBuffer);
454 HandleBuffer = NULL;
455 }
456
457 gBS->LocateHandleBuffer (
458 ByProtocol,
459 &gEfiSimpleTextOutProtocolGuid,
460 NULL,
461 &HandleCount,
462 &HandleBuffer
463 );
464 for (Index = 0; Index < HandleCount; Index++) {
465 gBS->HandleProtocol (
466 HandleBuffer[Index],
467 &gEfiDevicePathProtocolGuid,
468 (VOID **) &ConDevicePath
469 );
470 BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
471 BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
472 }
473
474 if (HandleBuffer != NULL) {
475 FreePool(HandleBuffer);
476 }
477
478 //
479 // Connect all console variables
480 //
481 BdsLibConnectAllDefaultConsoles ();
482
483 }
484
485 /**
486 This function will connect console device base on the console
487 device variable ConIn, ConOut and ErrOut.
488
489 @retval EFI_SUCCESS At least one of the ConIn and ConOut device have
490 been connected success.
491 @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
492
493 **/
494 EFI_STATUS
495 EFIAPI
496 BdsLibConnectAllDefaultConsoles (
497 VOID
498 )
499 {
500 EFI_STATUS Status;
501 BOOLEAN SystemTableUpdated;
502
503 //
504 // Connect all default console variables
505 //
506
507 //
508 // It seems impossible not to have any ConOut device on platform,
509 // so we check the status here.
510 //
511 Status = BdsLibConnectConsoleVariable (L"ConOut");
512 if (EFI_ERROR (Status)) {
513 return Status;
514 }
515
516 //
517 // Insert the performance probe for Console Out
518 //
519 PERF_START (NULL, "ConOut", "BDS", 1);
520 PERF_END (NULL, "ConOut", "BDS", 0);
521
522 //
523 // Because possibly the platform is legacy free, in such case,
524 // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
525 // so we need not check the status.
526 //
527 BdsLibConnectConsoleVariable (L"ConIn");
528
529 //
530 // The _ModuleEntryPoint err out var is legal.
531 //
532 BdsLibConnectConsoleVariable (L"ErrOut");
533
534 SystemTableUpdated = FALSE;
535 //
536 // Fill console handles in System Table if no console device assignd.
537 //
538 if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
539 SystemTableUpdated = TRUE;
540 }
541 if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
542 SystemTableUpdated = TRUE;
543 }
544 if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
545 SystemTableUpdated = TRUE;
546 }
547
548 if (SystemTableUpdated) {
549 //
550 // Update the CRC32 in the EFI System Table header
551 //
552 gST->Hdr.CRC32 = 0;
553 gBS->CalculateCrc32 (
554 (UINT8 *) &gST->Hdr,
555 gST->Hdr.HeaderSize,
556 &gST->Hdr.CRC32
557 );
558 }
559
560 return EFI_SUCCESS;
561
562 }
563
564 /**
565 Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
566 is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
567 buffer is passed in it will be used if it is big enough.
568
569 @param BmpImage Pointer to BMP file
570 @param BmpImageSize Number of bytes in BmpImage
571 @param GopBlt Buffer containing GOP version of BmpImage.
572 @param GopBltSize Size of GopBlt in bytes.
573 @param PixelHeight Height of GopBlt/BmpImage in pixels
574 @param PixelWidth Width of GopBlt/BmpImage in pixels
575
576 @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
577 @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
578 @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
579 GopBltSize will contain the required size.
580 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
581
582 **/
583 EFI_STATUS
584 ConvertBmpToGopBlt (
585 IN VOID *BmpImage,
586 IN UINTN BmpImageSize,
587 IN OUT VOID **GopBlt,
588 IN OUT UINTN *GopBltSize,
589 OUT UINTN *PixelHeight,
590 OUT UINTN *PixelWidth
591 )
592 {
593 UINT8 *Image;
594 UINT8 *ImageHeader;
595 BMP_IMAGE_HEADER *BmpHeader;
596 BMP_COLOR_MAP *BmpColorMap;
597 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
598 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
599 UINT64 BltBufferSize;
600 UINTN Index;
601 UINTN Height;
602 UINTN Width;
603 UINTN ImageIndex;
604 BOOLEAN IsAllocated;
605
606 BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
607
608 if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
609 return EFI_UNSUPPORTED;
610 }
611
612 //
613 // Doesn't support compress.
614 //
615 if (BmpHeader->CompressionType != 0) {
616 return EFI_UNSUPPORTED;
617 }
618
619 //
620 // Calculate Color Map offset in the image.
621 //
622 Image = BmpImage;
623 BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
624
625 //
626 // Calculate graphics image data address in the image
627 //
628 Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
629 ImageHeader = Image;
630
631 //
632 // Calculate the BltBuffer needed size.
633 //
634 BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
635 //
636 // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
637 //
638 if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
639 return EFI_UNSUPPORTED;
640 }
641 BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
642
643 IsAllocated = FALSE;
644 if (*GopBlt == NULL) {
645 //
646 // GopBlt is not allocated by caller.
647 //
648 *GopBltSize = (UINTN) BltBufferSize;
649 *GopBlt = AllocatePool (*GopBltSize);
650 IsAllocated = TRUE;
651 if (*GopBlt == NULL) {
652 return EFI_OUT_OF_RESOURCES;
653 }
654 } else {
655 //
656 // GopBlt has been allocated by caller.
657 //
658 if (*GopBltSize < (UINTN) BltBufferSize) {
659 *GopBltSize = (UINTN) BltBufferSize;
660 return EFI_BUFFER_TOO_SMALL;
661 }
662 }
663
664 *PixelWidth = BmpHeader->PixelWidth;
665 *PixelHeight = BmpHeader->PixelHeight;
666
667 //
668 // Convert image from BMP to Blt buffer format
669 //
670 BltBuffer = *GopBlt;
671 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
672 Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
673 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
674 switch (BmpHeader->BitPerPixel) {
675 case 1:
676 //
677 // Convert 1-bit (2 colors) BMP to 24-bit color
678 //
679 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
680 Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
681 Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
682 Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
683 Blt++;
684 Width++;
685 }
686
687 Blt--;
688 Width--;
689 break;
690
691 case 4:
692 //
693 // Convert 4-bit (16 colors) BMP Palette to 24-bit color
694 //
695 Index = (*Image) >> 4;
696 Blt->Red = BmpColorMap[Index].Red;
697 Blt->Green = BmpColorMap[Index].Green;
698 Blt->Blue = BmpColorMap[Index].Blue;
699 if (Width < (BmpHeader->PixelWidth - 1)) {
700 Blt++;
701 Width++;
702 Index = (*Image) & 0x0f;
703 Blt->Red = BmpColorMap[Index].Red;
704 Blt->Green = BmpColorMap[Index].Green;
705 Blt->Blue = BmpColorMap[Index].Blue;
706 }
707 break;
708
709 case 8:
710 //
711 // Convert 8-bit (256 colors) BMP Palette to 24-bit color
712 //
713 Blt->Red = BmpColorMap[*Image].Red;
714 Blt->Green = BmpColorMap[*Image].Green;
715 Blt->Blue = BmpColorMap[*Image].Blue;
716 break;
717
718 case 24:
719 //
720 // It is 24-bit BMP.
721 //
722 Blt->Blue = *Image++;
723 Blt->Green = *Image++;
724 Blt->Red = *Image;
725 break;
726
727 default:
728 //
729 // Other bit format BMP is not supported.
730 //
731 if (IsAllocated) {
732 FreePool (*GopBlt);
733 *GopBlt = NULL;
734 }
735 return EFI_UNSUPPORTED;
736 break;
737 };
738
739 }
740
741 ImageIndex = (UINTN) (Image - ImageHeader);
742 if ((ImageIndex % 4) != 0) {
743 //
744 // Bmp Image starts each row on a 32-bit boundary!
745 //
746 Image = Image + (4 - (ImageIndex % 4));
747 }
748 }
749
750 return EFI_SUCCESS;
751 }
752
753 /**
754 Use SystemTable Conout to stop video based Simple Text Out consoles from going
755 to the video device. Put up LogoFile on every video device that is a console.
756
757 @param[in] LogoFile File name of logo to display on the center of the screen.
758
759 @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
760 @retval EFI_UNSUPPORTED Logo not found
761
762 **/
763 EFI_STATUS
764 EFIAPI
765 EnableQuietBoot (
766 IN EFI_GUID *LogoFile
767 )
768 {
769 EFI_STATUS Status;
770 EFI_OEM_BADGING_PROTOCOL *Badging;
771 UINT32 SizeOfX;
772 UINT32 SizeOfY;
773 INTN DestX;
774 INTN DestY;
775 UINT8 *ImageData;
776 UINTN ImageSize;
777 UINTN BltSize;
778 UINT32 Instance;
779 EFI_BADGING_FORMAT Format;
780 EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
781 UINTN CoordinateX;
782 UINTN CoordinateY;
783 UINTN Height;
784 UINTN Width;
785 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
786 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
787 UINT32 ColorDepth;
788 UINT32 RefreshRate;
789 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
790 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
791 UINTN NumberOfLogos;
792 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
793 UINTN LogoDestX;
794 UINTN LogoDestY;
795 UINTN LogoHeight;
796 UINTN LogoWidth;
797 UINTN NewDestX;
798 UINTN NewDestY;
799 UINTN NewHeight;
800 UINTN NewWidth;
801
802 UgaDraw = NULL;
803 //
804 // Try to open GOP first
805 //
806 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
807 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
808 GraphicsOutput = NULL;
809 //
810 // Open GOP failed, try to open UGA
811 //
812 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
813 }
814 if (EFI_ERROR (Status)) {
815 return EFI_UNSUPPORTED;
816 }
817
818 //
819 // Try to open Boot Logo Protocol.
820 //
821 BootLogo = NULL;
822 gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
823
824 //
825 // Erase Cursor from screen
826 //
827 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
828
829 Badging = NULL;
830 Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
831
832 if (GraphicsOutput != NULL) {
833 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
834 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
835
836 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
837 Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
838 if (EFI_ERROR (Status)) {
839 return EFI_UNSUPPORTED;
840 }
841 } else {
842 return EFI_UNSUPPORTED;
843 }
844
845 Blt = NULL;
846 NumberOfLogos = 0;
847 LogoDestX = 0;
848 LogoDestY = 0;
849 LogoHeight = 0;
850 LogoWidth = 0;
851 NewDestX = 0;
852 NewDestY = 0;
853 NewHeight = 0;
854 NewWidth = 0;
855 Instance = 0;
856 while (1) {
857 ImageData = NULL;
858 ImageSize = 0;
859
860 if (Badging != NULL) {
861 //
862 // Get image from OEMBadging protocol.
863 //
864 Status = Badging->GetImage (
865 Badging,
866 &Instance,
867 &Format,
868 &ImageData,
869 &ImageSize,
870 &Attribute,
871 &CoordinateX,
872 &CoordinateY
873 );
874 if (EFI_ERROR (Status)) {
875 goto Done;
876 }
877
878 //
879 // Currently only support BMP format.
880 //
881 if (Format != EfiBadgingFormatBMP) {
882 if (ImageData != NULL) {
883 FreePool (ImageData);
884 }
885 continue;
886 }
887 } else {
888 //
889 // Get the specified image from FV.
890 //
891 Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
892 if (EFI_ERROR (Status)) {
893 return EFI_UNSUPPORTED;
894 }
895
896 CoordinateX = 0;
897 CoordinateY = 0;
898 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
899 Attribute = EfiBadgingDisplayAttributeCenter;
900 } else {
901 Attribute = EfiBadgingDisplayAttributeCustomized;
902 }
903 }
904
905 if (Blt != NULL) {
906 FreePool (Blt);
907 }
908 Blt = NULL;
909 Status = ConvertBmpToGopBlt (
910 ImageData,
911 ImageSize,
912 (VOID **) &Blt,
913 &BltSize,
914 &Height,
915 &Width
916 );
917 if (EFI_ERROR (Status)) {
918 FreePool (ImageData);
919
920 if (Badging == NULL) {
921 return Status;
922 } else {
923 continue;
924 }
925 }
926
927 //
928 // Calculate the display position according to Attribute.
929 //
930 switch (Attribute) {
931 case EfiBadgingDisplayAttributeLeftTop:
932 DestX = CoordinateX;
933 DestY = CoordinateY;
934 break;
935
936 case EfiBadgingDisplayAttributeCenterTop:
937 DestX = (SizeOfX - Width) / 2;
938 DestY = CoordinateY;
939 break;
940
941 case EfiBadgingDisplayAttributeRightTop:
942 DestX = (SizeOfX - Width - CoordinateX);
943 DestY = CoordinateY;;
944 break;
945
946 case EfiBadgingDisplayAttributeCenterRight:
947 DestX = (SizeOfX - Width - CoordinateX);
948 DestY = (SizeOfY - Height) / 2;
949 break;
950
951 case EfiBadgingDisplayAttributeRightBottom:
952 DestX = (SizeOfX - Width - CoordinateX);
953 DestY = (SizeOfY - Height - CoordinateY);
954 break;
955
956 case EfiBadgingDisplayAttributeCenterBottom:
957 DestX = (SizeOfX - Width) / 2;
958 DestY = (SizeOfY - Height - CoordinateY);
959 break;
960
961 case EfiBadgingDisplayAttributeLeftBottom:
962 DestX = CoordinateX;
963 DestY = (SizeOfY - Height - CoordinateY);
964 break;
965
966 case EfiBadgingDisplayAttributeCenterLeft:
967 DestX = CoordinateX;
968 DestY = (SizeOfY - Height) / 2;
969 break;
970
971 case EfiBadgingDisplayAttributeCenter:
972 DestX = (SizeOfX - Width) / 2;
973 DestY = (SizeOfY - Height) / 2;
974 break;
975
976 case EfiBadgingDisplayAttributeCustomized:
977 DestX = (SizeOfX - Width) / 2;
978 DestY = ((SizeOfY * 382) / 1000) - Height / 2;
979 break;
980
981 default:
982 DestX = CoordinateX;
983 DestY = CoordinateY;
984 break;
985 }
986
987 if ((DestX >= 0) && (DestY >= 0)) {
988 if (GraphicsOutput != NULL) {
989 Status = GraphicsOutput->Blt (
990 GraphicsOutput,
991 Blt,
992 EfiBltBufferToVideo,
993 0,
994 0,
995 (UINTN) DestX,
996 (UINTN) DestY,
997 Width,
998 Height,
999 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1000 );
1001 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1002 Status = UgaDraw->Blt (
1003 UgaDraw,
1004 (EFI_UGA_PIXEL *) Blt,
1005 EfiUgaBltBufferToVideo,
1006 0,
1007 0,
1008 (UINTN) DestX,
1009 (UINTN) DestY,
1010 Width,
1011 Height,
1012 Width * sizeof (EFI_UGA_PIXEL)
1013 );
1014 } else {
1015 Status = EFI_UNSUPPORTED;
1016 }
1017
1018 //
1019 // Report displayed Logo information.
1020 //
1021 if (!EFI_ERROR (Status)) {
1022 NumberOfLogos++;
1023
1024 if (LogoWidth == 0) {
1025 //
1026 // The first Logo.
1027 //
1028 LogoDestX = (UINTN) DestX;
1029 LogoDestY = (UINTN) DestY;
1030 LogoWidth = Width;
1031 LogoHeight = Height;
1032 } else {
1033 //
1034 // Merge new logo with old one.
1035 //
1036 NewDestX = MIN ((UINTN) DestX, LogoDestX);
1037 NewDestY = MIN ((UINTN) DestY, LogoDestY);
1038 NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
1039 NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
1040
1041 LogoDestX = NewDestX;
1042 LogoDestY = NewDestY;
1043 LogoWidth = NewWidth;
1044 LogoHeight = NewHeight;
1045 }
1046 }
1047 }
1048
1049 FreePool (ImageData);
1050
1051 if (Badging == NULL) {
1052 break;
1053 }
1054 }
1055
1056 Done:
1057 if (BootLogo == NULL || NumberOfLogos == 0) {
1058 //
1059 // No logo displayed.
1060 //
1061 if (Blt != NULL) {
1062 FreePool (Blt);
1063 }
1064
1065 return Status;
1066 }
1067
1068 //
1069 // Advertise displayed Logo information.
1070 //
1071 if (NumberOfLogos == 1) {
1072 //
1073 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
1074 //
1075 LogoBlt = Blt;
1076 Status = EFI_SUCCESS;
1077 } else {
1078 //
1079 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
1080 //
1081 if (Blt != NULL) {
1082 FreePool (Blt);
1083 }
1084
1085 LogoBlt = AllocateZeroPool (LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1086 if (LogoBlt == NULL) {
1087 return EFI_OUT_OF_RESOURCES;
1088 }
1089
1090 if (GraphicsOutput != NULL) {
1091 Status = GraphicsOutput->Blt (
1092 GraphicsOutput,
1093 LogoBlt,
1094 EfiBltVideoToBltBuffer,
1095 LogoDestX,
1096 LogoDestY,
1097 0,
1098 0,
1099 LogoWidth,
1100 LogoHeight,
1101 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
1102 );
1103 } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
1104 Status = UgaDraw->Blt (
1105 UgaDraw,
1106 (EFI_UGA_PIXEL *) LogoBlt,
1107 EfiUgaVideoToBltBuffer,
1108 LogoDestX,
1109 LogoDestY,
1110 0,
1111 0,
1112 LogoWidth,
1113 LogoHeight,
1114 LogoWidth * sizeof (EFI_UGA_PIXEL)
1115 );
1116 } else {
1117 Status = EFI_UNSUPPORTED;
1118 }
1119 }
1120
1121 if (!EFI_ERROR (Status)) {
1122 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
1123 }
1124 FreePool (LogoBlt);
1125
1126 return Status;
1127 }
1128
1129 /**
1130 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
1131 Simple Text Out screens will now be synced up with all non video output devices
1132
1133 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
1134
1135 **/
1136 EFI_STATUS
1137 EFIAPI
1138 DisableQuietBoot (
1139 VOID
1140 )
1141 {
1142
1143 //
1144 // Enable Cursor on Screen
1145 //
1146 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1147 return EFI_SUCCESS;
1148 }
1149