blob: 5ccec593f5757914e7d24dc8d183b652b9210a16 [file] [log] [blame]
Subrata Banik7bc92f02023-08-03 10:11:28 +00001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <bootsplash.h>
4#include <console/console.h>
5#include <fsp/api.h>
6#include <fsp/fsp_gop_blt.h>
7#include <lib.h>
8#include <stdlib.h>
9
10static bool is_bmp_image_valid(efi_bmp_image_header *header)
11{
12 if (header == NULL)
13 return false;
14
15 /* Check if the BMP Header Signature is valid */
16 if (header->CharB != 'B' || header->CharM != 'M')
17 return false;
18
19 /* Check if the BMP Image Header Length is valid */
20 if (!header->PixelHeight || !header->PixelWidth)
21 return false;
22
23 if (header->Size < header->ImageOffset)
24 return false;
25
26 if (header->ImageOffset < sizeof(efi_bmp_image_header))
27 return false;
28
29 return true;
30}
31
32static bool is_bmp_image_compressed(efi_bmp_image_header *header)
33{
34 if (header == NULL)
35 return false;
36
37 if (header->CompressionType != 0)
38 return true;
39
40 return false;
41}
42
43static bool is_bitmap_format_supported(efi_bmp_image_header *header)
44{
45 if (header == NULL)
46 return false;
47
48 /*
49 * Check BITMAP format is supported
50 * BMP_IMAGE_HEADER = BITMAP_FILE_HEADER + BITMAP_INFO_HEADER
51 */
52 if (header->HeaderSize != sizeof(efi_bmp_image_header) -
53 OFFSET_OF(efi_bmp_image_header, HeaderSize))
54 return false;
55
56 return true;
57}
58
59static bool do_bmp_image_authentication(efi_bmp_image_header *header)
60{
61 if (header == NULL)
62 return false;
63
64 if (!is_bmp_image_valid(header)) {
65 printk(BIOS_ERR, "%s: BMP Image Header is invalid.\n", __func__);
66 return false;
67 }
68
69 /*
70 * BMP image compression is unsupported by FSP implementation,
71 * hence, exit if the BMP image is compressed.
72 */
73 if (is_bmp_image_compressed(header)) {
74 printk(BIOS_ERR, "%s: BMP Image Compression is unsupported.\n", __func__);
75 return false;
76 }
77
78 if (!is_bitmap_format_supported(header)) {
79 printk(BIOS_ERR, "%s: BmpHeader Header Size (0x%x) is not as expected.\n",
80 __func__, header->HeaderSize);
81 return false;
82 }
83
84 return true;
85}
86
87static uint32_t calculate_blt_buffer_size(efi_bmp_image_header *header)
88{
89 uint32_t blt_buffer_size;
90
91 if (header == NULL)
92 return 0;
93
94 /* Calculate the size required for BLT buffer */
95 blt_buffer_size = header->PixelWidth * header->PixelHeight *
96 sizeof(efi_graphics_output_blt_pixel);
97 if (!blt_buffer_size)
98 return 0;
99
100 return blt_buffer_size;
101}
102
103static uint32_t get_color_map_num(efi_bmp_image_header *header)
104{
105 uint32_t col_map_number = 0;
106
107 if (header == NULL)
108 return 0;
109
110 switch (header->BitPerPixel) {
111 case 1:
112 col_map_number = 2;
113 break;
114 case 4:
115 col_map_number = 16;
116 break;
117 case 8:
118 col_map_number = 256;
119 break;
120 default:
121 break;
122 }
123
124 /*
125 * At times BMP file may have padding data between its header section and the
126 * data section.
127 */
128 if (header->ImageOffset - sizeof(efi_bmp_image_header) <
129 sizeof(efi_bmp_color_map) * col_map_number)
130 return 0;
131
132 return col_map_number;
133}
134
135/* Fill BMP image into BLT buffer format */
136static void *fill_blt_buffer(efi_bmp_image_header *header,
137 uint32_t logo_ptr, uint32_t blt_buffer_size)
138{
139 efi_graphics_output_blt_pixel *gop_blt_buffer;
140 efi_graphics_output_blt_pixel *gop_blt_ptr;
141 efi_graphics_output_blt_pixel *gop_blt;
142 uint8_t *bmp_image;
143 uint8_t *bmp_image_header;
144 efi_bmp_color_map *bmp_color_map;
145 size_t image_index;
146
147 if (header == NULL)
148 return NULL;
149
150 gop_blt_ptr = malloc(sizeof(blt_buffer_size));
151 if (!gop_blt_ptr)
152 die("%s: out of memory. Consider increasing the `CONFIG_HEAP_SIZE`\n",
153 __func__);
154
155 bmp_image = ((UINT8 *)logo_ptr) + header->ImageOffset;
156 bmp_image_header = bmp_image;
157 gop_blt_buffer = gop_blt_ptr;
158 bmp_color_map = (efi_bmp_color_map *)(logo_ptr + sizeof(efi_bmp_image_header));
159
160 for (size_t height = 0; height < header->PixelHeight; height++) {
161 gop_blt = &gop_blt_buffer[(header->PixelHeight - height - 1) *
162 header->PixelWidth];
163 for (size_t width = 0; width < header->PixelWidth; width++, bmp_image++,
164 gop_blt++) {
165 size_t index = 0;
166 switch (header->BitPerPixel) {
167 /* Translate 1-bit (2 colors) BMP to 24-bit color */
168 case 1:
169 for (index = 0; index < 8 && width < header->PixelWidth; index++) {
170 gop_blt->Red = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Red;
171 gop_blt->Green = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Green;
172 gop_blt->Blue = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Blue;
173 gop_blt++;
174 width++;
175 }
176 gop_blt--;
177 width--;
178 break;
179
180 /* Translate 4-bit (16 colors) BMP Palette to 24-bit color */
181 case 4:
182 index = (*bmp_image) >> 4;
183 gop_blt->Red = bmp_color_map[index].Red;
184 gop_blt->Green = bmp_color_map[index].Green;
185 gop_blt->Blue = bmp_color_map[index].Blue;
186 if (width < (header->PixelWidth - 1)) {
187 gop_blt++;
188 width++;
189 index = (*bmp_image) & 0x0f;
190 gop_blt->Red = bmp_color_map[index].Red;
191 gop_blt->Green = bmp_color_map[index].Green;
192 gop_blt->Blue = bmp_color_map[index].Blue;
193 }
194 break;
195
196 /* Translate 8-bit (256 colors) BMP Palette to 24-bit color */
197 case 8:
198 gop_blt->Red = bmp_color_map[*bmp_image].Red;
199 gop_blt->Green = bmp_color_map[*bmp_image].Green;
200 gop_blt->Blue = bmp_color_map[*bmp_image].Blue;
201 break;
202
203 /* For 24-bit BMP */
204 case 24:
205 gop_blt->Blue = *bmp_image++;
206 gop_blt->Green = *bmp_image++;
207 gop_blt->Red = *bmp_image;
208 break;
209
Martin Roth74f18772023-09-03 21:38:29 -0600210 /* Convert 32 bit to 24bit bmp - just ignore the final byte of each pixel */
Subrata Banik7bc92f02023-08-03 10:11:28 +0000211 case 32:
212 gop_blt->Blue = *bmp_image++;
213 gop_blt->Green = *bmp_image++;
214 gop_blt->Red = *bmp_image++;
215 break;
216
217 /* Other bit format of BMP is not supported. */
218 default:
219 free(gop_blt_ptr);
220 gop_blt_ptr = NULL;
221
222 printk(BIOS_ERR, "%s, BMP Bit format not supported. 0x%X\n", __func__,
223 header->BitPerPixel);
224 return NULL;
225 }
226 }
227 image_index = (uintptr_t)bmp_image - (uintptr_t)bmp_image_header;
228 /* Each row in BMP Image should be 4-byte align */
229 if ((image_index % 4) != 0)
230 bmp_image = bmp_image + (4 - (image_index % 4));
231 }
232
233 return gop_blt_ptr;
234}
235
236/* Convert a *.BMP graphics image to a GOP blt buffer */
237void fsp_convert_bmp_to_gop_blt(uint32_t *logo, uint32_t *logo_size,
238 uint32_t *blt_ptr, uint32_t *blt_size,
239 uint32_t *pixel_height, uint32_t *pixel_width)
240{
241 uint32_t logo_ptr, logo_ptr_size, blt_buffer_size;
242 efi_bmp_image_header *bmp_header;
243
244 if (!logo || !logo_size || !blt_ptr || !blt_size || !pixel_height || !pixel_width)
245 return;
246
247 bmp_load_logo(&logo_ptr, &logo_ptr_size);
248 if (!logo_ptr || logo_ptr_size < sizeof(efi_bmp_image_header)) {
249 printk(BIOS_ERR, "%s: BMP Image size is too small.\n", __func__);
250 return;
251 }
252
253 bmp_header = (efi_bmp_image_header *)logo_ptr;
254 if (!do_bmp_image_authentication(bmp_header) || (bmp_header->Size != logo_ptr_size))
255 return;
256
257 blt_buffer_size = calculate_blt_buffer_size(bmp_header);
258 if (!blt_buffer_size)
259 return;
260
261 if (!get_color_map_num(bmp_header))
262 return;
263
264 *logo = logo_ptr;
265 *logo_size = logo_ptr_size;
266 *blt_size = blt_buffer_size;
267 *pixel_height = bmp_header->PixelHeight;
268 *pixel_width = bmp_header->PixelWidth;
269 *blt_ptr = (uint32_t)fill_blt_buffer(bmp_header, logo_ptr, blt_buffer_size);
270}