1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
15 * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
16 * Copyright (C) 2013 Intel Corporation
17 * Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
26 EFI_STATUS
graphics_mode(BOOLEAN on
) {
27 #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
28 { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } };
30 struct _EFI_CONSOLE_CONTROL_PROTOCOL
;
33 EfiConsoleControlScreenText
,
34 EfiConsoleControlScreenGraphics
,
35 EfiConsoleControlScreenMaxValue
,
36 } EFI_CONSOLE_CONTROL_SCREEN_MODE
;
38 typedef EFI_STATUS (EFIAPI
*EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE
)(
39 struct _EFI_CONSOLE_CONTROL_PROTOCOL
*This
,
40 EFI_CONSOLE_CONTROL_SCREEN_MODE
*Mode
,
45 typedef EFI_STATUS (EFIAPI
*EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE
)(
46 struct _EFI_CONSOLE_CONTROL_PROTOCOL
*This
,
47 EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
50 typedef EFI_STATUS (EFIAPI
*EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN
)(
51 struct _EFI_CONSOLE_CONTROL_PROTOCOL
*This
,
55 typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL
{
56 EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode
;
57 EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode
;
58 EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn
;
59 } EFI_CONSOLE_CONTROL_PROTOCOL
;
61 EFI_GUID ConsoleControlProtocolGuid
= EFI_CONSOLE_CONTROL_PROTOCOL_GUID
;
62 EFI_CONSOLE_CONTROL_PROTOCOL
*ConsoleControl
= NULL
;
63 EFI_CONSOLE_CONTROL_SCREEN_MODE
new;
64 EFI_CONSOLE_CONTROL_SCREEN_MODE current
;
69 err
= LibLocateProtocol(&ConsoleControlProtocolGuid
, (VOID
**)&ConsoleControl
);
71 /* console control protocol is nonstandard and might not exist. */
72 return err
== EFI_NOT_FOUND
? EFI_SUCCESS
: err
;
75 /* check current mode */
76 err
= uefi_call_wrapper(ConsoleControl
->GetMode
, 4, ConsoleControl
, ¤t
, &uga_exists
, &stdin_locked
);
80 /* do not touch the mode */
81 new = on
? EfiConsoleControlScreenGraphics
: EfiConsoleControlScreenText
;
85 err
= uefi_call_wrapper(ConsoleControl
->SetMode
, 2, ConsoleControl
, new);
87 /* some firmware enables the cursor when switching modes */
88 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
, FALSE
);
98 } __attribute__((packed
));
100 /* we require at least BITMAPINFOHEADER, later versions are
101 accepted, but their features ignored */
113 UINT32 colors_important
;
114 } __attribute__((packed
));
121 } __attribute__((packed
));
123 EFI_STATUS
bmp_parse_header(UINT8
*bmp
, UINTN size
, struct bmp_dib
**ret_dib
,
124 struct bmp_map
**ret_map
, UINT8
**pixmap
) {
125 struct bmp_file
*file
;
130 if (size
< sizeof(struct bmp_file
) + sizeof(struct bmp_dib
))
131 return EFI_INVALID_PARAMETER
;
133 /* check file header */
134 file
= (struct bmp_file
*)bmp
;
135 if (file
->signature
[0] != 'B' || file
->signature
[1] != 'M')
136 return EFI_INVALID_PARAMETER
;
137 if (file
->size
!= size
)
138 return EFI_INVALID_PARAMETER
;
139 if (file
->size
< file
->offset
)
140 return EFI_INVALID_PARAMETER
;
142 /* check device-independent bitmap */
143 dib
= (struct bmp_dib
*)(bmp
+ sizeof(struct bmp_file
));
144 if (dib
->size
< sizeof(struct bmp_dib
))
145 return EFI_UNSUPPORTED
;
147 switch (dib
->depth
) {
152 if (dib
->compression
!= 0)
153 return EFI_UNSUPPORTED
;
159 if (dib
->compression
!= 0 && dib
->compression
!= 3)
160 return EFI_UNSUPPORTED
;
165 return EFI_UNSUPPORTED
;
168 row_size
= (((dib
->depth
* dib
->x
) + 31) / 32) * 4;
169 if (file
->size
- file
->offset
< dib
->y
* row_size
)
170 return EFI_INVALID_PARAMETER
;
171 if (row_size
* dib
->y
> 64 * 1024 * 1024)
172 return EFI_INVALID_PARAMETER
;
174 /* check color table */
175 map
= (struct bmp_map
*)(bmp
+ sizeof(struct bmp_file
) + dib
->size
);
176 if (file
->offset
< sizeof(struct bmp_file
) + dib
->size
)
177 return EFI_INVALID_PARAMETER
;
179 if (file
->offset
> sizeof(struct bmp_file
) + dib
->size
) {
183 if (dib
->colors_used
)
184 map_count
= dib
->colors_used
;
186 switch (dib
->depth
) {
190 map_count
= 1 << dib
->depth
;
199 map_size
= file
->offset
- (sizeof(struct bmp_file
) + dib
->size
);
200 if (map_size
!= sizeof(struct bmp_map
) * map_count
)
201 return EFI_INVALID_PARAMETER
;
206 *pixmap
= bmp
+ file
->offset
;
211 static VOID
pixel_blend(UINT32
*dst
, const UINT32 source
) {
212 UINT32 alpha
, src
, src_rb
, src_g
, dst_rb
, dst_g
, rb
, g
;
214 alpha
= (source
& 0xff);
216 /* convert src from RGBA to XRGB */
219 /* decompose into RB and G components */
220 src_rb
= (src
& 0xff00ff);
221 src_g
= (src
& 0x00ff00);
223 dst_rb
= (*dst
& 0xff00ff);
224 dst_g
= (*dst
& 0x00ff00);
227 rb
= ((((src_rb
- dst_rb
) * alpha
+ 0x800080) >> 8) + dst_rb
) & 0xff00ff;
228 g
= ((((src_g
- dst_g
) * alpha
+ 0x008000) >> 8) + dst_g
) & 0x00ff00;
233 EFI_STATUS
bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*buf
,
234 struct bmp_dib
*dib
, struct bmp_map
*map
,
239 /* transform and copy pixels */
241 for (y
= 0; y
< dib
->y
; y
++) {
242 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*out
;
246 out
= &buf
[(dib
->y
- y
- 1) * dib
->x
];
247 for (x
= 0; x
< dib
->x
; x
++, in
++, out
++) {
248 switch (dib
->depth
) {
252 for (i
= 0; i
< 8 && x
< dib
->x
; i
++) {
253 out
->Red
= map
[((*in
) >> (7 - i
)) & 1].red
;
254 out
->Green
= map
[((*in
) >> (7 - i
)) & 1].green
;
255 out
->Blue
= map
[((*in
) >> (7 - i
)) & 1].blue
;
268 out
->Red
= map
[i
].red
;
269 out
->Green
= map
[i
].green
;
270 out
->Blue
= map
[i
].blue
;
271 if (x
< (dib
->x
- 1)) {
275 out
->Red
= map
[i
].red
;
276 out
->Green
= map
[i
].green
;
277 out
->Blue
= map
[i
].blue
;
283 out
->Red
= map
[*in
].red
;
284 out
->Green
= map
[*in
].green
;
285 out
->Blue
= map
[*in
].blue
;
289 UINT16 i
= *(UINT16
*) in
;
291 out
->Red
= (i
& 0x7c00) >> 7;
292 out
->Green
= (i
& 0x3e0) >> 2;
293 out
->Blue
= (i
& 0x1f) << 3;
306 UINT32 i
= *(UINT32
*) in
;
308 pixel_blend((UINT32
*)out
, i
);
316 /* add row padding; new lines always start at 32 bit boundary */
317 row_size
= in
- pixmap
;
318 in
+= ((row_size
+ 3) & ~3) - row_size
;
324 EFI_STATUS
graphics_splash(EFI_FILE
*root_dir
, CHAR16
*path
,
325 const EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*background
) {
326 EFI_GUID GraphicsOutputProtocolGuid
= EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
;
327 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
= NULL
;
339 err
= LibLocateProtocol(&GraphicsOutputProtocolGuid
, (VOID
**)&GraphicsOutput
);
343 len
= file_read(root_dir
, path
, 0, 0, &content
);
345 return EFI_LOAD_ERROR
;
347 err
= bmp_parse_header(content
, len
, &dib
, &map
, &pixmap
);
351 if(dib
->x
< GraphicsOutput
->Mode
->Info
->HorizontalResolution
)
352 x_pos
= (GraphicsOutput
->Mode
->Info
->HorizontalResolution
- dib
->x
) / 2;
353 if(dib
->y
< GraphicsOutput
->Mode
->Info
->VerticalResolution
)
354 y_pos
= (GraphicsOutput
->Mode
->Info
->VerticalResolution
- dib
->y
) / 2;
356 uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
357 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)background
,
358 EfiBltVideoFill
, 0, 0, 0, 0,
359 GraphicsOutput
->Mode
->Info
->HorizontalResolution
,
360 GraphicsOutput
->Mode
->Info
->VerticalResolution
, 0);
363 blt_size
= dib
->x
* dib
->y
* sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
364 blt
= AllocatePool(blt_size
);
366 return EFI_OUT_OF_RESOURCES
;
368 err
= uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
369 blt
, EfiBltVideoToBltBuffer
, x_pos
, y_pos
, 0, 0,
374 err
= bmp_to_blt(blt
, dib
, map
, pixmap
);
378 err
= graphics_mode(TRUE
);
382 err
= uefi_call_wrapper(GraphicsOutput
->Blt
, 10, GraphicsOutput
,
383 blt
, EfiBltBufferToVideo
, 0, 0, x_pos
, y_pos
,