2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation; either version 2.1 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
13 * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
28 } __attribute__((packed
));
30 /* we require at least BITMAPINFOHEADER, later versions are
31 accepted, but their features ignored */
43 UINT32 colors_important
;
44 } __attribute__((packed
));
51 } __attribute__((packed
));
53 EFI_STATUS
bmp_parse_header(UINT8
*bmp
, UINTN size
, struct bmp_dib
**ret_dib
,
54 struct bmp_map
**ret_map
, UINT8
**pixmap
) {
55 struct bmp_file
*file
;
60 if (size
< sizeof(struct bmp_file
) + sizeof(struct bmp_dib
))
61 return EFI_INVALID_PARAMETER
;
63 /* check file header */
64 file
= (struct bmp_file
*)bmp
;
65 if (file
->signature
[0] != 'B' || file
->signature
[1] != 'M')
66 return EFI_INVALID_PARAMETER
;
67 if (file
->size
!= size
)
68 return EFI_INVALID_PARAMETER
;
69 if (file
->size
< file
->offset
)
70 return EFI_INVALID_PARAMETER
;
72 /* check device-independent bitmap */
73 dib
= (struct bmp_dib
*)(bmp
+ sizeof(struct bmp_file
));
74 if (dib
->size
< sizeof(struct bmp_dib
))
75 return EFI_UNSUPPORTED
;
82 if (dib
->compression
!= 0)
83 return EFI_UNSUPPORTED
;
89 if (dib
->compression
!= 0 && dib
->compression
!= 3)
90 return EFI_UNSUPPORTED
;
95 return EFI_UNSUPPORTED
;
98 row_size
= ((UINTN
) dib
->depth
* dib
->x
+ 31) / 32 * 4;
99 if (file
->size
- file
->offset
< dib
->y
* row_size
)
100 return EFI_INVALID_PARAMETER
;
101 if (row_size
* dib
->y
> 64 * 1024 * 1024)
102 return EFI_INVALID_PARAMETER
;
104 /* check color table */
105 map
= (struct bmp_map
*)(bmp
+ sizeof(struct bmp_file
) + dib
->size
);
106 if (file
->offset
< sizeof(struct bmp_file
) + dib
->size
)
107 return EFI_INVALID_PARAMETER
;
109 if (file
->offset
> sizeof(struct bmp_file
) + dib
->size
) {
113 if (dib
->colors_used
)
114 map_count
= dib
->colors_used
;
116 switch (dib
->depth
) {
120 map_count
= 1 << dib
->depth
;
129 map_size
= file
->offset
- (sizeof(struct bmp_file
) + dib
->size
);
130 if (map_size
!= sizeof(struct bmp_map
) * map_count
)
131 return EFI_INVALID_PARAMETER
;
136 *pixmap
= bmp
+ file
->offset
;
141 static VOID
pixel_blend(UINT32
*dst
, const UINT32 source
) {
142 UINT32 alpha
, src
, src_rb
, src_g
, dst_rb
, dst_g
, rb
, g
;
144 alpha
= (source
& 0xff);
146 /* convert src from RGBA to XRGB */
149 /* decompose into RB and G components */
150 src_rb
= (src
& 0xff00ff);
151 src_g
= (src
& 0x00ff00);
153 dst_rb
= (*dst
& 0xff00ff);
154 dst_g
= (*dst
& 0x00ff00);
157 rb
= ((((src_rb
- dst_rb
) * alpha
+ 0x800080) >> 8) + dst_rb
) & 0xff00ff;
158 g
= ((((src_g
- dst_g
) * alpha
+ 0x008000) >> 8) + dst_g
) & 0x00ff00;
163 EFI_STATUS
bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*buf
,
164 struct bmp_dib
*dib
, struct bmp_map
*map
,
169 /* transform and copy pixels */
171 for (y
= 0; y
< dib
->y
; y
++) {
172 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*out
;
176 out
= &buf
[(dib
->y
- y
- 1) * dib
->x
];
177 for (x
= 0; x
< dib
->x
; x
++, in
++, out
++) {
178 switch (dib
->depth
) {
182 for (i
= 0; i
< 8 && x
< dib
->x
; i
++) {
183 out
->Red
= map
[((*in
) >> (7 - i
)) & 1].red
;
184 out
->Green
= map
[((*in
) >> (7 - i
)) & 1].green
;
185 out
->Blue
= map
[((*in
) >> (7 - i
)) & 1].blue
;
198 out
->Red
= map
[i
].red
;
199 out
->Green
= map
[i
].green
;
200 out
->Blue
= map
[i
].blue
;
201 if (x
< (dib
->x
- 1)) {
205 out
->Red
= map
[i
].red
;
206 out
->Green
= map
[i
].green
;
207 out
->Blue
= map
[i
].blue
;
213 out
->Red
= map
[*in
].red
;
214 out
->Green
= map
[*in
].green
;
215 out
->Blue
= map
[*in
].blue
;
219 UINT16 i
= *(UINT16
*) in
;
221 out
->Red
= (i
& 0x7c00) >> 7;
222 out
->Green
= (i
& 0x3e0) >> 2;
223 out
->Blue
= (i
& 0x1f) << 3;
236 UINT32 i
= *(UINT32
*) in
;
238 pixel_blend((UINT32
*)out
, i
);
246 /* add row padding; new lines always start at 32 bit boundary */
247 row_size
= in
- pixmap
;
248 in
+= ((row_size
+ 3) & ~3) - row_size
;
254 EFI_STATUS
graphics_splash(UINT8
*content
, UINTN len
, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*background
) {
255 EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel
= {};
256 EFI_GUID GraphicsOutputProtocolGuid
= EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
;
257 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
= NULL
;
268 if (StriCmp(L
"Apple", ST
->FirmwareVendor
) == 0) {
276 err
= LibLocateProtocol(&GraphicsOutputProtocolGuid
, (VOID
**)&GraphicsOutput
);
280 err
= bmp_parse_header(content
, len
, &dib
, &map
, &pixmap
);
284 if(dib
->x
< GraphicsOutput
->Mode
->Info
->HorizontalResolution
)
285 x_pos
= (GraphicsOutput
->Mode
->Info
->HorizontalResolution
- dib
->x
) / 2;
286 if(dib
->y
< GraphicsOutput
->Mode
->Info
->VerticalResolution
)
287 y_pos
= (GraphicsOutput
->Mode
->Info
->VerticalResolution
- dib
->y
) / 2;
289 uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
290 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)background
,
291 EfiBltVideoFill
, 0, 0, 0, 0,
292 GraphicsOutput
->Mode
->Info
->HorizontalResolution
,
293 GraphicsOutput
->Mode
->Info
->VerticalResolution
, 0);
296 blt_size
= dib
->x
* dib
->y
* sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
297 blt
= AllocatePool(blt_size
);
299 return EFI_OUT_OF_RESOURCES
;
301 err
= uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
302 blt
, EfiBltVideoToBltBuffer
, x_pos
, y_pos
, 0, 0,
307 err
= bmp_to_blt(blt
, dib
, map
, pixmap
);
311 err
= graphics_mode(TRUE
);
315 err
= uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
316 blt
, EfiBltBufferToVideo
, 0, 0, x_pos
, y_pos
,