2 Platform BDS function for quiet boot support.
4 Copyright (C) 2016, Red Hat, Inc.
5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <IndustryStandard/Bmp.h>
17 #include <Library/DxeServicesLib.h>
18 #include <Protocol/BootLogo.h>
19 #include <Protocol/OEMBadging.h>
20 #include <Protocol/UgaDraw.h>
22 #include "PlatformBm.h"
25 Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
26 is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
27 buffer is passed in it will be used if it is big enough.
29 @param BmpImage Pointer to BMP file
30 @param BmpImageSize Number of bytes in BmpImage
31 @param GopBlt Buffer containing GOP version of BmpImage.
32 @param GopBltSize Size of GopBlt in bytes.
33 @param PixelHeight Height of GopBlt/BmpImage in pixels
34 @param PixelWidth Width of GopBlt/BmpImage in pixels
36 @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
37 @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
38 @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
39 GopBltSize will contain the required size.
40 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
47 IN UINTN BmpImageSize
,
49 IN OUT UINTN
*GopBltSize
,
50 OUT UINTN
*PixelHeight
,
56 BMP_IMAGE_HEADER
*BmpHeader
;
57 BMP_COLOR_MAP
*BmpColorMap
;
58 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
;
59 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
65 UINT32 DataSizePerLine
;
69 if (sizeof (BMP_IMAGE_HEADER
) > BmpImageSize
) {
70 return EFI_INVALID_PARAMETER
;
73 BmpHeader
= (BMP_IMAGE_HEADER
*) BmpImage
;
75 if (BmpHeader
->CharB
!= 'B' || BmpHeader
->CharM
!= 'M') {
76 return EFI_UNSUPPORTED
;
80 // Doesn't support compress.
82 if (BmpHeader
->CompressionType
!= 0) {
83 return EFI_UNSUPPORTED
;
87 // Only support BITMAPINFOHEADER format.
88 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
90 if (BmpHeader
->HeaderSize
!= sizeof (BMP_IMAGE_HEADER
) - OFFSET_OF(BMP_IMAGE_HEADER
, HeaderSize
)) {
91 return EFI_UNSUPPORTED
;
95 // The data size in each line must be 4 byte alignment.
97 DataSizePerLine
= ((BmpHeader
->PixelWidth
* BmpHeader
->BitPerPixel
+ 31) >> 3) & (~0x3);
98 BltBufferSize
= MultU64x32 (DataSizePerLine
, BmpHeader
->PixelHeight
);
99 if (BltBufferSize
> (UINT32
) ~0) {
100 return EFI_INVALID_PARAMETER
;
103 if ((BmpHeader
->Size
!= BmpImageSize
) ||
104 (BmpHeader
->Size
< BmpHeader
->ImageOffset
) ||
105 (BmpHeader
->Size
- BmpHeader
->ImageOffset
!= BmpHeader
->PixelHeight
* DataSizePerLine
)) {
106 return EFI_INVALID_PARAMETER
;
110 // Calculate Color Map offset in the image.
113 BmpColorMap
= (BMP_COLOR_MAP
*) (Image
+ sizeof (BMP_IMAGE_HEADER
));
114 if (BmpHeader
->ImageOffset
< sizeof (BMP_IMAGE_HEADER
)) {
115 return EFI_INVALID_PARAMETER
;
118 if (BmpHeader
->ImageOffset
> sizeof (BMP_IMAGE_HEADER
)) {
119 switch (BmpHeader
->BitPerPixel
) {
134 // BMP file may has padding data between the bmp header section and the bmp data section.
136 if (BmpHeader
->ImageOffset
- sizeof (BMP_IMAGE_HEADER
) < sizeof (BMP_COLOR_MAP
) * ColorMapNum
) {
137 return EFI_INVALID_PARAMETER
;
142 // Calculate graphics image data address in the image
144 Image
= ((UINT8
*) BmpImage
) + BmpHeader
->ImageOffset
;
148 // Calculate the BltBuffer needed size.
150 BltBufferSize
= MultU64x32 ((UINT64
) BmpHeader
->PixelWidth
, BmpHeader
->PixelHeight
);
152 // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
154 if (BltBufferSize
> DivU64x32 ((UINTN
) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
))) {
155 return EFI_UNSUPPORTED
;
157 BltBufferSize
= MultU64x32 (BltBufferSize
, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
160 if (*GopBlt
== NULL
) {
162 // GopBlt is not allocated by caller.
164 *GopBltSize
= (UINTN
) BltBufferSize
;
165 *GopBlt
= AllocatePool (*GopBltSize
);
167 if (*GopBlt
== NULL
) {
168 return EFI_OUT_OF_RESOURCES
;
172 // GopBlt has been allocated by caller.
174 if (*GopBltSize
< (UINTN
) BltBufferSize
) {
175 *GopBltSize
= (UINTN
) BltBufferSize
;
176 return EFI_BUFFER_TOO_SMALL
;
180 *PixelWidth
= BmpHeader
->PixelWidth
;
181 *PixelHeight
= BmpHeader
->PixelHeight
;
184 // Convert image from BMP to Blt buffer format
187 for (Height
= 0; Height
< BmpHeader
->PixelHeight
; Height
++) {
188 Blt
= &BltBuffer
[(BmpHeader
->PixelHeight
- Height
- 1) * BmpHeader
->PixelWidth
];
189 for (Width
= 0; Width
< BmpHeader
->PixelWidth
; Width
++, Image
++, Blt
++) {
190 switch (BmpHeader
->BitPerPixel
) {
193 // Convert 1-bit (2 colors) BMP to 24-bit color
195 for (Index
= 0; Index
< 8 && Width
< BmpHeader
->PixelWidth
; Index
++) {
196 Blt
->Red
= BmpColorMap
[((*Image
) >> (7 - Index
)) & 0x1].Red
;
197 Blt
->Green
= BmpColorMap
[((*Image
) >> (7 - Index
)) & 0x1].Green
;
198 Blt
->Blue
= BmpColorMap
[((*Image
) >> (7 - Index
)) & 0x1].Blue
;
209 // Convert 4-bit (16 colors) BMP Palette to 24-bit color
211 Index
= (*Image
) >> 4;
212 Blt
->Red
= BmpColorMap
[Index
].Red
;
213 Blt
->Green
= BmpColorMap
[Index
].Green
;
214 Blt
->Blue
= BmpColorMap
[Index
].Blue
;
215 if (Width
< (BmpHeader
->PixelWidth
- 1)) {
218 Index
= (*Image
) & 0x0f;
219 Blt
->Red
= BmpColorMap
[Index
].Red
;
220 Blt
->Green
= BmpColorMap
[Index
].Green
;
221 Blt
->Blue
= BmpColorMap
[Index
].Blue
;
227 // Convert 8-bit (256 colors) BMP Palette to 24-bit color
229 Blt
->Red
= BmpColorMap
[*Image
].Red
;
230 Blt
->Green
= BmpColorMap
[*Image
].Green
;
231 Blt
->Blue
= BmpColorMap
[*Image
].Blue
;
238 Blt
->Blue
= *Image
++;
239 Blt
->Green
= *Image
++;
245 // Other bit format BMP is not supported.
251 return EFI_UNSUPPORTED
;
256 ImageIndex
= (UINTN
) (Image
- ImageHeader
);
257 if ((ImageIndex
% 4) != 0) {
259 // Bmp Image starts each row on a 32-bit boundary!
261 Image
= Image
+ (4 - (ImageIndex
% 4));
269 Use SystemTable Conout to stop video based Simple Text Out consoles from going
270 to the video device. Put up LogoFile on every video device that is a console.
272 @param[in] LogoFile File name of logo to display on the center of the screen.
274 @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
275 @retval EFI_UNSUPPORTED Logo not found
280 IN EFI_GUID
*LogoFile
284 EFI_OEM_BADGING_PROTOCOL
*Badging
;
293 EFI_BADGING_FORMAT Format
;
294 EFI_BADGING_DISPLAY_ATTRIBUTE Attribute
;
299 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
300 EFI_UGA_DRAW_PROTOCOL
*UgaDraw
;
303 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
304 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
306 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*LogoBlt
;
319 // Try to open GOP first
321 Status
= gBS
->HandleProtocol (gST
->ConsoleOutHandle
, &gEfiGraphicsOutputProtocolGuid
, (VOID
**) &GraphicsOutput
);
322 if (EFI_ERROR (Status
) && FeaturePcdGet (PcdUgaConsumeSupport
)) {
323 GraphicsOutput
= NULL
;
325 // Open GOP failed, try to open UGA
327 Status
= gBS
->HandleProtocol (gST
->ConsoleOutHandle
, &gEfiUgaDrawProtocolGuid
, (VOID
**) &UgaDraw
);
329 if (EFI_ERROR (Status
)) {
330 return EFI_UNSUPPORTED
;
334 // Try to open Boot Logo Protocol.
337 gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
340 // Erase Cursor from screen
342 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
345 Status
= gBS
->LocateProtocol (&gEfiOEMBadgingProtocolGuid
, NULL
, (VOID
**) &Badging
);
347 if (GraphicsOutput
!= NULL
) {
348 SizeOfX
= GraphicsOutput
->Mode
->Info
->HorizontalResolution
;
349 SizeOfY
= GraphicsOutput
->Mode
->Info
->VerticalResolution
;
351 } else if (UgaDraw
!= NULL
&& FeaturePcdGet (PcdUgaConsumeSupport
)) {
352 Status
= UgaDraw
->GetMode (UgaDraw
, &SizeOfX
, &SizeOfY
, &ColorDepth
, &RefreshRate
);
353 if (EFI_ERROR (Status
)) {
354 return EFI_UNSUPPORTED
;
357 return EFI_UNSUPPORTED
;
377 if (Badging
!= NULL
) {
379 // Get image from OEMBadging protocol.
381 Status
= Badging
->GetImage (
391 if (EFI_ERROR (Status
)) {
396 // Currently only support BMP format.
398 if (Format
!= EfiBadgingFormatBMP
) {
399 if (ImageData
!= NULL
) {
400 FreePool (ImageData
);
406 // Get the specified image from FV.
408 Status
= GetSectionFromAnyFv (LogoFile
, EFI_SECTION_RAW
, 0, (VOID
**) &ImageData
, &ImageSize
);
409 if (EFI_ERROR (Status
)) {
410 return EFI_UNSUPPORTED
;
415 if (!FeaturePcdGet(PcdBootlogoOnlyEnable
)) {
416 Attribute
= EfiBadgingDisplayAttributeCenter
;
418 Attribute
= EfiBadgingDisplayAttributeCustomized
;
426 Status
= ConvertBmpToGopBlt (
434 if (EFI_ERROR (Status
)) {
435 FreePool (ImageData
);
437 if (Badging
== NULL
) {
445 // Calculate the display position according to Attribute.
448 case EfiBadgingDisplayAttributeLeftTop
:
453 case EfiBadgingDisplayAttributeCenterTop
:
454 DestX
= (SizeOfX
- Width
) / 2;
458 case EfiBadgingDisplayAttributeRightTop
:
459 DestX
= (SizeOfX
- Width
- CoordinateX
);
460 DestY
= CoordinateY
;;
463 case EfiBadgingDisplayAttributeCenterRight
:
464 DestX
= (SizeOfX
- Width
- CoordinateX
);
465 DestY
= (SizeOfY
- Height
) / 2;
468 case EfiBadgingDisplayAttributeRightBottom
:
469 DestX
= (SizeOfX
- Width
- CoordinateX
);
470 DestY
= (SizeOfY
- Height
- CoordinateY
);
473 case EfiBadgingDisplayAttributeCenterBottom
:
474 DestX
= (SizeOfX
- Width
) / 2;
475 DestY
= (SizeOfY
- Height
- CoordinateY
);
478 case EfiBadgingDisplayAttributeLeftBottom
:
480 DestY
= (SizeOfY
- Height
- CoordinateY
);
483 case EfiBadgingDisplayAttributeCenterLeft
:
485 DestY
= (SizeOfY
- Height
) / 2;
488 case EfiBadgingDisplayAttributeCenter
:
489 DestX
= (SizeOfX
- Width
) / 2;
490 DestY
= (SizeOfY
- Height
) / 2;
493 case EfiBadgingDisplayAttributeCustomized
:
494 DestX
= (SizeOfX
- Width
) / 2;
495 DestY
= ((SizeOfY
* 382) / 1000) - Height
/ 2;
504 if ((DestX
>= 0) && (DestY
>= 0)) {
505 if (GraphicsOutput
!= NULL
) {
506 Status
= GraphicsOutput
->Blt (
516 Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
)
518 } else if (UgaDraw
!= NULL
&& FeaturePcdGet (PcdUgaConsumeSupport
)) {
519 Status
= UgaDraw
->Blt (
521 (EFI_UGA_PIXEL
*) Blt
,
522 EfiUgaBltBufferToVideo
,
529 Width
* sizeof (EFI_UGA_PIXEL
)
532 Status
= EFI_UNSUPPORTED
;
536 // Report displayed Logo information.
538 if (!EFI_ERROR (Status
)) {
541 if (LogoWidth
== 0) {
545 LogoDestX
= (UINTN
) DestX
;
546 LogoDestY
= (UINTN
) DestY
;
551 // Merge new logo with old one.
553 NewDestX
= MIN ((UINTN
) DestX
, LogoDestX
);
554 NewDestY
= MIN ((UINTN
) DestY
, LogoDestY
);
555 NewWidth
= MAX ((UINTN
) DestX
+ Width
, LogoDestX
+ LogoWidth
) - NewDestX
;
556 NewHeight
= MAX ((UINTN
) DestY
+ Height
, LogoDestY
+ LogoHeight
) - NewDestY
;
558 LogoDestX
= NewDestX
;
559 LogoDestY
= NewDestY
;
560 LogoWidth
= NewWidth
;
561 LogoHeight
= NewHeight
;
566 FreePool (ImageData
);
568 if (Badging
== NULL
) {
574 if (BootLogo
== NULL
|| NumberOfLogos
== 0) {
576 // No logo displayed.
586 // Advertise displayed Logo information.
588 if (NumberOfLogos
== 1) {
590 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
593 Status
= EFI_SUCCESS
;
596 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
603 // Ensure the LogoHeight * LogoWidth doesn't overflow
605 if (LogoHeight
> DivU64x64Remainder ((UINTN
) ~0, LogoWidth
, NULL
)) {
606 return EFI_UNSUPPORTED
;
608 BufferSize
= MultU64x64 (LogoWidth
, LogoHeight
);
611 // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
613 if (BufferSize
> DivU64x32 ((UINTN
) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
))) {
614 return EFI_UNSUPPORTED
;
617 LogoBlt
= AllocateZeroPool ((UINTN
)BufferSize
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
618 if (LogoBlt
== NULL
) {
619 return EFI_OUT_OF_RESOURCES
;
622 if (GraphicsOutput
!= NULL
) {
623 Status
= GraphicsOutput
->Blt (
626 EfiBltVideoToBltBuffer
,
633 LogoWidth
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
)
635 } else if (UgaDraw
!= NULL
&& FeaturePcdGet (PcdUgaConsumeSupport
)) {
636 Status
= UgaDraw
->Blt (
638 (EFI_UGA_PIXEL
*) LogoBlt
,
639 EfiUgaVideoToBltBuffer
,
646 LogoWidth
* sizeof (EFI_UGA_PIXEL
)
649 Status
= EFI_UNSUPPORTED
;
653 if (!EFI_ERROR (Status
)) {
654 BootLogo
->SetBootLogo (BootLogo
, LogoBlt
, LogoDestX
, LogoDestY
, LogoWidth
, LogoHeight
);
662 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
663 Simple Text Out screens will now be synced up with all non video output devices
665 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
675 // Enable Cursor on Screen
677 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);