diff --git a/src/drivers/intel/fsp2_0/Makefile.inc b/src/drivers/intel/fsp2_0/Makefile.inc index ae82833fc2..a1855dd71b 100644 --- a/src/drivers/intel/fsp2_0/Makefile.inc +++ b/src/drivers/intel/fsp2_0/Makefile.inc @@ -33,6 +33,7 @@ ramstage-y += util.c ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += save_mrc_data.c ramstage-$(CONFIG_MMA) += mma_core.c ramstage-$(CONFIG_ENABLE_FSP_ERROR_INFO) += fsp_error_info_hob.c +ramstage-$(CONFIG_BMP_LOGO) += fsp_gop_blt.c ifneq ($(CONFIG_NO_FSP_TEMP_RAM_EXIT),y) postcar-$(CONFIG_FSP_CAR) += temp_ram_exit.c diff --git a/src/drivers/intel/fsp2_0/fsp_gop_blt.c b/src/drivers/intel/fsp2_0/fsp_gop_blt.c new file mode 100644 index 0000000000..a5d55c1d85 --- /dev/null +++ b/src/drivers/intel/fsp2_0/fsp_gop_blt.c @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include +#include +#include +#include + +static bool is_bmp_image_valid(efi_bmp_image_header *header) +{ + if (header == NULL) + return false; + + /* Check if the BMP Header Signature is valid */ + if (header->CharB != 'B' || header->CharM != 'M') + return false; + + /* Check if the BMP Image Header Length is valid */ + if (!header->PixelHeight || !header->PixelWidth) + return false; + + if (header->Size < header->ImageOffset) + return false; + + if (header->ImageOffset < sizeof(efi_bmp_image_header)) + return false; + + return true; +} + +static bool is_bmp_image_compressed(efi_bmp_image_header *header) +{ + if (header == NULL) + return false; + + if (header->CompressionType != 0) + return true; + + return false; +} + +static bool is_bitmap_format_supported(efi_bmp_image_header *header) +{ + if (header == NULL) + return false; + + /* + * Check BITMAP format is supported + * BMP_IMAGE_HEADER = BITMAP_FILE_HEADER + BITMAP_INFO_HEADER + */ + if (header->HeaderSize != sizeof(efi_bmp_image_header) - + OFFSET_OF(efi_bmp_image_header, HeaderSize)) + return false; + + return true; +} + +static bool do_bmp_image_authentication(efi_bmp_image_header *header) +{ + if (header == NULL) + return false; + + if (!is_bmp_image_valid(header)) { + printk(BIOS_ERR, "%s: BMP Image Header is invalid.\n", __func__); + return false; + } + + /* + * BMP image compression is unsupported by FSP implementation, + * hence, exit if the BMP image is compressed. + */ + if (is_bmp_image_compressed(header)) { + printk(BIOS_ERR, "%s: BMP Image Compression is unsupported.\n", __func__); + return false; + } + + if (!is_bitmap_format_supported(header)) { + printk(BIOS_ERR, "%s: BmpHeader Header Size (0x%x) is not as expected.\n", + __func__, header->HeaderSize); + return false; + } + + return true; +} + +static uint32_t calculate_blt_buffer_size(efi_bmp_image_header *header) +{ + uint32_t blt_buffer_size; + + if (header == NULL) + return 0; + + /* Calculate the size required for BLT buffer */ + blt_buffer_size = header->PixelWidth * header->PixelHeight * + sizeof(efi_graphics_output_blt_pixel); + if (!blt_buffer_size) + return 0; + + return blt_buffer_size; +} + +static uint32_t get_color_map_num(efi_bmp_image_header *header) +{ + uint32_t col_map_number = 0; + + if (header == NULL) + return 0; + + switch (header->BitPerPixel) { + case 1: + col_map_number = 2; + break; + case 4: + col_map_number = 16; + break; + case 8: + col_map_number = 256; + break; + default: + break; + } + + /* + * At times BMP file may have padding data between its header section and the + * data section. + */ + if (header->ImageOffset - sizeof(efi_bmp_image_header) < + sizeof(efi_bmp_color_map) * col_map_number) + return 0; + + return col_map_number; +} + +/* Fill BMP image into BLT buffer format */ +static void *fill_blt_buffer(efi_bmp_image_header *header, + uint32_t logo_ptr, uint32_t blt_buffer_size) +{ + efi_graphics_output_blt_pixel *gop_blt_buffer; + efi_graphics_output_blt_pixel *gop_blt_ptr; + efi_graphics_output_blt_pixel *gop_blt; + uint8_t *bmp_image; + uint8_t *bmp_image_header; + efi_bmp_color_map *bmp_color_map; + size_t image_index; + + if (header == NULL) + return NULL; + + gop_blt_ptr = malloc(sizeof(blt_buffer_size)); + if (!gop_blt_ptr) + die("%s: out of memory. Consider increasing the `CONFIG_HEAP_SIZE`\n", + __func__); + + bmp_image = ((UINT8 *)logo_ptr) + header->ImageOffset; + bmp_image_header = bmp_image; + gop_blt_buffer = gop_blt_ptr; + bmp_color_map = (efi_bmp_color_map *)(logo_ptr + sizeof(efi_bmp_image_header)); + + for (size_t height = 0; height < header->PixelHeight; height++) { + gop_blt = &gop_blt_buffer[(header->PixelHeight - height - 1) * + header->PixelWidth]; + for (size_t width = 0; width < header->PixelWidth; width++, bmp_image++, + gop_blt++) { + size_t index = 0; + switch (header->BitPerPixel) { + /* Translate 1-bit (2 colors) BMP to 24-bit color */ + case 1: + for (index = 0; index < 8 && width < header->PixelWidth; index++) { + gop_blt->Red = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Red; + gop_blt->Green = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Green; + gop_blt->Blue = bmp_color_map[((*bmp_image) >> (7 - index)) & 0x1].Blue; + gop_blt++; + width++; + } + gop_blt--; + width--; + break; + + /* Translate 4-bit (16 colors) BMP Palette to 24-bit color */ + case 4: + index = (*bmp_image) >> 4; + gop_blt->Red = bmp_color_map[index].Red; + gop_blt->Green = bmp_color_map[index].Green; + gop_blt->Blue = bmp_color_map[index].Blue; + if (width < (header->PixelWidth - 1)) { + gop_blt++; + width++; + index = (*bmp_image) & 0x0f; + gop_blt->Red = bmp_color_map[index].Red; + gop_blt->Green = bmp_color_map[index].Green; + gop_blt->Blue = bmp_color_map[index].Blue; + } + break; + + /* Translate 8-bit (256 colors) BMP Palette to 24-bit color */ + case 8: + gop_blt->Red = bmp_color_map[*bmp_image].Red; + gop_blt->Green = bmp_color_map[*bmp_image].Green; + gop_blt->Blue = bmp_color_map[*bmp_image].Blue; + break; + + /* For 24-bit BMP */ + case 24: + gop_blt->Blue = *bmp_image++; + gop_blt->Green = *bmp_image++; + gop_blt->Red = *bmp_image; + break; + + /* Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel */ + case 32: + gop_blt->Blue = *bmp_image++; + gop_blt->Green = *bmp_image++; + gop_blt->Red = *bmp_image++; + break; + + /* Other bit format of BMP is not supported. */ + default: + free(gop_blt_ptr); + gop_blt_ptr = NULL; + + printk(BIOS_ERR, "%s, BMP Bit format not supported. 0x%X\n", __func__, + header->BitPerPixel); + return NULL; + } + } + image_index = (uintptr_t)bmp_image - (uintptr_t)bmp_image_header; + /* Each row in BMP Image should be 4-byte align */ + if ((image_index % 4) != 0) + bmp_image = bmp_image + (4 - (image_index % 4)); + } + + return gop_blt_ptr; +} + +/* Convert a *.BMP graphics image to a GOP blt buffer */ +void fsp_convert_bmp_to_gop_blt(uint32_t *logo, uint32_t *logo_size, + uint32_t *blt_ptr, uint32_t *blt_size, + uint32_t *pixel_height, uint32_t *pixel_width) +{ + uint32_t logo_ptr, logo_ptr_size, blt_buffer_size; + efi_bmp_image_header *bmp_header; + + if (!logo || !logo_size || !blt_ptr || !blt_size || !pixel_height || !pixel_width) + return; + + bmp_load_logo(&logo_ptr, &logo_ptr_size); + if (!logo_ptr || logo_ptr_size < sizeof(efi_bmp_image_header)) { + printk(BIOS_ERR, "%s: BMP Image size is too small.\n", __func__); + return; + } + + bmp_header = (efi_bmp_image_header *)logo_ptr; + if (!do_bmp_image_authentication(bmp_header) || (bmp_header->Size != logo_ptr_size)) + return; + + blt_buffer_size = calculate_blt_buffer_size(bmp_header); + if (!blt_buffer_size) + return; + + if (!get_color_map_num(bmp_header)) + return; + + *logo = logo_ptr; + *logo_size = logo_ptr_size; + *blt_size = blt_buffer_size; + *pixel_height = bmp_header->PixelHeight; + *pixel_width = bmp_header->PixelWidth; + *blt_ptr = (uint32_t)fill_blt_buffer(bmp_header, logo_ptr, blt_buffer_size); +} diff --git a/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h b/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h new file mode 100644 index 0000000000..7ffb54c3b3 --- /dev/null +++ b/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef FSP_GOP_BLT_H +#define FSP_GOP_BLT_H + +#include +#include + +/* Convert a *.BMP graphics image to a GOP blt buffer */ +void fsp_convert_bmp_to_gop_blt(uint32_t *logo, uint32_t *logo_size, + uint32_t *blt_ptr, uint32_t *blt_size, + uint32_t *pixel_height, uint32_t *pixel_width); + +#endif /* FSP_GOP_BLT_H */