diff options
author | Subrata Banik <subratabanik@google.com> | 2023-08-03 10:11:28 +0000 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2023-08-11 13:18:22 +0000 |
commit | 7bc92f03a669f4721bd690f56703a6976c0ae3b9 (patch) | |
tree | ea0d33a53516d6fa4cee91858b0e1b4beeca14e1 | |
parent | bfe220c4cc9463d9f8bfee5a600d94873d23d949 (diff) |
drivers/intel/fsp2_0: Add API to convert BMP images to GOP BLT buffer
This patch adds an API to convert BMP images into GOP BLT buffers for
Intel FSP-S. This is required to display the OEM splash screen at
pre-boot phase.
Previously, Intel FSP-S had provision to consume the *.BMP file as is.
However, starting with the Alder Lake platform, Intel FSP has dropped
this conversion logic and expects the boot firmware to pass the BLT
buffer directly.
This patch implements the conversion logic in coreboot.
BUG=b:284799726
TEST=Able to build and boot google/rex
Signed-off-by: Subrata Banik <subratabanik@google.com>
Change-Id: I992b45d65374f09498ff0cab497f7091e1e7a350
Reviewed-on: https://review.coreboot.org/c/coreboot/+/76921
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
-rw-r--r-- | src/drivers/intel/fsp2_0/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/intel/fsp2_0/fsp_gop_blt.c | 270 | ||||
-rw-r--r-- | src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h | 14 |
3 files changed, 285 insertions, 0 deletions
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 <bootsplash.h> +#include <console/console.h> +#include <fsp/api.h> +#include <fsp/fsp_gop_blt.h> +#include <lib.h> +#include <stdlib.h> + +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 <efi/efi_datatype.h> +#include <types.h> + +/* 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 */ |