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