xref: /aosp_15_r20/external/coreboot/src/drivers/intel/fsp2_0/fsp_gop_blt.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* 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 <stdlib.h>
8 
is_bmp_image_valid(efi_bmp_image_header * header)9 static 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 
is_bmp_image_compressed(efi_bmp_image_header * header)31 static 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 
is_bitmap_format_supported(efi_bmp_image_header * header)42 static 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 
do_bmp_image_authentication(efi_bmp_image_header * header)58 static 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 
calculate_blt_buffer_size(efi_bmp_image_header * header)86 static 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 
get_color_map_num(efi_bmp_image_header * header)102 static 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 */
fill_blt_buffer(efi_bmp_image_header * header,uintptr_t logo_ptr,size_t blt_buffer_size)135 static void *fill_blt_buffer(efi_bmp_image_header *header,
136 	uintptr_t logo_ptr, size_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 
154 	bmp_image = ((uint8_t *)logo_ptr) + header->ImageOffset;
155 	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 
209 			/* Convert 32 bit to 24bit bmp - just ignore the final byte of each pixel */
210 			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 */
fsp_convert_bmp_to_gop_blt(efi_uintn_t * logo,uint32_t * logo_size,efi_uintn_t * blt_ptr,efi_uintn_t * blt_size,uint32_t * pixel_height,uint32_t * pixel_width)236 void fsp_convert_bmp_to_gop_blt(efi_uintn_t *logo, uint32_t *logo_size,
237 	efi_uintn_t *blt_ptr, efi_uintn_t *blt_size,
238 	uint32_t *pixel_height, uint32_t *pixel_width)
239 {
240 	uintptr_t logo_ptr;
241 	size_t 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 	logo_ptr = (uintptr_t)bmp_load_logo(&logo_ptr_size);
248 
249 	if (!logo_ptr || logo_ptr_size < sizeof(efi_bmp_image_header)) {
250 		printk(BIOS_ERR, "%s: BMP Image size is too small.\n", __func__);
251 		return;
252 	}
253 
254 	bmp_header = (efi_bmp_image_header *)logo_ptr;
255 	if (!do_bmp_image_authentication(bmp_header) || (bmp_header->Size != logo_ptr_size))
256 		return;
257 
258 	blt_buffer_size = calculate_blt_buffer_size(bmp_header);
259 	if (!blt_buffer_size)
260 		return;
261 
262 	if (!get_color_map_num(bmp_header))
263 		return;
264 
265 	*logo = logo_ptr;
266 	*logo_size = logo_ptr_size;
267 	*blt_size = blt_buffer_size;
268 	*pixel_height = bmp_header->PixelHeight;
269 	*pixel_width = bmp_header->PixelWidth;
270 	*blt_ptr = (uintptr_t)fill_blt_buffer(bmp_header, logo_ptr, blt_buffer_size);
271 }
272