Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/patch/misc/0002-bootsplash.patch
Views: 3959
diff --git a/MAINTAINERS b/MAINTAINERS1index b5633b56391e..5c237445761e 1006442--- a/MAINTAINERS3+++ b/MAINTAINERS4@@ -2712,6 +2712,7 @@ S: Maintained5F: drivers/video/fbdev/core/bootsplash*.*6F: drivers/video/fbdev/core/dummycon.c7F: include/linux/bootsplash.h8+F: include/uapi/linux/bootsplash_file.h910BPF (Safe dynamic programs and tools)11M: Alexei Starovoitov <[email protected]>12diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile13index 66895321928e..6a8d1bab8a01 10064414--- a/drivers/video/fbdev/core/Makefile15+++ b/drivers/video/fbdev/core/Makefile16@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o17obj-$(CONFIG_FB_DDC) += fb_ddc.o1819obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \20- dummyblit.o21+ bootsplash_load.o dummyblit.o22diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c23index e449755af268..843c5400fefc 10064424--- a/drivers/video/fbdev/core/bootsplash.c25+++ b/drivers/video/fbdev/core/bootsplash.c26@@ -32,6 +32,7 @@27#include <linux/workqueue.h>2829#include "bootsplash_internal.h"30+#include "uapi/linux/bootsplash_file.h"313233/*34@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)35*/36void bootsplash_render_full(struct fb_info *info)37{38+ mutex_lock(&splash_state.data_lock);39+40if (!is_fb_compatible(info))41- return;42+ goto out;43+44+ bootsplash_do_render_background(info, splash_state.file);45+46+ bootsplash_do_render_pictures(info, splash_state.file);4748- bootsplash_do_render_background(info);49+out:50+ mutex_unlock(&splash_state.data_lock);51}525354@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)55{56return !oops_in_progress57&& !console_blanked58+ && splash_state.file59&& bootsplash_is_enabled();60}6162@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {63void bootsplash_init(void)64{65int ret;66+ struct splash_file_priv *fp;6768/* Initialized already? */69if (splash_state.splash_device)70@@ -280,8 +290,26 @@ void bootsplash_init(void)71}727374+ mutex_init(&splash_state.data_lock);75+ set_bit(0, &splash_state.enabled);76+77INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);7879+80+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))81+ return;82+83+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,84+ splash_state.bootfile);85+86+ if (!fp)87+ goto err;88+89+ mutex_lock(&splash_state.data_lock);90+ splash_state.splash_fb = NULL;91+ splash_state.file = fp;92+ mutex_unlock(&splash_state.data_lock);93+94return;9596err_device:97@@ -292,3 +320,7 @@ void bootsplash_init(void)98err:99pr_err("Failed to initialize.\n");100}101+102+103+module_param_named(bootfile, splash_state.bootfile, charp, 0444);104+MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");105diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h106index b11da5cb90bf..71e2a27ac0b8 100644107--- a/drivers/video/fbdev/core/bootsplash_internal.h108+++ b/drivers/video/fbdev/core/bootsplash_internal.h109@@ -15,15 +15,43 @@110111#include <linux/types.h>112#include <linux/fb.h>113+#include <linux/firmware.h>114#include <linux/kernel.h>115#include <linux/mutex.h>116#include <linux/spinlock.h>117118+#include "uapi/linux/bootsplash_file.h"119+120121/*122* Runtime types123*/124+struct splash_blob_priv {125+ struct splash_blob_header *blob_header;126+ const void *data;127+};128+129+130+struct splash_pic_priv {131+ const struct splash_pic_header *pic_header;132+133+ struct splash_blob_priv *blobs;134+ u16 blobs_loaded;135+};136+137+138+struct splash_file_priv {139+ const struct firmware *fw;140+ const struct splash_file_header *header;141+142+ struct splash_pic_priv *pics;143+};144+145+146struct splash_priv {147+ /* Bootup and runtime state */148+ char *bootfile;149+150/*151* Enabled/disabled state, to be used with atomic bit operations.152* Bit 0: 0 = Splash hidden153@@ -43,6 +71,13 @@ struct splash_priv {154struct platform_device *splash_device;155156struct work_struct work_redraw_vc;157+158+ /* Splash data structures including lock for everything below */159+ struct mutex data_lock;160+161+ struct fb_info *splash_fb;162+163+ struct splash_file_priv *file;164};165166167@@ -50,6 +85,14 @@ struct splash_priv {168/*169* Rendering functions170*/171-void bootsplash_do_render_background(struct fb_info *info);172+void bootsplash_do_render_background(struct fb_info *info,173+ const struct splash_file_priv *fp);174+void bootsplash_do_render_pictures(struct fb_info *info,175+ const struct splash_file_priv *fp);176+177+178+void bootsplash_free_file(struct splash_file_priv *fp);179+struct splash_file_priv *bootsplash_load_firmware(struct device *device,180+ const char *path);181182#endif183diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c184new file mode 100644185index 000000000000..fd807571ab7d186--- /dev/null187+++ b/drivers/video/fbdev/core/bootsplash_load.c188@@ -0,0 +1,225 @@189+/*190+ * Kernel based bootsplash.191+ *192+ * (Loading and freeing functions)193+ *194+ * Authors:195+ * Max Staudt <[email protected]>196+ *197+ * SPDX-License-Identifier: GPL-2.0198+ */199+200+#define pr_fmt(fmt) "bootsplash: " fmt201+202+203+#include <linux/bootsplash.h>204+#include <linux/fb.h>205+#include <linux/firmware.h>206+#include <linux/kernel.h>207+#include <linux/mutex.h>208+#include <linux/printk.h>209+#include <linux/types.h>210+#include <linux/vmalloc.h>211+212+#include "bootsplash_internal.h"213+#include "uapi/linux/bootsplash_file.h"214+215+216+217+218+/*219+ * Free all vmalloc()'d resources describing a splash file.220+ */221+void bootsplash_free_file(struct splash_file_priv *fp)222+{223+ if (!fp)224+ return;225+226+ if (fp->pics) {227+ unsigned int i;228+229+ for (i = 0; i < fp->header->num_pics; i++) {230+ struct splash_pic_priv *pp = &fp->pics[i];231+232+ if (pp->blobs)233+ vfree(pp->blobs);234+ }235+236+ vfree(fp->pics);237+ }238+239+ release_firmware(fp->fw);240+ vfree(fp);241+}242+243+244+245+246+/*247+ * Load a splash screen from a "firmware" file.248+ *249+ * Parsing, and sanity checks.250+ */251+#ifdef __BIG_ENDIAN252+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE253+#else254+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE255+#endif256+257+struct splash_file_priv *bootsplash_load_firmware(struct device *device,258+ const char *path)259+{260+ const struct firmware *fw;261+ struct splash_file_priv *fp;262+ unsigned int i;263+ const u8 *walker;264+265+ if (request_firmware(&fw, path, device))266+ return NULL;267+268+ if (fw->size < sizeof(struct splash_file_header)269+ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {270+ pr_err("Not a bootsplash file.\n");271+272+ release_firmware(fw);273+ return NULL;274+ }275+276+ fp = vzalloc(sizeof(struct splash_file_priv));277+ if (!fp) {278+ release_firmware(fw);279+ return NULL;280+ }281+282+ pr_info("Loading splash file (%li bytes)\n", fw->size);283+284+ fp->fw = fw;285+ fp->header = (struct splash_file_header *)fw->data;286+287+ /* Sanity checks */288+ if (fp->header->version != BOOTSPLASH_VERSION) {289+ pr_err("Loaded v%d file, but we only support version %d\n",290+ fp->header->version,291+ BOOTSPLASH_VERSION);292+293+ goto err;294+ }295+296+ if (fw->size < sizeof(struct splash_file_header)297+ + fp->header->num_pics298+ * sizeof(struct splash_pic_header)299+ + fp->header->num_blobs300+ * sizeof(struct splash_blob_header)) {301+ pr_err("File incomplete.\n");302+303+ goto err;304+ }305+306+ /* Read picture headers */307+ if (fp->header->num_pics) {308+ fp->pics = vzalloc(fp->header->num_pics309+ * sizeof(struct splash_pic_priv));310+ if (!fp->pics)311+ goto err;312+ }313+314+ walker = fw->data + sizeof(struct splash_file_header);315+ for (i = 0; i < fp->header->num_pics; i++) {316+ struct splash_pic_priv *pp = &fp->pics[i];317+ struct splash_pic_header *ph = (void *)walker;318+319+ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);320+321+ if (ph->num_blobs < 1) {322+ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);323+ goto err;324+ }325+326+ pp->pic_header = ph;327+ pp->blobs = vzalloc(ph->num_blobs328+ * sizeof(struct splash_blob_priv));329+ if (!pp->blobs)330+ goto err;331+332+ walker += sizeof(struct splash_pic_header);333+ }334+335+ /* Read blob headers */336+ for (i = 0; i < fp->header->num_blobs; i++) {337+ struct splash_blob_header *bh = (void *)walker;338+ struct splash_pic_priv *pp;339+340+ if (walker + sizeof(struct splash_blob_header)341+ > fw->data + fw->size)342+ goto err;343+344+ walker += sizeof(struct splash_blob_header);345+346+ if (walker + bh->length > fw->data + fw->size)347+ goto err;348+349+ if (bh->picture_id >= fp->header->num_pics)350+ goto nextblob;351+352+ pp = &fp->pics[bh->picture_id];353+354+ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",355+ i, bh->picture_id,356+ pp->blobs_loaded, pp->pic_header->num_blobs);357+358+ if (pp->blobs_loaded >= pp->pic_header->num_blobs)359+ goto nextblob;360+361+ switch (bh->type) {362+ case 0:363+ /* Raw 24-bit packed pixels */364+ if (bh->length != pp->pic_header->width365+ * pp->pic_header->height * 3) {366+ pr_err("Blob %u, type 1: Length doesn't match picture.\n",367+ i);368+369+ goto err;370+ }371+ break;372+ default:373+ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);374+ goto nextblob;375+ }376+377+ pp->blobs[pp->blobs_loaded].blob_header = bh;378+ pp->blobs[pp->blobs_loaded].data = walker;379+ pp->blobs_loaded++;380+381+nextblob:382+ walker += bh->length;383+ if (bh->length % 16)384+ walker += 16 - (bh->length % 16);385+ }386+387+ if (walker != fw->data + fw->size)388+ pr_warn("Trailing data in splash file.\n");389+390+ /* Walk over pictures and ensure all blob slots are filled */391+ for (i = 0; i < fp->header->num_pics; i++) {392+ struct splash_pic_priv *pp = &fp->pics[i];393+394+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {395+ pr_err("Picture %u doesn't have all blob slots filled.\n",396+ i);397+398+ goto err;399+ }400+ }401+402+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",403+ fw->size,404+ fp->header->num_pics,405+ fp->header->num_blobs);406+407+ return fp;408+409+410+err:411+ bootsplash_free_file(fp);412+ return NULL;413+}414diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c415index 4d7e0117f653..2ae36949d0e3 100644416--- a/drivers/video/fbdev/core/bootsplash_render.c417+++ b/drivers/video/fbdev/core/bootsplash_render.c418@@ -19,6 +19,7 @@419#include <linux/types.h>420421#include "bootsplash_internal.h"422+#include "uapi/linux/bootsplash_file.h"423424425426@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,427}428429430-void bootsplash_do_render_background(struct fb_info *info)431+/*432+ * Copy from source and blend into the destination picture.433+ * Currently assumes that the source picture is 24bpp.434+ * Currently assumes that the destination is <= 32bpp.435+ */436+static int splash_convert_to_fb(u8 *dst,437+ const struct fb_var_screeninfo *dst_var,438+ unsigned int dst_stride,439+ unsigned int dst_xoff,440+ unsigned int dst_yoff,441+ const u8 *src,442+ unsigned int src_width,443+ unsigned int src_height)444+{445+ unsigned int x, y;446+ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */447+ u32 dst_octpp = dst_var->bits_per_pixel / 8;448+449+ dst_xoff += dst_var->xoffset;450+ dst_yoff += dst_var->yoffset;451+452+ /* Copy with stride and pixel size adjustment */453+ for (y = 0;454+ y < src_height && y + dst_yoff < dst_var->yres_virtual;455+ y++) {456+ const u8 *srcline = src + (y * src_stride);457+ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)458+ + (dst_xoff * dst_octpp);459+460+ for (x = 0;461+ x < src_width && x + dst_xoff < dst_var->xres_virtual;462+ x++) {463+ u8 red, green, blue;464+ u32 dstpix;465+466+ /* Read pixel */467+ red = *srcline++;468+ green = *srcline++;469+ blue = *srcline++;470+471+ /* Write pixel */472+ dstpix = pack_pixel(dst_var, red, green, blue);473+ memcpy(dstline, &dstpix, dst_octpp);474+475+ dstline += dst_octpp;476+ }477+ }478+479+ return 0;480+}481+482+483+void bootsplash_do_render_background(struct fb_info *info,484+ const struct splash_file_priv *fp)485{486unsigned int x, y;487u32 dstpix;488u32 dst_octpp = info->var.bits_per_pixel / 8;489490dstpix = pack_pixel(&info->var,491- 0,492- 0,493- 0);494+ fp->header->bg_red,495+ fp->header->bg_green,496+ fp->header->bg_blue);497498for (y = 0; y < info->var.yres_virtual; y++) {499u8 *dstline = info->screen_buffer + (y * info->fix.line_length);500@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)501}502}503}504+505+506+void bootsplash_do_render_pictures(struct fb_info *info,507+ const struct splash_file_priv *fp)508+{509+ unsigned int i;510+511+ for (i = 0; i < fp->header->num_pics; i++) {512+ struct splash_blob_priv *bp;513+ struct splash_pic_priv *pp = &fp->pics[i];514+ long dst_xoff, dst_yoff;515+516+ if (pp->blobs_loaded < 1)517+ continue;518+519+ bp = &pp->blobs[0];520+521+ if (!bp || bp->blob_header->type != 0)522+ continue;523+524+ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;525+ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;526+527+ if (dst_xoff < 0528+ || dst_yoff < 0529+ || dst_xoff + pp->pic_header->width > info->var.xres530+ || dst_yoff + pp->pic_header->height > info->var.yres) {531+ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"532+ "(this will only be printed once every reboot)\n",533+ i, info->var.xres, info->var.yres);534+535+ continue;536+ }537+538+ /* Draw next splash frame */539+ splash_convert_to_fb(info->screen_buffer, &info->var,540+ info->fix.line_length, dst_xoff, dst_yoff,541+ bp->data,542+ pp->pic_header->width, pp->pic_header->height);543+ }544+}545diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h546new file mode 100644547index 000000000000..89dc9cca8f0c548--- /dev/null549+++ b/include/uapi/linux/bootsplash_file.h550@@ -0,0 +1,118 @@551+/*552+ * Kernel based bootsplash.553+ *554+ * (File format)555+ *556+ * Authors:557+ * Max Staudt <[email protected]>558+ *559+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note560+ */561+562+#ifndef __BOOTSPLASH_FILE_H563+#define __BOOTSPLASH_FILE_H564+565+566+#define BOOTSPLASH_VERSION 55561567+568+569+#include <linux/kernel.h>570+#include <linux/types.h>571+572+573+/*574+ * On-disk types575+ *576+ * A splash file consists of:577+ * - One single 'struct splash_file_header'578+ * - An array of 'struct splash_pic_header'579+ * - An array of raw data blocks, each padded to 16 bytes and580+ * preceded by a 'struct splash_blob_header'581+ *582+ * A single-frame splash may look like this:583+ *584+ * +--------------------+585+ * | |586+ * | splash_file_header |587+ * | -> num_blobs = 1 |588+ * | -> num_pics = 1 |589+ * | |590+ * +--------------------+591+ * | |592+ * | splash_pic_header |593+ * | |594+ * +--------------------+595+ * | |596+ * | splash_blob_header |597+ * | -> type = 0 |598+ * | -> picture_id = 0 |599+ * | |600+ * | (raw RGB data) |601+ * | (pad to 16 bytes) |602+ * | |603+ * +--------------------+604+ *605+ * All multi-byte values are stored on disk in the native format606+ * expected by the system the file will be used on.607+ */608+#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"609+#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"610+611+struct splash_file_header {612+ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */613+614+ /* Splash file format version to avoid clashes */615+ uint16_t version;616+617+ /* The background color */618+ uint8_t bg_red;619+ uint8_t bg_green;620+ uint8_t bg_blue;621+ uint8_t bg_reserved;622+623+ /*624+ * Number of pic/blobs so we can allocate memory for internal625+ * structures ahead of time when reading the file626+ */627+ uint16_t num_blobs;628+ uint8_t num_pics;629+630+ uint8_t padding[103];631+} __attribute__((__packed__));632+633+634+struct splash_pic_header {635+ uint16_t width;636+ uint16_t height;637+638+ /*639+ * Number of data packages associated with this picture.640+ * Currently, the only use for more than 1 is for animations.641+ */642+ uint8_t num_blobs;643+644+ uint8_t padding[27];645+} __attribute__((__packed__));646+647+648+struct splash_blob_header {649+ /* Length of the data block in bytes. */650+ uint32_t length;651+652+ /*653+ * Type of the contents.654+ * 0 - Raw RGB data.655+ */656+ uint16_t type;657+658+ /*659+ * Picture this blob is associated with.660+ * Blobs will be added to a picture in the order they are661+ * found in the file.662+ */663+ uint8_t picture_id;664+665+ uint8_t padding[9];666+} __attribute__((__packed__));667+668+#endif669670671