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