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>
30 } __attribute__((packed));
32 /* we require at least BITMAPINFOHEADER, later versions are
33 accepted, but their features ignored */
45 UINT32 colors_important;
46 } __attribute__((packed));
53 } __attribute__((packed));
55 EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
56 struct bmp_map **ret_map, UINT8 **pixmap) {
57 struct bmp_file *file;
62 if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib))
63 return EFI_INVALID_PARAMETER;
65 /* check file header */
66 file = (struct bmp_file *)bmp;
67 if (file->signature[0] != 'B' || file->signature[1] != 'M')
68 return EFI_INVALID_PARAMETER;
69 if (file->size != size)
70 return EFI_INVALID_PARAMETER;
71 if (file->size < file->offset)
72 return EFI_INVALID_PARAMETER;
74 /* check device-independent bitmap */
75 dib = (struct bmp_dib *)(bmp + sizeof(struct bmp_file));
76 if (dib->size < sizeof(struct bmp_dib))
77 return EFI_UNSUPPORTED;
84 if (dib->compression != 0)
85 return EFI_UNSUPPORTED;
91 if (dib->compression != 0 && dib->compression != 3)
92 return EFI_UNSUPPORTED;
97 return EFI_UNSUPPORTED;
100 row_size = ((UINTN) dib->depth * dib->x + 31) / 32 * 4;
101 if (file->size - file->offset < dib->y * row_size)
102 return EFI_INVALID_PARAMETER;
103 if (row_size * dib->y > 64 * 1024 * 1024)
104 return EFI_INVALID_PARAMETER;
106 /* check color table */
107 map = (struct bmp_map *)(bmp + sizeof(struct bmp_file) + dib->size);
108 if (file->offset < sizeof(struct bmp_file) + dib->size)
109 return EFI_INVALID_PARAMETER;
111 if (file->offset > sizeof(struct bmp_file) + dib->size) {
115 if (dib->colors_used)
116 map_count = dib->colors_used;
118 switch (dib->depth) {
122 map_count = 1 << dib->depth;
131 map_size = file->offset - (sizeof(struct bmp_file) + dib->size);
132 if (map_size != sizeof(struct bmp_map) * map_count)
133 return EFI_INVALID_PARAMETER;
138 *pixmap = bmp + file->offset;
143 static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
144 UINT32 alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g;
146 alpha = (source & 0xff);
148 /* convert src from RGBA to XRGB */
151 /* decompose into RB and G components */
152 src_rb = (src & 0xff00ff);
153 src_g = (src & 0x00ff00);
155 dst_rb = (*dst & 0xff00ff);
156 dst_g = (*dst & 0x00ff00);
159 rb = ((((src_rb - dst_rb) * alpha + 0x800080) >> 8) + dst_rb) & 0xff00ff;
160 g = ((((src_g - dst_g) * alpha + 0x008000) >> 8) + dst_g) & 0x00ff00;
165 EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
166 struct bmp_dib *dib, struct bmp_map *map,
171 /* transform and copy pixels */
173 for (y = 0; y < dib->y; y++) {
174 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out;
178 out = &buf[(dib->y - y - 1) * dib->x];
179 for (x = 0; x < dib->x; x++, in++, out++) {
180 switch (dib->depth) {
184 for (i = 0; i < 8 && x < dib->x; i++) {
185 out->Red = map[((*in) >> (7 - i)) & 1].red;
186 out->Green = map[((*in) >> (7 - i)) & 1].green;
187 out->Blue = map[((*in) >> (7 - i)) & 1].blue;
200 out->Red = map[i].red;
201 out->Green = map[i].green;
202 out->Blue = map[i].blue;
203 if (x < (dib->x - 1)) {
207 out->Red = map[i].red;
208 out->Green = map[i].green;
209 out->Blue = map[i].blue;
215 out->Red = map[*in].red;
216 out->Green = map[*in].green;
217 out->Blue = map[*in].blue;
221 UINT16 i = *(UINT16 *) in;
223 out->Red = (i & 0x7c00) >> 7;
224 out->Green = (i & 0x3e0) >> 2;
225 out->Blue = (i & 0x1f) << 3;
238 UINT32 i = *(UINT32 *) in;
240 pixel_blend((UINT32 *)out, i);
248 /* add row padding; new lines always start at 32 bit boundary */
249 row_size = in - pixmap;
250 in += ((row_size + 3) & ~3) - row_size;
256 EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
257 EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel = {};
258 EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
259 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
270 if (StriCmp(L"Apple", ST->FirmwareVendor) == 0) {
278 err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
282 err = bmp_parse_header(content, len, &dib, &map, &pixmap);
286 if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution)
287 x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2;
288 if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution)
289 y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2;
291 uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
292 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)background,
293 EfiBltVideoFill, 0, 0, 0, 0,
294 GraphicsOutput->Mode->Info->HorizontalResolution,
295 GraphicsOutput->Mode->Info->VerticalResolution, 0);
298 blt_size = dib->x * dib->y * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
299 blt = AllocatePool(blt_size);
301 return EFI_OUT_OF_RESOURCES;
303 err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
304 blt, EfiBltVideoToBltBuffer, x_pos, y_pos, 0, 0,
309 err = bmp_to_blt(blt, dib, map, pixmap);
313 err = graphics_mode(TRUE);
317 err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
318 blt, EfiBltBufferToVideo, 0, 0, x_pos, y_pos,