diff options
Diffstat (limited to '0004-bootsplash.patch')
-rw-r--r-- | 0004-bootsplash.patch | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/0004-bootsplash.patch b/0004-bootsplash.patch new file mode 100644 index 000000000000..92d62caa7031 --- /dev/null +++ b/0004-bootsplash.patch @@ -0,0 +1,669 @@ +diff --git a/MAINTAINERS b/MAINTAINERS +index b5633b56391e..5c237445761e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2712,6 +2712,7 @@ S: Maintained + F: drivers/video/fbdev/core/bootsplash*.* + F: drivers/video/fbdev/core/dummycon.c + F: include/linux/bootsplash.h ++F: include/uapi/linux/bootsplash_file.h + + BPF (Safe dynamic programs and tools) + M: Alexei Starovoitov <ast@kernel.org> +diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile +index 66895321928e..6a8d1bab8a01 100644 +--- a/drivers/video/fbdev/core/Makefile ++++ b/drivers/video/fbdev/core/Makefile +@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o + obj-$(CONFIG_FB_DDC) += fb_ddc.o + + obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \ +- dummyblit.o ++ bootsplash_load.o dummyblit.o +diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c +index e449755af268..843c5400fefc 100644 +--- a/drivers/video/fbdev/core/bootsplash.c ++++ b/drivers/video/fbdev/core/bootsplash.c +@@ -32,6 +32,7 @@ + #include <linux/workqueue.h> + + #include "bootsplash_internal.h" ++#include "uapi/linux/bootsplash_file.h" + + + /* +@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info) + */ + void bootsplash_render_full(struct fb_info *info) + { ++ mutex_lock(&splash_state.data_lock); ++ + if (!is_fb_compatible(info)) +- return; ++ goto out; ++ ++ bootsplash_do_render_background(info, splash_state.file); ++ ++ bootsplash_do_render_pictures(info, splash_state.file); + +- bootsplash_do_render_background(info); ++out: ++ mutex_unlock(&splash_state.data_lock); + } + + +@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void) + { + return !oops_in_progress + && !console_blanked ++ && splash_state.file + && bootsplash_is_enabled(); + } + +@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = { + void bootsplash_init(void) + { + int ret; ++ struct splash_file_priv *fp; + + /* Initialized already? */ + if (splash_state.splash_device) +@@ -280,8 +290,26 @@ void bootsplash_init(void) + } + + ++ mutex_init(&splash_state.data_lock); ++ set_bit(0, &splash_state.enabled); ++ + INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); + ++ ++ if (!splash_state.bootfile || !strlen(splash_state.bootfile)) ++ return; ++ ++ fp = bootsplash_load_firmware(&splash_state.splash_device->dev, ++ splash_state.bootfile); ++ ++ if (!fp) ++ goto err; ++ ++ mutex_lock(&splash_state.data_lock); ++ splash_state.splash_fb = NULL; ++ splash_state.file = fp; ++ mutex_unlock(&splash_state.data_lock); ++ + return; + + err_device: +@@ -292,3 +320,7 @@ void bootsplash_init(void) + err: + pr_err("Failed to initialize.\n"); + } ++ ++ ++module_param_named(bootfile, splash_state.bootfile, charp, 0444); ++MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot"); +diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h +index b11da5cb90bf..71e2a27ac0b8 100644 +--- a/drivers/video/fbdev/core/bootsplash_internal.h ++++ b/drivers/video/fbdev/core/bootsplash_internal.h +@@ -15,15 +15,43 @@ + + #include <linux/types.h> + #include <linux/fb.h> ++#include <linux/firmware.h> + #include <linux/kernel.h> + #include <linux/mutex.h> + #include <linux/spinlock.h> + ++#include "uapi/linux/bootsplash_file.h" ++ + + /* + * Runtime types + */ ++struct splash_blob_priv { ++ struct splash_blob_header *blob_header; ++ const void *data; ++}; ++ ++ ++struct splash_pic_priv { ++ const struct splash_pic_header *pic_header; ++ ++ struct splash_blob_priv *blobs; ++ u16 blobs_loaded; ++}; ++ ++ ++struct splash_file_priv { ++ const struct firmware *fw; ++ const struct splash_file_header *header; ++ ++ struct splash_pic_priv *pics; ++}; ++ ++ + struct splash_priv { ++ /* Bootup and runtime state */ ++ char *bootfile; ++ + /* + * Enabled/disabled state, to be used with atomic bit operations. + * Bit 0: 0 = Splash hidden +@@ -43,6 +71,13 @@ struct splash_priv { + struct platform_device *splash_device; + + struct work_struct work_redraw_vc; ++ ++ /* Splash data structures including lock for everything below */ ++ struct mutex data_lock; ++ ++ struct fb_info *splash_fb; ++ ++ struct splash_file_priv *file; + }; + + +@@ -50,6 +85,14 @@ struct splash_priv { + /* + * Rendering functions + */ +-void bootsplash_do_render_background(struct fb_info *info); ++void bootsplash_do_render_background(struct fb_info *info, ++ const struct splash_file_priv *fp); ++void bootsplash_do_render_pictures(struct fb_info *info, ++ const struct splash_file_priv *fp); ++ ++ ++void bootsplash_free_file(struct splash_file_priv *fp); ++struct splash_file_priv *bootsplash_load_firmware(struct device *device, ++ const char *path); + + #endif +diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c +new file mode 100644 +index 000000000000..fd807571ab7d +--- /dev/null ++++ b/drivers/video/fbdev/core/bootsplash_load.c +@@ -0,0 +1,225 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (Loading and freeing functions) ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define pr_fmt(fmt) "bootsplash: " fmt ++ ++ ++#include <linux/bootsplash.h> ++#include <linux/fb.h> ++#include <linux/firmware.h> ++#include <linux/kernel.h> ++#include <linux/mutex.h> ++#include <linux/printk.h> ++#include <linux/types.h> ++#include <linux/vmalloc.h> ++ ++#include "bootsplash_internal.h" ++#include "uapi/linux/bootsplash_file.h" ++ ++ ++ ++ ++/* ++ * Free all vmalloc()'d resources describing a splash file. ++ */ ++void bootsplash_free_file(struct splash_file_priv *fp) ++{ ++ if (!fp) ++ return; ++ ++ if (fp->pics) { ++ unsigned int i; ++ ++ for (i = 0; i < fp->header->num_pics; i++) { ++ struct splash_pic_priv *pp = &fp->pics[i]; ++ ++ if (pp->blobs) ++ vfree(pp->blobs); ++ } ++ ++ vfree(fp->pics); ++ } ++ ++ release_firmware(fp->fw); ++ vfree(fp); ++} ++ ++ ++ ++ ++/* ++ * Load a splash screen from a "firmware" file. ++ * ++ * Parsing, and sanity checks. ++ */ ++#ifdef __BIG_ENDIAN ++ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE ++#else ++ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE ++#endif ++ ++struct splash_file_priv *bootsplash_load_firmware(struct device *device, ++ const char *path) ++{ ++ const struct firmware *fw; ++ struct splash_file_priv *fp; ++ unsigned int i; ++ const u8 *walker; ++ ++ if (request_firmware(&fw, path, device)) ++ return NULL; ++ ++ if (fw->size < sizeof(struct splash_file_header) ++ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) { ++ pr_err("Not a bootsplash file.\n"); ++ ++ release_firmware(fw); ++ return NULL; ++ } ++ ++ fp = vzalloc(sizeof(struct splash_file_priv)); ++ if (!fp) { ++ release_firmware(fw); ++ return NULL; ++ } ++ ++ pr_info("Loading splash file (%li bytes)\n", fw->size); ++ ++ fp->fw = fw; ++ fp->header = (struct splash_file_header *)fw->data; ++ ++ /* Sanity checks */ ++ if (fp->header->version != BOOTSPLASH_VERSION) { ++ pr_err("Loaded v%d file, but we only support version %d\n", ++ fp->header->version, ++ BOOTSPLASH_VERSION); ++ ++ goto err; ++ } ++ ++ if (fw->size < sizeof(struct splash_file_header) ++ + fp->header->num_pics ++ * sizeof(struct splash_pic_header) ++ + fp->header->num_blobs ++ * sizeof(struct splash_blob_header)) { ++ pr_err("File incomplete.\n"); ++ ++ goto err; ++ } ++ ++ /* Read picture headers */ ++ if (fp->header->num_pics) { ++ fp->pics = vzalloc(fp->header->num_pics ++ * sizeof(struct splash_pic_priv)); ++ if (!fp->pics) ++ goto err; ++ } ++ ++ walker = fw->data + sizeof(struct splash_file_header); ++ for (i = 0; i < fp->header->num_pics; i++) { ++ struct splash_pic_priv *pp = &fp->pics[i]; ++ struct splash_pic_header *ph = (void *)walker; ++ ++ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height); ++ ++ if (ph->num_blobs < 1) { ++ pr_err("Picture %u: Zero blobs? Aborting load.\n", i); ++ goto err; ++ } ++ ++ pp->pic_header = ph; ++ pp->blobs = vzalloc(ph->num_blobs ++ * sizeof(struct splash_blob_priv)); ++ if (!pp->blobs) ++ goto err; ++ ++ walker += sizeof(struct splash_pic_header); ++ } ++ ++ /* Read blob headers */ ++ for (i = 0; i < fp->header->num_blobs; i++) { ++ struct splash_blob_header *bh = (void *)walker; ++ struct splash_pic_priv *pp; ++ ++ if (walker + sizeof(struct splash_blob_header) ++ > fw->data + fw->size) ++ goto err; ++ ++ walker += sizeof(struct splash_blob_header); ++ ++ if (walker + bh->length > fw->data + fw->size) ++ goto err; ++ ++ if (bh->picture_id >= fp->header->num_pics) ++ goto nextblob; ++ ++ pp = &fp->pics[bh->picture_id]; ++ ++ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n", ++ i, bh->picture_id, ++ pp->blobs_loaded, pp->pic_header->num_blobs); ++ ++ if (pp->blobs_loaded >= pp->pic_header->num_blobs) ++ goto nextblob; ++ ++ switch (bh->type) { ++ case 0: ++ /* Raw 24-bit packed pixels */ ++ if (bh->length != pp->pic_header->width ++ * pp->pic_header->height * 3) { ++ pr_err("Blob %u, type 1: Length doesn't match picture.\n", ++ i); ++ ++ goto err; ++ } ++ break; ++ default: ++ pr_warn("Blob %u, unknown type %u.\n", i, bh->type); ++ goto nextblob; ++ } ++ ++ pp->blobs[pp->blobs_loaded].blob_header = bh; ++ pp->blobs[pp->blobs_loaded].data = walker; ++ pp->blobs_loaded++; ++ ++nextblob: ++ walker += bh->length; ++ if (bh->length % 16) ++ walker += 16 - (bh->length % 16); ++ } ++ ++ if (walker != fw->data + fw->size) ++ pr_warn("Trailing data in splash file.\n"); ++ ++ /* Walk over pictures and ensure all blob slots are filled */ ++ for (i = 0; i < fp->header->num_pics; i++) { ++ struct splash_pic_priv *pp = &fp->pics[i]; ++ ++ if (pp->blobs_loaded != pp->pic_header->num_blobs) { ++ pr_err("Picture %u doesn't have all blob slots filled.\n", ++ i); ++ ++ goto err; ++ } ++ } ++ ++ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n", ++ fw->size, ++ fp->header->num_pics, ++ fp->header->num_blobs); ++ ++ return fp; ++ ++ ++err: ++ bootsplash_free_file(fp); ++ return NULL; ++} +diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c +index 4d7e0117f653..2ae36949d0e3 100644 +--- a/drivers/video/fbdev/core/bootsplash_render.c ++++ b/drivers/video/fbdev/core/bootsplash_render.c +@@ -19,6 +19,7 @@ + #include <linux/types.h> + + #include "bootsplash_internal.h" ++#include "uapi/linux/bootsplash_file.h" + + + +@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var, + } + + +-void bootsplash_do_render_background(struct fb_info *info) ++/* ++ * Copy from source and blend into the destination picture. ++ * Currently assumes that the source picture is 24bpp. ++ * Currently assumes that the destination is <= 32bpp. ++ */ ++static int splash_convert_to_fb(u8 *dst, ++ const struct fb_var_screeninfo *dst_var, ++ unsigned int dst_stride, ++ unsigned int dst_xoff, ++ unsigned int dst_yoff, ++ const u8 *src, ++ unsigned int src_width, ++ unsigned int src_height) ++{ ++ unsigned int x, y; ++ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */ ++ u32 dst_octpp = dst_var->bits_per_pixel / 8; ++ ++ dst_xoff += dst_var->xoffset; ++ dst_yoff += dst_var->yoffset; ++ ++ /* Copy with stride and pixel size adjustment */ ++ for (y = 0; ++ y < src_height && y + dst_yoff < dst_var->yres_virtual; ++ y++) { ++ const u8 *srcline = src + (y * src_stride); ++ u8 *dstline = dst + ((y + dst_yoff) * dst_stride) ++ + (dst_xoff * dst_octpp); ++ ++ for (x = 0; ++ x < src_width && x + dst_xoff < dst_var->xres_virtual; ++ x++) { ++ u8 red, green, blue; ++ u32 dstpix; ++ ++ /* Read pixel */ ++ red = *srcline++; ++ green = *srcline++; ++ blue = *srcline++; ++ ++ /* Write pixel */ ++ dstpix = pack_pixel(dst_var, red, green, blue); ++ memcpy(dstline, &dstpix, dst_octpp); ++ ++ dstline += dst_octpp; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++void bootsplash_do_render_background(struct fb_info *info, ++ const struct splash_file_priv *fp) + { + unsigned int x, y; + u32 dstpix; + u32 dst_octpp = info->var.bits_per_pixel / 8; + + dstpix = pack_pixel(&info->var, +- 0, +- 0, +- 0); ++ fp->header->bg_red, ++ fp->header->bg_green, ++ fp->header->bg_blue); + + for (y = 0; y < info->var.yres_virtual; y++) { + u8 *dstline = info->screen_buffer + (y * info->fix.line_length); +@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info) + } + } + } ++ ++ ++void bootsplash_do_render_pictures(struct fb_info *info, ++ const struct splash_file_priv *fp) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < fp->header->num_pics; i++) { ++ struct splash_blob_priv *bp; ++ struct splash_pic_priv *pp = &fp->pics[i]; ++ long dst_xoff, dst_yoff; ++ ++ if (pp->blobs_loaded < 1) ++ continue; ++ ++ bp = &pp->blobs[0]; ++ ++ if (!bp || bp->blob_header->type != 0) ++ continue; ++ ++ dst_xoff = (info->var.xres - pp->pic_header->width) / 2; ++ dst_yoff = (info->var.yres - pp->pic_header->height) / 2; ++ ++ if (dst_xoff < 0 ++ || dst_yoff < 0 ++ || dst_xoff + pp->pic_header->width > info->var.xres ++ || dst_yoff + pp->pic_header->height > info->var.yres) { ++ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n" ++ "(this will only be printed once every reboot)\n", ++ i, info->var.xres, info->var.yres); ++ ++ continue; ++ } ++ ++ /* Draw next splash frame */ ++ splash_convert_to_fb(info->screen_buffer, &info->var, ++ info->fix.line_length, dst_xoff, dst_yoff, ++ bp->data, ++ pp->pic_header->width, pp->pic_header->height); ++ } ++} +diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h +new file mode 100644 +index 000000000000..89dc9cca8f0c +--- /dev/null ++++ b/include/uapi/linux/bootsplash_file.h +@@ -0,0 +1,118 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (File format) ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ */ ++ ++#ifndef __BOOTSPLASH_FILE_H ++#define __BOOTSPLASH_FILE_H ++ ++ ++#define BOOTSPLASH_VERSION 55561 ++ ++ ++#include <linux/kernel.h> ++#include <linux/types.h> ++ ++ ++/* ++ * On-disk types ++ * ++ * A splash file consists of: ++ * - One single 'struct splash_file_header' ++ * - An array of 'struct splash_pic_header' ++ * - An array of raw data blocks, each padded to 16 bytes and ++ * preceded by a 'struct splash_blob_header' ++ * ++ * A single-frame splash may look like this: ++ * ++ * +--------------------+ ++ * | | ++ * | splash_file_header | ++ * | -> num_blobs = 1 | ++ * | -> num_pics = 1 | ++ * | | ++ * +--------------------+ ++ * | | ++ * | splash_pic_header | ++ * | | ++ * +--------------------+ ++ * | | ++ * | splash_blob_header | ++ * | -> type = 0 | ++ * | -> picture_id = 0 | ++ * | | ++ * | (raw RGB data) | ++ * | (pad to 16 bytes) | ++ * | | ++ * +--------------------+ ++ * ++ * All multi-byte values are stored on disk in the native format ++ * expected by the system the file will be used on. ++ */ ++#define BOOTSPLASH_MAGIC_BE "Linux bootsplash" ++#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL" ++ ++struct splash_file_header { ++ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */ ++ ++ /* Splash file format version to avoid clashes */ ++ uint16_t version; ++ ++ /* The background color */ ++ uint8_t bg_red; ++ uint8_t bg_green; ++ uint8_t bg_blue; ++ uint8_t bg_reserved; ++ ++ /* ++ * Number of pic/blobs so we can allocate memory for internal ++ * structures ahead of time when reading the file ++ */ ++ uint16_t num_blobs; ++ uint8_t num_pics; ++ ++ uint8_t padding[103]; ++} __attribute__((__packed__)); ++ ++ ++struct splash_pic_header { ++ uint16_t width; ++ uint16_t height; ++ ++ /* ++ * Number of data packages associated with this picture. ++ * Currently, the only use for more than 1 is for animations. ++ */ ++ uint8_t num_blobs; ++ ++ uint8_t padding[27]; ++} __attribute__((__packed__)); ++ ++ ++struct splash_blob_header { ++ /* Length of the data block in bytes. */ ++ uint32_t length; ++ ++ /* ++ * Type of the contents. ++ * 0 - Raw RGB data. ++ */ ++ uint16_t type; ++ ++ /* ++ * Picture this blob is associated with. ++ * Blobs will be added to a picture in the order they are ++ * found in the file. ++ */ ++ uint8_t picture_id; ++ ++ uint8_t padding[9]; ++} __attribute__((__packed__)); ++ ++#endif |