diff options
author | charveey | 2019-09-07 00:12:07 -0400 |
---|---|---|
committer | charveey | 2019-09-07 00:12:07 -0400 |
commit | a10bc0064f2a2af38bb346929e5b3410f2c67182 (patch) | |
tree | 8a9dea3020c71f666d84900738c4766c6ec54595 | |
parent | ca6e5711064e89f07ab10d5866542ca1d4841c2a (diff) | |
download | aur-a10bc0064f2a2af38bb346929e5b3410f2c67182.tar.gz |
updated to 5.2.11 & fixed build checksums
-rw-r--r-- | .SRCINFO | 12 | ||||
-rw-r--r-- | 0003-bootsplash.patch | 746 | ||||
-rw-r--r-- | 0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch | 53 | ||||
-rw-r--r-- | 0004-bootsplash.patch | 669 | ||||
-rw-r--r-- | 0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch | 328 | ||||
-rw-r--r-- | 0005-bootsplash.patch | 66 | ||||
-rw-r--r-- | 0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch | 27 | ||||
-rw-r--r-- | 0006-bootsplash.patch | 923 | ||||
-rw-r--r-- | 0007-bootsplash.patch | 838 | ||||
-rw-r--r-- | 0008-bootsplash.patch | 128 | ||||
-rw-r--r-- | 0009-bootsplash.patch | 245 | ||||
-rw-r--r-- | 0010-bootsplash.patch | 342 | ||||
-rw-r--r-- | 0011-bootsplash.patch | 99 | ||||
-rw-r--r-- | 0012-bootsplash.patch | 363 | ||||
-rw-r--r-- | 0013-bootsplash.patch | 146 | ||||
-rw-r--r-- | 0014-bootsplash.patch | 530 | ||||
-rw-r--r-- | 0015-bootsplash.patch | 407 | ||||
-rw-r--r-- | 0016-bootsplash.patch | 129 | ||||
-rw-r--r-- | 0017-bootsplash.patch | 511 | ||||
-rw-r--r-- | 0018-bootsplash.patch | 102 | ||||
-rw-r--r-- | PKGBUILD | 12 |
21 files changed, 3130 insertions, 3546 deletions
@@ -18,8 +18,9 @@ pkgbase = linux-bootsplash source = enable_additional_cpu_optimizations-20190714.tar.gz::https://github.com/graysky2/kernel_gcc_patch/archive/20190714.tar.gz source = 0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch source = 0002-ZEN-Add-CONFIG-for-unprivileged_userns_clone.patch - source = 0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch - source = 0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch + source = 0003-bootsplash.patch + source = 0004-bootsplash.patch + source = 0005-bootsplash.patch source = 0006-bootsplash.patch source = 0007-bootsplash.patch source = 0008-bootsplash.patch @@ -30,13 +31,10 @@ pkgbase = linux-bootsplash source = 0013-bootsplash.patch source = 0014-bootsplash.patch source = 0015-bootsplash.patch - source = 0016-bootsplash.patch - source = 0017-bootsplash.patch - source = 0018-bootsplash.patch source = ajax-loader.gif validpgpkeys = ABAF11C65A2970B130ABE3C479BE3E4300411886 validpgpkeys = 647F28654894E3BD457199BE38DBBDC86092693E - sha256sums = b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6 + sha256sums = 0c2a831f993dc8a8a8e1ca4186b467de72ff173c6f5855e2aab70f6f7fb033f9 sha256sums = SKIP sha256sums = 1c4d5500a3b4995035c2e940fc0ad2a2dae7be047c8eb20c097444e348258f87 sha256sums = ae2e95db94ef7176207c690224169594d49445e04249d2499e9d2fbc117a0b21 @@ -44,8 +42,6 @@ pkgbase = linux-bootsplash sha256sums = ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65 sha256sums = f1abc13a8d859fbf6350040e45d7f04ad551a6d39f113ba96fbbd820118c0e36 sha256sums = 91fafa76bf9cb32159ac7f22191b3589278b91e65bc4505cf2fc6013b8037bf3 - sha256sums = 63e4378e69e2f23ed87af32a4951477a6d82d4ac0de2295db46502c8120da9d9 - sha256sums = fc96300831506965383ef30bc46b72735dc45bb97dea2ccb8b9450c005d2f020 sha256sums = ef926edbd866d95464eb86f7565de572eb97ecfa0369d3b2e078016a0e71a871 sha256sums = a504f6cf84094e08eaa3cc5b28440261797bf4f06f04993ee46a20628ff2b53c sha256sums = e096b127a5208f56d368d2cb938933454d7200d70c86b763aa22c38e0ddb8717 diff --git a/0003-bootsplash.patch b/0003-bootsplash.patch new file mode 100644 index 000000000000..924f23f33ce9 --- /dev/null +++ b/0003-bootsplash.patch @@ -0,0 +1,746 @@ +diff --git a/MAINTAINERS b/MAINTAINERS +index a74227ad082e..b5633b56391e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2705,6 +2705,14 @@ S: Supported + F: drivers/net/bonding/ + F: include/uapi/linux/if_bonding.h + ++BOOTSPLASH ++M: Max Staudt <mstaudt@suse.de> ++L: linux-fbdev@vger.kernel.org ++S: Maintained ++F: drivers/video/fbdev/core/bootsplash*.* ++F: drivers/video/fbdev/core/dummycon.c ++F: include/linux/bootsplash.h ++ + BPF (Safe dynamic programs and tools) + M: Alexei Starovoitov <ast@kernel.org> + M: Daniel Borkmann <daniel@iogearbox.net> +diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig +index 7f1f1fbcef9e..f3ff976266fe 100644 +--- a/drivers/video/console/Kconfig ++++ b/drivers/video/console/Kconfig +@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION + such that other users of the framebuffer will remain normally + oriented. + ++config BOOTSPLASH ++ bool "Bootup splash screen" ++ depends on FRAMEBUFFER_CONSOLE ++ ---help--- ++ This option enables the Linux bootsplash screen. ++ ++ The bootsplash is a full-screen logo or animation indicating a ++ booting system. It replaces the classic scrolling text with a ++ graphical alternative, similar to other systems. ++ ++ Since this is technically implemented as a hook on top of fbcon, ++ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a ++ framebuffer driver is active. Thus, to get a text-free boot, ++ the system needs to boot with vesafb, efifb, or similar. ++ ++ Once built into the kernel, the bootsplash needs to be enabled ++ with bootsplash.enabled=1 and a splash file needs to be supplied. ++ ++ Further documentation can be found in: ++ Documentation/fb/bootsplash.txt ++ ++ If unsure, say N. ++ This is typically used by distributors and system integrators. ++ + config STI_CONSOLE + bool "STI text console" + depends on PARISC +diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile +index 73493bbd7a15..66895321928e 100644 +--- a/drivers/video/fbdev/core/Makefile ++++ b/drivers/video/fbdev/core/Makefile +@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o + obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o + obj-$(CONFIG_FB_SVGALIB) += svgalib.o + obj-$(CONFIG_FB_DDC) += fb_ddc.o ++ ++obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \ ++ dummyblit.o +diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c +new file mode 100644 +index 000000000000..e449755af268 +--- /dev/null ++++ b/drivers/video/fbdev/core/bootsplash.c +@@ -0,0 +1,294 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (Main file: Glue code, workers, timer, PM, kernel and userland API) ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define pr_fmt(fmt) "bootsplash: " fmt ++ ++ ++#include <linux/atomic.h> ++#include <linux/bootsplash.h> ++#include <linux/console.h> ++#include <linux/device.h> /* dev_warn() */ ++#include <linux/fb.h> ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/jiffies.h> ++#include <linux/module.h> ++#include <linux/mutex.h> ++#include <linux/platform_device.h> ++#include <linux/printk.h> ++#include <linux/selection.h> /* console_blanked */ ++#include <linux/stringify.h> ++#include <linux/types.h> ++#include <linux/vmalloc.h> ++#include <linux/vt_kern.h> ++#include <linux/workqueue.h> ++ ++#include "bootsplash_internal.h" ++ ++ ++/* ++ * We only have one splash screen, so let's keep a single ++ * instance of the internal state. ++ */ ++static struct splash_priv splash_state; ++ ++ ++static void splash_callback_redraw_vc(struct work_struct *ignored) ++{ ++ if (console_blanked) ++ return; ++ ++ console_lock(); ++ if (vc_cons[fg_console].d) ++ update_screen(vc_cons[fg_console].d); ++ console_unlock(); ++} ++ ++ ++static bool is_fb_compatible(const struct fb_info *info) ++{ ++ if (!(info->flags & FBINFO_BE_MATH) ++ != !fb_be_math((struct fb_info *)info)) { ++ dev_warn(info->device, ++ "Can't draw on foreign endianness framebuffer.\n"); ++ ++ return false; ++ } ++ ++ if (info->flags & FBINFO_MISC_TILEBLITTING) { ++ dev_warn(info->device, ++ "Can't draw splash on tiling framebuffer.\n"); ++ ++ return false; ++ } ++ ++ if (info->fix.type != FB_TYPE_PACKED_PIXELS ++ || (info->fix.visual != FB_VISUAL_TRUECOLOR ++ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) { ++ dev_warn(info->device, ++ "Can't draw splash on non-packed or non-truecolor framebuffer.\n"); ++ ++ dev_warn(info->device, ++ " type: %u visual: %u\n", ++ info->fix.type, info->fix.visual); ++ ++ return false; ++ } ++ ++ if (info->var.bits_per_pixel != 16 ++ && info->var.bits_per_pixel != 24 ++ && info->var.bits_per_pixel != 32) { ++ dev_warn(info->device, ++ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n", ++ info->var.bits_per_pixel); ++ ++ return false; ++ } ++ ++ return true; ++} ++ ++ ++/* ++ * Called by fbcon_switch() when an instance is activated or refreshed. ++ */ ++void bootsplash_render_full(struct fb_info *info) ++{ ++ if (!is_fb_compatible(info)) ++ return; ++ ++ bootsplash_do_render_background(info); ++} ++ ++ ++/* ++ * External status enquiry and on/off switch ++ */ ++bool bootsplash_would_render_now(void) ++{ ++ return !oops_in_progress ++ && !console_blanked ++ && bootsplash_is_enabled(); ++} ++ ++bool bootsplash_is_enabled(void) ++{ ++ bool was_enabled; ++ ++ /* Make sure we have the newest state */ ++ smp_rmb(); ++ ++ was_enabled = test_bit(0, &splash_state.enabled); ++ ++ return was_enabled; ++} ++ ++void bootsplash_disable(void) ++{ ++ int was_enabled; ++ ++ was_enabled = test_and_clear_bit(0, &splash_state.enabled); ++ ++ if (was_enabled) { ++ if (oops_in_progress) { ++ /* Redraw screen now so we can see a panic */ ++ if (vc_cons[fg_console].d) ++ update_screen(vc_cons[fg_console].d); ++ } else { ++ /* No urgency, redraw at next opportunity */ ++ schedule_work(&splash_state.work_redraw_vc); ++ } ++ } ++} ++ ++void bootsplash_enable(void) ++{ ++ bool was_enabled; ++ ++ if (oops_in_progress) ++ return; ++ ++ was_enabled = test_and_set_bit(0, &splash_state.enabled); ++ ++ if (!was_enabled) ++ schedule_work(&splash_state.work_redraw_vc); ++} ++ ++ ++/* ++ * Userland API via platform device in sysfs ++ */ ++static ssize_t splash_show_enabled(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%d\n", bootsplash_is_enabled()); ++} ++ ++static ssize_t splash_store_enabled(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ bool enable; ++ int err; ++ ++ if (!buf || !count) ++ return -EFAULT; ++ ++ err = kstrtobool(buf, &enable); ++ if (err) ++ return err; ++ ++ if (enable) ++ bootsplash_enable(); ++ else ++ bootsplash_disable(); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled); ++ ++ ++static struct attribute *splash_dev_attrs[] = { ++ &dev_attr_enabled.attr, ++ NULL ++}; ++ ++ATTRIBUTE_GROUPS(splash_dev); ++ ++ ++ ++ ++/* ++ * Power management fixup via platform device ++ * ++ * When the system is woken from sleep or restored after hibernating, we ++ * cannot expect the screen contents to still be present in video RAM. ++ * Thus, we have to redraw the splash if we're currently active. ++ */ ++static int splash_resume(struct device *device) ++{ ++ if (bootsplash_would_render_now()) ++ schedule_work(&splash_state.work_redraw_vc); ++ ++ return 0; ++} ++ ++static int splash_suspend(struct device *device) ++{ ++ cancel_work_sync(&splash_state.work_redraw_vc); ++ ++ return 0; ++} ++ ++ ++static const struct dev_pm_ops splash_pm_ops = { ++ .thaw = splash_resume, ++ .restore = splash_resume, ++ .resume = splash_resume, ++ .suspend = splash_suspend, ++ .freeze = splash_suspend, ++}; ++ ++static struct platform_driver splash_driver = { ++ .driver = { ++ .name = "bootsplash", ++ .pm = &splash_pm_ops, ++ }, ++}; ++ ++ ++/* ++ * Main init ++ */ ++void bootsplash_init(void) ++{ ++ int ret; ++ ++ /* Initialized already? */ ++ if (splash_state.splash_device) ++ return; ++ ++ ++ /* Register platform device to export user API */ ++ ret = platform_driver_register(&splash_driver); ++ if (ret) { ++ pr_err("platform_driver_register() failed: %d\n", ret); ++ goto err; ++ } ++ ++ splash_state.splash_device ++ = platform_device_alloc("bootsplash", 0); ++ ++ if (!splash_state.splash_device) ++ goto err_driver; ++ ++ splash_state.splash_device->dev.groups = splash_dev_groups; ++ ++ ret = platform_device_add(splash_state.splash_device); ++ if (ret) { ++ pr_err("platform_device_add() failed: %d\n", ret); ++ goto err_device; ++ } ++ ++ ++ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); ++ ++ return; ++ ++err_device: ++ platform_device_put(splash_state.splash_device); ++ splash_state.splash_device = NULL; ++err_driver: ++ platform_driver_unregister(&splash_driver); ++err: ++ pr_err("Failed to initialize.\n"); ++} +diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h +new file mode 100644 +index 000000000000..b11da5cb90bf +--- /dev/null ++++ b/drivers/video/fbdev/core/bootsplash_internal.h +@@ -0,0 +1,55 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (Internal data structures used at runtime) ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#ifndef __BOOTSPLASH_INTERNAL_H ++#define __BOOTSPLASH_INTERNAL_H ++ ++ ++#include <linux/types.h> ++#include <linux/fb.h> ++#include <linux/kernel.h> ++#include <linux/mutex.h> ++#include <linux/spinlock.h> ++ ++ ++/* ++ * Runtime types ++ */ ++struct splash_priv { ++ /* ++ * Enabled/disabled state, to be used with atomic bit operations. ++ * Bit 0: 0 = Splash hidden ++ * 1 = Splash shown ++ * ++ * Note: fbcon.c uses this twice, by calling ++ * bootsplash_would_render_now() in set_blitting_type() and ++ * in fbcon_switch(). ++ * This is racy, but eventually consistent: Turning the ++ * splash on/off will cause a redraw, which calls ++ * fbcon_switch(), which calls set_blitting_type(). ++ * So the last on/off toggle will make things consistent. ++ */ ++ unsigned long enabled; ++ ++ /* Our gateway to userland via sysfs */ ++ struct platform_device *splash_device; ++ ++ struct work_struct work_redraw_vc; ++}; ++ ++ ++ ++/* ++ * Rendering functions ++ */ ++void bootsplash_do_render_background(struct fb_info *info); ++ ++#endif +diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c +new file mode 100644 +index 000000000000..4d7e0117f653 +--- /dev/null ++++ b/drivers/video/fbdev/core/bootsplash_render.c +@@ -0,0 +1,93 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (Rendering 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/kernel.h> ++#include <linux/printk.h> ++#include <linux/types.h> ++ ++#include "bootsplash_internal.h" ++ ++ ++ ++ ++/* ++ * Rendering: Internal drawing routines ++ */ ++ ++ ++/* ++ * Pack pixel into target format and do Big/Little Endian handling. ++ * This would be a good place to handle endianness conversion if necessary. ++ */ ++static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var, ++ u8 red, u8 green, u8 blue) ++{ ++ u32 dstpix; ++ ++ /* Quantize pixel */ ++ red = red >> (8 - dst_var->red.length); ++ green = green >> (8 - dst_var->green.length); ++ blue = blue >> (8 - dst_var->blue.length); ++ ++ /* Pack pixel */ ++ dstpix = red << (dst_var->red.offset) ++ | green << (dst_var->green.offset) ++ | blue << (dst_var->blue.offset); ++ ++ /* ++ * Move packed pixel to the beginning of the memory cell, ++ * so we can memcpy() it out easily ++ */ ++#ifdef __BIG_ENDIAN ++ switch (dst_var->bits_per_pixel) { ++ case 16: ++ dstpix <<= 16; ++ break; ++ case 24: ++ dstpix <<= 8; ++ break; ++ case 32: ++ break; ++ } ++#else ++ /* This is intrinsically unnecessary on Little Endian */ ++#endif ++ ++ return dstpix; ++} ++ ++ ++void bootsplash_do_render_background(struct fb_info *info) ++{ ++ unsigned int x, y; ++ u32 dstpix; ++ u32 dst_octpp = info->var.bits_per_pixel / 8; ++ ++ dstpix = pack_pixel(&info->var, ++ 0, ++ 0, ++ 0); ++ ++ for (y = 0; y < info->var.yres_virtual; y++) { ++ u8 *dstline = info->screen_buffer + (y * info->fix.line_length); ++ ++ for (x = 0; x < info->var.xres_virtual; x++) { ++ memcpy(dstline, &dstpix, dst_octpp); ++ ++ dstline += dst_octpp; ++ } ++ } ++} +diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c +new file mode 100644 +index 000000000000..8c22ff92ce24 +--- /dev/null ++++ b/drivers/video/fbdev/core/dummyblit.c +@@ -0,0 +1,89 @@ ++/* ++ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * These functions are used in place of blitblit/tileblit to suppress ++ * fbcon's text output while a splash is shown. ++ * ++ * Only suppressing actual rendering keeps the text buffer in the VC layer ++ * intact and makes it easy to switch back from the bootsplash to a full ++ * text console with a simple redraw (with the original functions in place). ++ * ++ * Based on linux/drivers/video/fbdev/core/bitblit.c ++ * and linux/drivers/video/fbdev/core/tileblit.c ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#include <linux/module.h> ++#include <linux/fb.h> ++#include <linux/vt_kern.h> ++#include <linux/console.h> ++#include <asm/types.h> ++#include "fbcon.h" ++ ++static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int dy, int dx, int height, int width) ++{ ++ ; ++} ++ ++static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int height, int width) ++{ ++ ; ++} ++ ++static void dummy_putcs(struct vc_data *vc, struct fb_info *info, ++ const unsigned short *s, int count, int yy, int xx, ++ int fg, int bg) ++{ ++ ; ++} ++ ++static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info, ++ int color, int bottom_only) ++{ ++ ; ++} ++ ++static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) ++{ ++ ; ++} ++ ++static int dummy_update_start(struct fb_info *info) ++{ ++ /* ++ * Copied from bitblit.c and tileblit.c ++ * ++ * As of Linux 4.12, nobody seems to care about our return value. ++ */ ++ struct fbcon_ops *ops = info->fbcon_par; ++ int err; ++ ++ err = fb_pan_display(info, &ops->var); ++ ops->var.xoffset = info->var.xoffset; ++ ops->var.yoffset = info->var.yoffset; ++ ops->var.vmode = info->var.vmode; ++ return err; ++} ++ ++void fbcon_set_dummyops(struct fbcon_ops *ops) ++{ ++ ops->bmove = dummy_bmove; ++ ops->clear = dummy_clear; ++ ops->putcs = dummy_putcs; ++ ops->clear_margins = dummy_clear_margins; ++ ops->cursor = dummy_cursor; ++ ops->update_start = dummy_update_start; ++ ops->rotate_font = NULL; ++} ++EXPORT_SYMBOL_GPL(fbcon_set_dummyops); ++ ++MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>"); ++MODULE_DESCRIPTION("Dummy Blitting Operation"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 04612f938bab..9a39a6fcfe98 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -80,6 +80,7 @@ + #include <asm/irq.h> + + #include "fbcon.h" ++#include <linux/bootsplash.h> + + #ifdef FBCONDEBUG + # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) +@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo) + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + ++ bootsplash_init(); ++ + err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + +@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + else { + fbcon_set_rotation(info); + fbcon_set_bitops(ops); ++ ++ if (bootsplash_would_render_now()) ++ fbcon_set_dummyops(ops); + } + } + +@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) + ops->p = &fb_display[vc->vc_num]; + fbcon_set_rotation(info); + fbcon_set_bitops(ops); ++ ++ /* ++ * Note: ++ * This is *eventually correct*. ++ * Setting the fbcon operations and drawing the splash happen at ++ * different points in time. If the splash is enabled/disabled ++ * in between, then bootsplash_{en,dis}able will schedule a ++ * redraw, which will again render the splash (or not) and set ++ * the correct fbcon ops. ++ * The last run will then be the right one. ++ */ ++ if (bootsplash_would_render_now()) ++ fbcon_set_dummyops(ops); + } + + static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) +@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc) + info = registered_fb[con2fb_map[vc->vc_num]]; + ops = info->fbcon_par; + ++ if (bootsplash_would_render_now()) ++ bootsplash_render_full(info); ++ + if (softback_top) { + if (softback_lines) + fbcon_set_origin(vc); +diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h +index 18f3ac144237..45f94347fe5e 100644 +--- a/drivers/video/fbdev/core/fbcon.h ++++ b/drivers/video/fbdev/core/fbcon.h +@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc, + #define SCROLL_REDRAW 0x004 + #define SCROLL_PAN_REDRAW 0x005 + ++#ifdef CONFIG_BOOTSPLASH ++extern void fbcon_set_dummyops(struct fbcon_ops *ops); ++#else /* CONFIG_BOOTSPLASH */ ++#define fbcon_set_dummyops(x) ++#endif /* CONFIG_BOOTSPLASH */ + #ifdef CONFIG_FB_TILEBLITTING + extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); + #endif +diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h +new file mode 100644 +index 000000000000..c6dd0b43180d +--- /dev/null ++++ b/include/linux/bootsplash.h +@@ -0,0 +1,43 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#ifndef __LINUX_BOOTSPLASH_H ++#define __LINUX_BOOTSPLASH_H ++ ++#include <linux/fb.h> ++ ++ ++#ifdef CONFIG_BOOTSPLASH ++ ++extern void bootsplash_render_full(struct fb_info *info); ++ ++extern bool bootsplash_would_render_now(void); ++ ++extern bool bootsplash_is_enabled(void); ++extern void bootsplash_disable(void); ++extern void bootsplash_enable(void); ++ ++extern void bootsplash_init(void); ++ ++#else /* CONFIG_BOOTSPLASH */ ++ ++#define bootsplash_render_full(x) ++ ++#define bootsplash_would_render_now() (false) ++ ++#define bootsplash_is_enabled() (false) ++#define bootsplash_disable() ++#define bootsplash_enable() ++ ++#define bootsplash_init() ++ ++#endif /* CONFIG_BOOTSPLASH */ ++ ++ ++#endif diff --git a/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch b/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch deleted file mode 100644 index 59d743deccaa..000000000000 --- a/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f6f6b798c7330d7851fee4bbe835c3954886fc3f Mon Sep 17 00:00:00 2001 -From: Johannes Berg <johannes.berg@intel.com> -Date: Wed, 3 Jul 2019 11:10:49 +0300 -Subject: [PATCH 3/4] iwlwifi: mvm: disable TX-AMSDU on older NICs - -On older NICs, we occasionally see issues with A-MSDU support, -where the commands in the FIFO get confused and then we see an -assert EDC because the next command in the FIFO isn't TX. - -We've tried to isolate this issue and understand where it comes -from, but haven't found any errors in building the A-MSDU in -software. - -At least for now, disable A-MSDU support on older hardware so -that users can use it again without fearing the assert. - -This fixes https://bugzilla.kernel.org/show_bug.cgi?id=203315. - -Signed-off-by: Johannes Berg <johannes.berg@intel.com> -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> -Acked-by: Kalle Valo <kvalo@codeaurora.org> ---- - drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c -index fdbabca0280e..3a076e5e319f 100644 ---- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c -+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c -@@ -468,7 +468,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) - ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); - ieee80211_hw_set(hw, BUFF_MMPDU_TXQ); - ieee80211_hw_set(hw, STA_MMPDU_TXQ); -- ieee80211_hw_set(hw, TX_AMSDU); -+ /* -+ * On older devices, enabling TX A-MSDU occasionally leads to -+ * something getting messed up, the command read from the FIFO -+ * gets out of sync and isn't a TX command, so that we have an -+ * assert EDC. -+ * -+ * It's not clear where the bug is, but since we didn't used to -+ * support A-MSDU until moving the mac80211 iTXQs, just leave it -+ * for older devices. We also don't see this issue on any newer -+ * devices. -+ */ -+ if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_9000) -+ ieee80211_hw_set(hw, TX_AMSDU); - ieee80211_hw_set(hw, TX_FRAG_LIST); - - if (iwl_mvm_has_tlc_offload(mvm)) { --- -2.22.0 - 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 diff --git a/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch b/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch deleted file mode 100644 index 67a9c762ccc1..000000000000 --- a/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch +++ /dev/null @@ -1,328 +0,0 @@ -From e7cae1276332a8d1a94e1e0e272c8b9209bdd83f Mon Sep 17 00:00:00 2001 -From: Haim Dreyfuss <haim.dreyfuss@intel.com> -Date: Wed, 27 Feb 2019 16:43:45 +0200 -Subject: [PATCH 4/6] iwlwifi: Add support for SAR South Korea limitation - -South Korea is adding a more strict SAR limit called "Limb SAR". -Currently, WGDS SAR offset group 3 is not used (not mapped to any country). -In order to be able to comply with South Korea new restriction: -- OEM will use WGDS SAR offset group 3 to South Korea limitation. -- OEM will change WGDS revision to 1 (currently latest revision is 0) - to notify that Korea Limb SAR applied. -- Driver will read the WGDS table and pass the values to FW (as usual) -- Driver will pass to FW an indication that Korea Limb SAR is applied - in case table revision is 1. - -Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com> -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> ---- - drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 28 ++++++---- - drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 +- - .../net/wireless/intel/iwlwifi/fw/api/power.h | 12 ++++ - drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 + - drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 55 ++++++++++++++----- - drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + - 6 files changed, 76 insertions(+), 28 deletions(-) - -diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c -index 405038ce98d6..7573af2d88ce 100644 ---- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c -+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c -@@ -97,7 +97,7 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_object); - - union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, - union acpi_object *data, -- int data_size) -+ int data_size, int *tbl_rev) - { - int i; - union acpi_object *wifi_pkg; -@@ -113,16 +113,19 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, - /* - * We need at least two packages, one for the revision and one - * for the data itself. Also check that the revision is valid -- * (i.e. it is an integer set to 0). -+ * (i.e. it is an integer smaller than 2, as we currently support only -+ * 2 revisions). - */ - if (data->type != ACPI_TYPE_PACKAGE || - data->package.count < 2 || - data->package.elements[0].type != ACPI_TYPE_INTEGER || -- data->package.elements[0].integer.value != 0) { -+ data->package.elements[0].integer.value > 1) { - IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n"); - return ERR_PTR(-EINVAL); - } - -+ *tbl_rev = data->package.elements[0].integer.value; -+ - /* loop through all the packages to find the one for WiFi */ - for (i = 1; i < data->package.count; i++) { - union acpi_object *domain; -@@ -151,14 +154,15 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc) - { - union acpi_object *wifi_pkg, *data; - u32 mcc_val; -- int ret; -+ int ret, tbl_rev; - - data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - -- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg)) { -+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, -+ &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } -@@ -185,6 +189,7 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev) - { - union acpi_object *data, *wifi_pkg; - u64 dflt_pwr_limit; -+ int tbl_rev; - - data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); - if (IS_ERR(data)) { -@@ -193,8 +198,8 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev) - } - - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, -- ACPI_SPLC_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg) || -+ ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev != 0 || - wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { - dflt_pwr_limit = 0; - goto out_free; -@@ -211,14 +216,15 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); - int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) - { - union acpi_object *wifi_pkg, *data; -- int ret; -+ int ret, tbl_rev; - - data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - -- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg)) { -+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, -+ &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } -diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h -index f5704e16643f..991a23450999 100644 ---- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h -+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h -@@ -97,7 +97,7 @@ - void *iwl_acpi_get_object(struct device *dev, acpi_string method); - union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, - union acpi_object *data, -- int data_size); -+ int data_size, int *tbl_rev); - - /** - * iwl_acpi_get_mcc - read MCC from ACPI, if available -@@ -131,7 +131,8 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method) - - static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, - union acpi_object *data, -- int data_size) -+ int data_size, -+ int *tbl_rev) - { - return ERR_PTR(-ENOENT); - } -diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h -index 01f003c6cff9..f195db398bed 100644 ---- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h -+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h -@@ -419,14 +419,26 @@ struct iwl_per_chain_offset_group { - struct iwl_per_chain_offset hb; - } __packed; /* PER_CHAIN_LIMIT_OFFSET_GROUP_S_VER_1 */ - -+/** -+ * struct iwl_geo_tx_power_profile_cmd_v1 - struct for GEO_TX_POWER_LIMIT cmd. -+ * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation -+ * @table: offset profile per band. -+ */ -+struct iwl_geo_tx_power_profiles_cmd_v1 { -+ __le32 ops; -+ struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES]; -+} __packed; /* GEO_TX_POWER_LIMIT_VER_1 */ -+ - /** - * struct iwl_geo_tx_power_profile_cmd - struct for GEO_TX_POWER_LIMIT cmd. - * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation - * @table: offset profile per band. -+ * @table_revision: BIOS table revision. - */ - struct iwl_geo_tx_power_profiles_cmd { - __le32 ops; - struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES]; -+ __le32 table_revision; - } __packed; /* GEO_TX_POWER_LIMIT */ - - /** -diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h -index de9243d30135..a74f34a8dffb 100644 ---- a/drivers/net/wireless/intel/iwlwifi/fw/file.h -+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h -@@ -286,6 +286,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; - * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S. - * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of - * STA_CONTEXT_DOT11AX_API_S -+ * @IWL_UCODE_TLV_CAPA_SAR_TABLE_VER: This ucode supports different sar -+ * version tables. - * - * @NUM_IWL_UCODE_TLV_API: number of bits used - */ -@@ -318,6 +320,7 @@ enum iwl_ucode_tlv_api { - IWL_UCODE_TLV_API_MBSSID_HE = (__force iwl_ucode_tlv_api_t)52, - IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE = (__force iwl_ucode_tlv_api_t)53, - IWL_UCODE_TLV_API_FTM_RTT_ACCURACY = (__force iwl_ucode_tlv_api_t)54, -+ IWL_UCODE_TLV_API_SAR_TABLE_VER = (__force iwl_ucode_tlv_api_t)55, - - NUM_IWL_UCODE_TLV_API - #ifdef __CHECKER__ -diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c -index 559f6df1a74d..8a3e542c47b2 100644 ---- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c -+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c -@@ -682,15 +682,15 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) - { - union acpi_object *wifi_pkg, *table, *data; - bool enabled; -- int ret; -+ int ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, -- ACPI_WRDS_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg)) { -+ ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } -@@ -719,15 +719,15 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) - { - union acpi_object *wifi_pkg, *data; - bool enabled; -- int i, n_profiles, ret; -+ int i, n_profiles, ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, -- ACPI_EWRD_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg)) { -+ ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } -@@ -778,7 +778,7 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) - static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) - { - union acpi_object *wifi_pkg, *data; -- int i, j, ret; -+ int i, j, ret, tbl_rev; - int idx = 1; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD); -@@ -786,12 +786,13 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, -- ACPI_WGDS_WIFI_DATA_SIZE); -- if (IS_ERR(wifi_pkg)) { -+ ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); -+ if (IS_ERR(wifi_pkg) || tbl_rev > 1) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - -+ mvm->geo_rev = tbl_rev; - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { - union acpi_object *entry; -@@ -878,15 +879,29 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) - { - struct iwl_geo_tx_power_profiles_resp *resp; - int ret; -+ u16 len; -+ void *data; -+ struct iwl_geo_tx_power_profiles_cmd geo_cmd; -+ struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1; -+ struct iwl_host_cmd cmd; -+ -+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { -+ geo_cmd.ops = -+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); -+ len = sizeof(geo_cmd); -+ data = &geo_cmd; -+ } else { -+ geo_cmd_v1.ops = -+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); -+ len = sizeof(geo_cmd_v1); -+ data = &geo_cmd_v1; -+ } - -- struct iwl_geo_tx_power_profiles_cmd geo_cmd = { -- .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE), -- }; -- struct iwl_host_cmd cmd = { -+ cmd = (struct iwl_host_cmd){ - .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), -- .len = { sizeof(geo_cmd), }, -+ .len = { len, }, - .flags = CMD_WANT_SKB, -- .data = { &geo_cmd }, -+ .data = { data }, - }; - - ret = iwl_mvm_send_cmd(mvm, &cmd); -@@ -956,6 +971,16 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) - i, j, value[1], value[2], value[0]); - } - } -+ -+ cmd.table_revision = cpu_to_le32(mvm->geo_rev); -+ -+ if (!fw_has_api(&mvm->fw->ucode_capa, -+ IWL_UCODE_TLV_API_SAR_TABLE_VER)) { -+ return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, -+ sizeof(struct iwl_geo_tx_power_profiles_cmd_v1), -+ &cmd); -+ } -+ - return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd); - } - -diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h -index 88af1f0ba3f0..ed8fc9a9204c 100644 ---- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h -+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h -@@ -1184,6 +1184,7 @@ struct iwl_mvm { - #ifdef CONFIG_ACPI - struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; - struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES]; -+ u32 geo_rev; - #endif - }; - --- -2.22.0 - diff --git a/0005-bootsplash.patch b/0005-bootsplash.patch new file mode 100644 index 000000000000..216953762e2e --- /dev/null +++ b/0005-bootsplash.patch @@ -0,0 +1,66 @@ +diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c +index 843c5400fefc..815b007f81ca 100644 +--- a/drivers/video/fbdev/core/bootsplash.c ++++ b/drivers/video/fbdev/core/bootsplash.c +@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info) + + bootsplash_do_render_pictures(info, splash_state.file); + ++ bootsplash_do_render_flush(info); ++ + out: + mutex_unlock(&splash_state.data_lock); + } +diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h +index 71e2a27ac0b8..0acb383aa4e3 100644 +--- a/drivers/video/fbdev/core/bootsplash_internal.h ++++ b/drivers/video/fbdev/core/bootsplash_internal.h +@@ -89,6 +89,7 @@ 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_do_render_flush(struct fb_info *info); + + + void bootsplash_free_file(struct splash_file_priv *fp); +diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c +index 2ae36949d0e3..8c09c306ff67 100644 +--- a/drivers/video/fbdev/core/bootsplash_render.c ++++ b/drivers/video/fbdev/core/bootsplash_render.c +@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info, + pp->pic_header->width, pp->pic_header->height); + } + } ++ ++ ++void bootsplash_do_render_flush(struct fb_info *info) ++{ ++ /* ++ * FB drivers using deferred_io (such as Xen) need to sync the ++ * screen after modifying its contents. When the FB is mmap()ed ++ * from userspace, this happens via a dirty pages callback, but ++ * when modifying the FB from the kernel, there is no such thing. ++ * ++ * So let's issue a fake fb_copyarea (copying the FB onto itself) ++ * to trick the FB driver into syncing the screen. ++ * ++ * A few DRM drivers' FB implementations are broken by not using ++ * deferred_io when they really should - we match on the known ++ * bad ones manually for now. ++ */ ++ if (info->fbdefio ++ || !strcmp(info->fix.id, "astdrmfb") ++ || !strcmp(info->fix.id, "cirrusdrmfb") ++ || !strcmp(info->fix.id, "mgadrmfb")) { ++ struct fb_copyarea area; ++ ++ area.dx = 0; ++ area.dy = 0; ++ area.width = info->var.xres; ++ area.height = info->var.yres; ++ area.sx = 0; ++ area.sy = 0; ++ ++ info->fbops->fb_copyarea(info, &area); ++ } ++} diff --git a/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch b/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch deleted file mode 100644 index 1c617f6121dd..000000000000 --- a/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 103abca5ff3ca4db4d8f6c21626fa597fe122a03 Mon Sep 17 00:00:00 2001 -From: Christian Hesse <mail@eworm.de> -Date: Thu, 11 Jul 2019 01:31:12 +0200 -Subject: [PATCH 5/6] netfilter: nf_tables: fix module autoload for redir - -Fix expression for autoloading. - -Fixes: 5142967ab524 ("netfilter: nf_tables: fix module autoload with inet family") -Signed-off-by: Christian Hesse <mail@eworm.de> -Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> ---- - net/netfilter/nft_redir.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c -index 8487eeff5c0e..43eeb1f609f1 100644 ---- a/net/netfilter/nft_redir.c -+++ b/net/netfilter/nft_redir.c -@@ -291,4 +291,4 @@ module_exit(nft_redir_module_exit); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>"); --MODULE_ALIAS_NFT_EXPR("nat"); -+MODULE_ALIAS_NFT_EXPR("redir"); --- -2.22.0 - diff --git a/0006-bootsplash.patch b/0006-bootsplash.patch index 924f23f33ce9..7eb54aff7e00 100644 --- a/0006-bootsplash.patch +++ b/0006-bootsplash.patch @@ -1,746 +1,215 @@ -diff --git a/MAINTAINERS b/MAINTAINERS -index a74227ad082e..b5633b56391e 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -2705,6 +2705,14 @@ S: Supported - F: drivers/net/bonding/ - F: include/uapi/linux/if_bonding.h +diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c +index 8c09c306ff67..07e3a4eab811 100644 +--- a/drivers/video/fbdev/core/bootsplash_render.c ++++ b/drivers/video/fbdev/core/bootsplash_render.c +@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info, + for (i = 0; i < fp->header->num_pics; i++) { + struct splash_blob_priv *bp; + struct splash_pic_priv *pp = &fp->pics[i]; ++ const struct splash_pic_header *ph = pp->pic_header; + long dst_xoff, dst_yoff; -+BOOTSPLASH -+M: Max Staudt <mstaudt@suse.de> -+L: linux-fbdev@vger.kernel.org -+S: Maintained -+F: drivers/video/fbdev/core/bootsplash*.* -+F: drivers/video/fbdev/core/dummycon.c -+F: include/linux/bootsplash.h -+ - BPF (Safe dynamic programs and tools) - M: Alexei Starovoitov <ast@kernel.org> - M: Daniel Borkmann <daniel@iogearbox.net> -diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig -index 7f1f1fbcef9e..f3ff976266fe 100644 ---- a/drivers/video/console/Kconfig -+++ b/drivers/video/console/Kconfig -@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION - such that other users of the framebuffer will remain normally - oriented. + if (pp->blobs_loaded < 1) +@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info, + if (!bp || bp->blob_header->type != 0) + continue; -+config BOOTSPLASH -+ bool "Bootup splash screen" -+ depends on FRAMEBUFFER_CONSOLE -+ ---help--- -+ This option enables the Linux bootsplash screen. -+ -+ The bootsplash is a full-screen logo or animation indicating a -+ booting system. It replaces the classic scrolling text with a -+ graphical alternative, similar to other systems. -+ -+ Since this is technically implemented as a hook on top of fbcon, -+ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a -+ framebuffer driver is active. Thus, to get a text-free boot, -+ the system needs to boot with vesafb, efifb, or similar. -+ -+ Once built into the kernel, the bootsplash needs to be enabled -+ with bootsplash.enabled=1 and a splash file needs to be supplied. -+ -+ Further documentation can be found in: -+ Documentation/fb/bootsplash.txt -+ -+ If unsure, say N. -+ This is typically used by distributors and system integrators. -+ - config STI_CONSOLE - bool "STI text console" - depends on PARISC -diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile -index 73493bbd7a15..66895321928e 100644 ---- a/drivers/video/fbdev/core/Makefile -+++ b/drivers/video/fbdev/core/Makefile -@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o - obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o - obj-$(CONFIG_FB_SVGALIB) += svgalib.o - obj-$(CONFIG_FB_DDC) += fb_ddc.o -+ -+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \ -+ dummyblit.o -diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c -new file mode 100644 -index 000000000000..e449755af268 ---- /dev/null -+++ b/drivers/video/fbdev/core/bootsplash.c -@@ -0,0 +1,294 @@ -+/* -+ * Kernel based bootsplash. -+ * -+ * (Main file: Glue code, workers, timer, PM, kernel and userland API) -+ * -+ * Authors: -+ * Max Staudt <mstaudt@suse.de> -+ * -+ * SPDX-License-Identifier: GPL-2.0 -+ */ -+ -+#define pr_fmt(fmt) "bootsplash: " fmt -+ -+ -+#include <linux/atomic.h> -+#include <linux/bootsplash.h> -+#include <linux/console.h> -+#include <linux/device.h> /* dev_warn() */ -+#include <linux/fb.h> -+#include <linux/fs.h> -+#include <linux/kernel.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/platform_device.h> -+#include <linux/printk.h> -+#include <linux/selection.h> /* console_blanked */ -+#include <linux/stringify.h> -+#include <linux/types.h> -+#include <linux/vmalloc.h> -+#include <linux/vt_kern.h> -+#include <linux/workqueue.h> -+ -+#include "bootsplash_internal.h" -+ -+ -+/* -+ * We only have one splash screen, so let's keep a single -+ * instance of the internal state. -+ */ -+static struct splash_priv splash_state; -+ -+ -+static void splash_callback_redraw_vc(struct work_struct *ignored) -+{ -+ if (console_blanked) -+ return; -+ -+ console_lock(); -+ if (vc_cons[fg_console].d) -+ update_screen(vc_cons[fg_console].d); -+ console_unlock(); -+} -+ -+ -+static bool is_fb_compatible(const struct fb_info *info) -+{ -+ if (!(info->flags & FBINFO_BE_MATH) -+ != !fb_be_math((struct fb_info *)info)) { -+ dev_warn(info->device, -+ "Can't draw on foreign endianness framebuffer.\n"); -+ -+ return false; -+ } -+ -+ if (info->flags & FBINFO_MISC_TILEBLITTING) { -+ dev_warn(info->device, -+ "Can't draw splash on tiling framebuffer.\n"); -+ -+ return false; -+ } -+ -+ if (info->fix.type != FB_TYPE_PACKED_PIXELS -+ || (info->fix.visual != FB_VISUAL_TRUECOLOR -+ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) { -+ dev_warn(info->device, -+ "Can't draw splash on non-packed or non-truecolor framebuffer.\n"); -+ -+ dev_warn(info->device, -+ " type: %u visual: %u\n", -+ info->fix.type, info->fix.visual); -+ -+ return false; -+ } -+ -+ if (info->var.bits_per_pixel != 16 -+ && info->var.bits_per_pixel != 24 -+ && info->var.bits_per_pixel != 32) { -+ dev_warn(info->device, -+ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n", -+ info->var.bits_per_pixel); -+ -+ return false; -+ } -+ -+ return true; -+} -+ -+ -+/* -+ * Called by fbcon_switch() when an instance is activated or refreshed. -+ */ -+void bootsplash_render_full(struct fb_info *info) -+{ -+ if (!is_fb_compatible(info)) -+ return; -+ -+ bootsplash_do_render_background(info); -+} -+ -+ -+/* -+ * External status enquiry and on/off switch -+ */ -+bool bootsplash_would_render_now(void) -+{ -+ return !oops_in_progress -+ && !console_blanked -+ && bootsplash_is_enabled(); -+} -+ -+bool bootsplash_is_enabled(void) -+{ -+ bool was_enabled; -+ -+ /* Make sure we have the newest state */ -+ smp_rmb(); -+ -+ was_enabled = test_bit(0, &splash_state.enabled); -+ -+ return was_enabled; -+} -+ -+void bootsplash_disable(void) -+{ -+ int was_enabled; -+ -+ was_enabled = test_and_clear_bit(0, &splash_state.enabled); -+ -+ if (was_enabled) { -+ if (oops_in_progress) { -+ /* Redraw screen now so we can see a panic */ -+ if (vc_cons[fg_console].d) -+ update_screen(vc_cons[fg_console].d); -+ } else { -+ /* No urgency, redraw at next opportunity */ -+ schedule_work(&splash_state.work_redraw_vc); +- dst_xoff = (info->var.xres - pp->pic_header->width) / 2; +- dst_yoff = (info->var.yres - pp->pic_header->height) / 2; ++ switch (ph->position) { ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT: ++ dst_xoff = 0; ++ dst_yoff = 0; ++ ++ dst_xoff += ph->position_offset; ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = 0; ++ ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_yoff = 0; ++ ++ dst_xoff -= ph->position_offset; ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff -= ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ ++ dst_xoff -= ph->position_offset; ++ dst_yoff -= ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ ++ dst_yoff -= ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT: ++ dst_xoff = 0 + ph->position_offset; ++ dst_yoff = info->var.yres - pp->pic_header->height ++ - ph->position_offset; ++ break; ++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT: ++ dst_xoff = 0; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff += ph->position_offset; ++ break; ++ ++ case SPLASH_CORNER_TOP_LEFT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff -= ph->position_offset; ++ dst_yoff -= ph->position_offset; ++ break; ++ case SPLASH_CORNER_TOP: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_yoff -= ph->position_offset; ++ break; ++ case SPLASH_CORNER_TOP_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff += ph->position_offset; ++ dst_yoff -= ph->position_offset; ++ break; ++ case SPLASH_CORNER_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff += ph->position_offset; ++ break; ++ case SPLASH_CORNER_BOTTOM_RIGHT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff += ph->position_offset; ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_CORNER_BOTTOM: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_CORNER_BOTTOM_LEFT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff -= ph->position_offset; ++ dst_yoff += ph->position_offset; ++ break; ++ case SPLASH_CORNER_LEFT: ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ ++ dst_xoff -= ph->position_offset; ++ break; ++ ++ default: ++ /* As a fallback, center the picture. */ ++ dst_xoff = info->var.xres - pp->pic_header->width; ++ dst_xoff /= 2; ++ dst_yoff = info->var.yres - pp->pic_header->height; ++ dst_yoff /= 2; ++ break; + } -+ } -+} -+ -+void bootsplash_enable(void) -+{ -+ bool was_enabled; -+ -+ if (oops_in_progress) -+ return; -+ -+ was_enabled = test_and_set_bit(0, &splash_state.enabled); -+ -+ if (!was_enabled) -+ schedule_work(&splash_state.work_redraw_vc); -+} -+ -+ -+/* -+ * Userland API via platform device in sysfs -+ */ -+static ssize_t splash_show_enabled(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%d\n", bootsplash_is_enabled()); -+} -+ -+static ssize_t splash_store_enabled(struct device *device, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ bool enable; -+ int err; -+ -+ if (!buf || !count) -+ return -EFAULT; -+ -+ err = kstrtobool(buf, &enable); -+ if (err) -+ return err; -+ -+ if (enable) -+ bootsplash_enable(); -+ else -+ bootsplash_disable(); -+ -+ return count; -+} -+ -+static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled); -+ -+ -+static struct attribute *splash_dev_attrs[] = { -+ &dev_attr_enabled.attr, -+ NULL -+}; -+ -+ATTRIBUTE_GROUPS(splash_dev); -+ -+ -+ -+ -+/* -+ * Power management fixup via platform device -+ * -+ * When the system is woken from sleep or restored after hibernating, we -+ * cannot expect the screen contents to still be present in video RAM. -+ * Thus, we have to redraw the splash if we're currently active. -+ */ -+static int splash_resume(struct device *device) -+{ -+ if (bootsplash_would_render_now()) -+ schedule_work(&splash_state.work_redraw_vc); -+ -+ return 0; -+} -+ -+static int splash_suspend(struct device *device) -+{ -+ cancel_work_sync(&splash_state.work_redraw_vc); -+ -+ return 0; -+} -+ -+ -+static const struct dev_pm_ops splash_pm_ops = { -+ .thaw = splash_resume, -+ .restore = splash_resume, -+ .resume = splash_resume, -+ .suspend = splash_suspend, -+ .freeze = splash_suspend, -+}; -+ -+static struct platform_driver splash_driver = { -+ .driver = { -+ .name = "bootsplash", -+ .pm = &splash_pm_ops, -+ }, -+}; -+ -+ -+/* -+ * Main init -+ */ -+void bootsplash_init(void) -+{ -+ int ret; -+ -+ /* Initialized already? */ -+ if (splash_state.splash_device) -+ return; -+ -+ -+ /* Register platform device to export user API */ -+ ret = platform_driver_register(&splash_driver); -+ if (ret) { -+ pr_err("platform_driver_register() failed: %d\n", ret); -+ goto err; -+ } -+ -+ splash_state.splash_device -+ = platform_device_alloc("bootsplash", 0); -+ -+ if (!splash_state.splash_device) -+ goto err_driver; -+ -+ splash_state.splash_device->dev.groups = splash_dev_groups; -+ -+ ret = platform_device_add(splash_state.splash_device); -+ if (ret) { -+ pr_err("platform_device_add() failed: %d\n", ret); -+ goto err_device; -+ } -+ -+ -+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); -+ -+ return; -+ -+err_device: -+ platform_device_put(splash_state.splash_device); -+ splash_state.splash_device = NULL; -+err_driver: -+ platform_driver_unregister(&splash_driver); -+err: -+ pr_err("Failed to initialize.\n"); -+} -diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h -new file mode 100644 -index 000000000000..b11da5cb90bf ---- /dev/null -+++ b/drivers/video/fbdev/core/bootsplash_internal.h -@@ -0,0 +1,55 @@ -+/* -+ * Kernel based bootsplash. -+ * -+ * (Internal data structures used at runtime) -+ * -+ * Authors: -+ * Max Staudt <mstaudt@suse.de> -+ * -+ * SPDX-License-Identifier: GPL-2.0 -+ */ -+ -+#ifndef __BOOTSPLASH_INTERNAL_H -+#define __BOOTSPLASH_INTERNAL_H -+ -+ -+#include <linux/types.h> -+#include <linux/fb.h> -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/spinlock.h> -+ -+ -+/* -+ * Runtime types -+ */ -+struct splash_priv { + + if (dst_xoff < 0 + || dst_yoff < 0 +diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h +index 89dc9cca8f0c..71cedcc68933 100644 +--- a/include/uapi/linux/bootsplash_file.h ++++ b/include/uapi/linux/bootsplash_file.h +@@ -91,7 +91,32 @@ struct splash_pic_header { + */ + uint8_t num_blobs; + +- uint8_t padding[27]; + /* -+ * Enabled/disabled state, to be used with atomic bit operations. -+ * Bit 0: 0 = Splash hidden -+ * 1 = Splash shown ++ * Corner to move the picture to / from. ++ * 0x00 - Top left ++ * 0x01 - Top ++ * 0x02 - Top right ++ * 0x03 - Right ++ * 0x04 - Bottom right ++ * 0x05 - Bottom ++ * 0x06 - Bottom left ++ * 0x07 - Left + * -+ * Note: fbcon.c uses this twice, by calling -+ * bootsplash_would_render_now() in set_blitting_type() and -+ * in fbcon_switch(). -+ * This is racy, but eventually consistent: Turning the -+ * splash on/off will cause a redraw, which calls -+ * fbcon_switch(), which calls set_blitting_type(). -+ * So the last on/off toggle will make things consistent. -+ */ -+ unsigned long enabled; -+ -+ /* Our gateway to userland via sysfs */ -+ struct platform_device *splash_device; -+ -+ struct work_struct work_redraw_vc; -+}; -+ -+ -+ -+/* -+ * Rendering functions -+ */ -+void bootsplash_do_render_background(struct fb_info *info); -+ -+#endif -diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c -new file mode 100644 -index 000000000000..4d7e0117f653 ---- /dev/null -+++ b/drivers/video/fbdev/core/bootsplash_render.c -@@ -0,0 +1,93 @@ -+/* -+ * Kernel based bootsplash. -+ * -+ * (Rendering 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/kernel.h> -+#include <linux/printk.h> -+#include <linux/types.h> -+ -+#include "bootsplash_internal.h" -+ -+ -+ -+ -+/* -+ * Rendering: Internal drawing routines -+ */ -+ -+ -+/* -+ * Pack pixel into target format and do Big/Little Endian handling. -+ * This would be a good place to handle endianness conversion if necessary. -+ */ -+static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var, -+ u8 red, u8 green, u8 blue) -+{ -+ u32 dstpix; -+ -+ /* Quantize pixel */ -+ red = red >> (8 - dst_var->red.length); -+ green = green >> (8 - dst_var->green.length); -+ blue = blue >> (8 - dst_var->blue.length); -+ -+ /* Pack pixel */ -+ dstpix = red << (dst_var->red.offset) -+ | green << (dst_var->green.offset) -+ | blue << (dst_var->blue.offset); -+ -+ /* -+ * Move packed pixel to the beginning of the memory cell, -+ * so we can memcpy() it out easily ++ * Flags: ++ * 0x10 - Calculate offset from the corner towards the center, ++ * rather than from the center towards the corner + */ -+#ifdef __BIG_ENDIAN -+ switch (dst_var->bits_per_pixel) { -+ case 16: -+ dstpix <<= 16; -+ break; -+ case 24: -+ dstpix <<= 8; -+ break; -+ case 32: -+ break; -+ } -+#else -+ /* This is intrinsically unnecessary on Little Endian */ -+#endif -+ -+ return dstpix; -+} -+ -+ -+void bootsplash_do_render_background(struct fb_info *info) -+{ -+ unsigned int x, y; -+ u32 dstpix; -+ u32 dst_octpp = info->var.bits_per_pixel / 8; -+ -+ dstpix = pack_pixel(&info->var, -+ 0, -+ 0, -+ 0); -+ -+ for (y = 0; y < info->var.yres_virtual; y++) { -+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length); -+ -+ for (x = 0; x < info->var.xres_virtual; x++) { -+ memcpy(dstline, &dstpix, dst_octpp); -+ -+ dstline += dst_octpp; -+ } -+ } -+} -diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c -new file mode 100644 -index 000000000000..8c22ff92ce24 ---- /dev/null -+++ b/drivers/video/fbdev/core/dummyblit.c -@@ -0,0 +1,89 @@ -+/* -+ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation -+ * -+ * Authors: -+ * Max Staudt <mstaudt@suse.de> -+ * -+ * These functions are used in place of blitblit/tileblit to suppress -+ * fbcon's text output while a splash is shown. -+ * -+ * Only suppressing actual rendering keeps the text buffer in the VC layer -+ * intact and makes it easy to switch back from the bootsplash to a full -+ * text console with a simple redraw (with the original functions in place). -+ * -+ * Based on linux/drivers/video/fbdev/core/bitblit.c -+ * and linux/drivers/video/fbdev/core/tileblit.c -+ * -+ * SPDX-License-Identifier: GPL-2.0 -+ */ -+ -+#include <linux/module.h> -+#include <linux/fb.h> -+#include <linux/vt_kern.h> -+#include <linux/console.h> -+#include <asm/types.h> -+#include "fbcon.h" ++ uint8_t position; + -+static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ ; -+} -+ -+static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int height, int width) -+{ -+ ; -+} -+ -+static void dummy_putcs(struct vc_data *vc, struct fb_info *info, -+ const unsigned short *s, int count, int yy, int xx, -+ int fg, int bg) -+{ -+ ; -+} -+ -+static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info, -+ int color, int bottom_only) -+{ -+ ; -+} -+ -+static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -+{ -+ ; -+} -+ -+static int dummy_update_start(struct fb_info *info) -+{ + /* -+ * Copied from bitblit.c and tileblit.c -+ * -+ * As of Linux 4.12, nobody seems to care about our return value. ++ * Pixel offset from the selected position. ++ * Example: If the picture is in the top right corner, it will ++ * be placed position_offset pixels from the top and ++ * position_offset pixels from the right margin. + */ -+ struct fbcon_ops *ops = info->fbcon_par; -+ int err; ++ uint16_t position_offset; + -+ err = fb_pan_display(info, &ops->var); -+ ops->var.xoffset = info->var.xoffset; -+ ops->var.yoffset = info->var.yoffset; -+ ops->var.vmode = info->var.vmode; -+ return err; -+} -+ -+void fbcon_set_dummyops(struct fbcon_ops *ops) -+{ -+ ops->bmove = dummy_bmove; -+ ops->clear = dummy_clear; -+ ops->putcs = dummy_putcs; -+ ops->clear_margins = dummy_clear_margins; -+ ops->cursor = dummy_cursor; -+ ops->update_start = dummy_update_start; -+ ops->rotate_font = NULL; -+} -+EXPORT_SYMBOL_GPL(fbcon_set_dummyops); -+ -+MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>"); -+MODULE_DESCRIPTION("Dummy Blitting Operation"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c -index 04612f938bab..9a39a6fcfe98 100644 ---- a/drivers/video/fbdev/core/fbcon.c -+++ b/drivers/video/fbdev/core/fbcon.c -@@ -80,6 +80,7 @@ - #include <asm/irq.h> ++ uint8_t padding[24]; + } __attribute__((__packed__)); - #include "fbcon.h" -+#include <linux/bootsplash.h> - #ifdef FBCONDEBUG - # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo) - for (i = first_fb_vc; i <= last_fb_vc; i++) - con2fb_map[i] = info_idx; +@@ -115,4 +140,22 @@ struct splash_blob_header { + uint8_t padding[9]; + } __attribute__((__packed__)); -+ bootsplash_init(); + - err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc, - fbcon_is_default); - -@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) - else { - fbcon_set_rotation(info); - fbcon_set_bitops(ops); -+ -+ if (bootsplash_would_render_now()) -+ fbcon_set_dummyops(ops); - } - } - -@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) - ops->p = &fb_display[vc->vc_num]; - fbcon_set_rotation(info); - fbcon_set_bitops(ops); + -+ /* -+ * Note: -+ * This is *eventually correct*. -+ * Setting the fbcon operations and drawing the splash happen at -+ * different points in time. If the splash is enabled/disabled -+ * in between, then bootsplash_{en,dis}able will schedule a -+ * redraw, which will again render the splash (or not) and set -+ * the correct fbcon ops. -+ * The last run will then be the right one. -+ */ -+ if (bootsplash_would_render_now()) -+ fbcon_set_dummyops(ops); - } - - static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) -@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc) - info = registered_fb[con2fb_map[vc->vc_num]]; - ops = info->fbcon_par; - -+ if (bootsplash_would_render_now()) -+ bootsplash_render_full(info); + - if (softback_top) { - if (softback_lines) - fbcon_set_origin(vc); -diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h -index 18f3ac144237..45f94347fe5e 100644 ---- a/drivers/video/fbdev/core/fbcon.h -+++ b/drivers/video/fbdev/core/fbcon.h -@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc, - #define SCROLL_REDRAW 0x004 - #define SCROLL_PAN_REDRAW 0x005 - -+#ifdef CONFIG_BOOTSPLASH -+extern void fbcon_set_dummyops(struct fbcon_ops *ops); -+#else /* CONFIG_BOOTSPLASH */ -+#define fbcon_set_dummyops(x) -+#endif /* CONFIG_BOOTSPLASH */ - #ifdef CONFIG_FB_TILEBLITTING - extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); - #endif -diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h -new file mode 100644 -index 000000000000..c6dd0b43180d ---- /dev/null -+++ b/include/linux/bootsplash.h -@@ -0,0 +1,43 @@ +/* -+ * Kernel based bootsplash. -+ * -+ * Authors: -+ * Max Staudt <mstaudt@suse.de> -+ * -+ * SPDX-License-Identifier: GPL-2.0 ++ * Enums for on-disk types + */ ++enum splash_position { ++ SPLASH_CORNER_TOP_LEFT = 0, ++ SPLASH_CORNER_TOP = 1, ++ SPLASH_CORNER_TOP_RIGHT = 2, ++ SPLASH_CORNER_RIGHT = 3, ++ SPLASH_CORNER_BOTTOM_RIGHT = 4, ++ SPLASH_CORNER_BOTTOM = 5, ++ SPLASH_CORNER_BOTTOM_LEFT = 6, ++ SPLASH_CORNER_LEFT = 7, ++ SPLASH_POS_FLAG_CORNER = 0x10, ++}; + -+#ifndef __LINUX_BOOTSPLASH_H -+#define __LINUX_BOOTSPLASH_H -+ -+#include <linux/fb.h> -+ -+ -+#ifdef CONFIG_BOOTSPLASH -+ -+extern void bootsplash_render_full(struct fb_info *info); -+ -+extern bool bootsplash_would_render_now(void); -+ -+extern bool bootsplash_is_enabled(void); -+extern void bootsplash_disable(void); -+extern void bootsplash_enable(void); -+ -+extern void bootsplash_init(void); -+ -+#else /* CONFIG_BOOTSPLASH */ -+ -+#define bootsplash_render_full(x) -+ -+#define bootsplash_would_render_now() (false) -+ -+#define bootsplash_is_enabled() (false) -+#define bootsplash_disable() -+#define bootsplash_enable() -+ -+#define bootsplash_init() -+ -+#endif /* CONFIG_BOOTSPLASH */ -+ -+ -+#endif + #endif diff --git a/0007-bootsplash.patch b/0007-bootsplash.patch index 92d62caa7031..2785c5e65277 100644 --- a/0007-bootsplash.patch +++ b/0007-bootsplash.patch @@ -1,669 +1,327 @@ -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 +index 815b007f81ca..c8642142cfea 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" +@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored) + console_unlock(); + } ++static void splash_callback_animation(struct work_struct *ignored) ++{ ++ if (bootsplash_would_render_now()) { ++ /* This will also re-schedule this delayed worker */ ++ splash_callback_redraw_vc(ignored); ++ } ++} ++ - /* -@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info) + static bool is_fb_compatible(const struct fb_info *info) + { +@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info) */ void bootsplash_render_full(struct fb_info *info) { -+ mutex_lock(&splash_state.data_lock); ++ bool is_update = false; + - if (!is_fb_compatible(info)) -- return; -+ goto out; + mutex_lock(&splash_state.data_lock); + +- if (!is_fb_compatible(info)) +- goto out; ++ /* ++ * If we've painted on this FB recently, we don't have to do ++ * the sanity checks and background drawing again. ++ */ ++ if (splash_state.splash_fb == info) ++ is_update = true; + -+ bootsplash_do_render_background(info, splash_state.file); + -+ bootsplash_do_render_pictures(info, splash_state.file); ++ if (!is_update) { ++ /* Check whether we actually support this FB. */ ++ splash_state.splash_fb = NULL; ++ ++ if (!is_fb_compatible(info)) ++ goto out; ++ ++ /* Draw the background only once */ ++ bootsplash_do_render_background(info, splash_state.file); -- bootsplash_do_render_background(info); -+out: -+ mutex_unlock(&splash_state.data_lock); - } +- bootsplash_do_render_background(info, splash_state.file); ++ /* Mark this FB as last seen */ ++ splash_state.splash_fb = info; ++ } +- bootsplash_do_render_pictures(info, splash_state.file); ++ bootsplash_do_render_pictures(info, splash_state.file, is_update); -@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void) - { - return !oops_in_progress - && !console_blanked -+ && splash_state.file - && bootsplash_is_enabled(); - } + bootsplash_do_render_flush(info); -@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = { - void bootsplash_init(void) - { - int ret; -+ struct splash_file_priv *fp; ++ bootsplash_do_step_animations(splash_state.file); ++ ++ /* Schedule update for animated splash screens */ ++ if (splash_state.file->frame_ms > 0) ++ schedule_delayed_work(&splash_state.dwork_animation, ++ msecs_to_jiffies( ++ splash_state.file->frame_ms)); ++ + out: + mutex_unlock(&splash_state.data_lock); + } +@@ -169,8 +204,14 @@ void bootsplash_enable(void) - /* Initialized already? */ - if (splash_state.splash_device) -@@ -280,8 +290,26 @@ void bootsplash_init(void) - } + was_enabled = test_and_set_bit(0, &splash_state.enabled); +- if (!was_enabled) ++ if (!was_enabled) { ++ /* Force a full redraw when the splash is re-activated */ ++ mutex_lock(&splash_state.data_lock); ++ splash_state.splash_fb = NULL; ++ mutex_unlock(&splash_state.data_lock); ++ + schedule_work(&splash_state.work_redraw_vc); ++ } + } -+ 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; -+ +@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev); + */ + static int splash_resume(struct device *device) + { ++ /* ++ * Force full redraw on resume since we've probably lost the ++ * framebuffer's contents meanwhile ++ */ + mutex_lock(&splash_state.data_lock); + splash_state.splash_fb = NULL; -+ splash_state.file = fp; + mutex_unlock(&splash_state.data_lock); + - return; + if (bootsplash_would_render_now()) + schedule_work(&splash_state.work_redraw_vc); - 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"); +@@ -235,6 +284,7 @@ static int splash_resume(struct device *device) + + static int splash_suspend(struct device *device) + { ++ cancel_delayed_work_sync(&splash_state.dwork_animation); + cancel_work_sync(&splash_state.work_redraw_vc); + + return 0; +@@ -296,6 +346,8 @@ void bootsplash_init(void) + set_bit(0, &splash_state.enabled); + + INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); ++ INIT_DELAYED_WORK(&splash_state.dwork_animation, ++ splash_callback_animation); + + + if (!splash_state.bootfile || !strlen(splash_state.bootfile)) diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h -index b11da5cb90bf..71e2a27ac0b8 100644 +index 0acb383aa4e3..b3a74835d90f 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> +@@ -37,6 +37,8 @@ struct splash_pic_priv { -+#include "uapi/linux/bootsplash_file.h" + struct splash_blob_priv *blobs; + u16 blobs_loaded; + ++ u16 anim_nextframe; + }; - /* - * 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; + +@@ -45,6 +47,12 @@ struct splash_file_priv { + const struct splash_file_header *header; + + struct splash_pic_priv *pics; + - /* - * Enabled/disabled state, to be used with atomic bit operations. - * Bit 0: 0 = Splash hidden -@@ -43,6 +71,13 @@ struct splash_priv { ++ /* ++ * A local copy of the frame delay in the header. ++ * We modify it to keep the code simple. ++ */ ++ u16 frame_ms; + }; + + +@@ -71,6 +79,7 @@ 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; - }; ++ struct delayed_work dwork_animation; + /* Splash data structures including lock for everything below */ + struct mutex data_lock; +@@ -88,8 +97,10 @@ struct splash_priv { + 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); ++ const struct splash_file_priv *fp, ++ bool is_update); + void bootsplash_do_render_flush(struct fb_info *info); ++void bootsplash_do_step_animations(struct splash_file_priv *fp); -@@ -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 + void bootsplash_free_file(struct splash_file_priv *fp); 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 +index fd807571ab7d..1f661b2d4cc9 100644 +--- a/drivers/video/fbdev/core/bootsplash_load.c +++ 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); +@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + { + const struct firmware *fw; + struct splash_file_priv *fp; ++ bool have_anim = false; + unsigned int i; + const u8 *walker; + +@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + goto err; + } + ++ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) { ++ pr_warn("Picture %u: Unsupported animation type %u.\n", ++ i, ph->anim_type); + -+ goto err; ++ ph->anim_type = SPLASH_ANIM_NONE; + } -+ } -+ -+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n", -+ fw->size, -+ fp->header->num_pics, -+ fp->header->num_blobs); -+ -+ return fp; + + pp->pic_header = ph; + pp->blobs = vzalloc(ph->num_blobs + * sizeof(struct splash_blob_priv)); +@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + /* 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]; ++ const struct splash_pic_header *ph = pp->pic_header; + + if (pp->blobs_loaded != pp->pic_header->num_blobs) { + pr_err("Picture %u doesn't have all blob slots filled.\n", +@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + + goto err; + } + -+err: -+ bootsplash_free_file(fp); -+ return NULL; -+} ++ if (ph->anim_type ++ && ph->num_blobs > 1 ++ && ph->anim_loop < pp->blobs_loaded) ++ have_anim = true; + } + ++ if (!have_anim) ++ /* Disable animation timer if there is nothing to animate */ ++ fp->frame_ms = 0; ++ else ++ /* Enforce minimum delay between frames */ ++ fp->frame_ms = max((u16)20, fp->header->frame_ms); ++ + pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n", + fw->size, + fp->header->num_pics, diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c -index 4d7e0117f653..2ae36949d0e3 100644 +index 07e3a4eab811..76033606ca8a 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" +@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info, + void bootsplash_do_render_pictures(struct fb_info *info, +- const struct splash_file_priv *fp) ++ const struct splash_file_priv *fp, ++ bool is_update) + { + unsigned int i; -@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var, - } - +@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info, + if (pp->blobs_loaded < 1) + continue; --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; -+} -+ +- bp = &pp->blobs[0]; ++ /* Skip static pictures when refreshing animations */ ++ if (ph->anim_type == SPLASH_ANIM_NONE && is_update) ++ continue; + -+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) - } ++ bp = &pp->blobs[pp->anim_nextframe]; + + if (!bp || bp->blob_header->type != 0) + continue; +@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info) + info->fbops->fb_copyarea(info, &area); } } + + -+void bootsplash_do_render_pictures(struct fb_info *info, -+ const struct splash_file_priv *fp) ++void bootsplash_do_step_animations(struct splash_file_priv *fp) +{ + unsigned int i; + ++ /* Step every animation once */ + 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) ++ if (pp->blobs_loaded < 2 ++ || pp->pic_header->anim_loop > pp->blobs_loaded) + 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; ++ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) { ++ pp->anim_nextframe++; ++ if (pp->anim_nextframe >= pp->pic_header->num_blobs) ++ pp->anim_nextframe = pp->pic_header->anim_loop; + } -+ -+ /* 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 +index 71cedcc68933..b3af0a3c6487 100644 +--- a/include/uapi/linux/bootsplash_file.h +++ 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; +@@ -77,7 +77,17 @@ struct splash_file_header { + uint16_t num_blobs; + uint8_t num_pics; + +- uint8_t padding[103]; ++ uint8_t unused_1; + + /* -+ * Number of data packages associated with this picture. -+ * Currently, the only use for more than 1 is for animations. ++ * Milliseconds to wait before painting the next frame in ++ * an animation. ++ * This is actually a minimum, as the system is allowed to ++ * stall for longer between frames. + */ -+ uint8_t num_blobs; -+ -+ uint8_t padding[27]; -+} __attribute__((__packed__)); -+ -+ -+struct splash_blob_header { -+ /* Length of the data block in bytes. */ -+ uint32_t length; ++ uint16_t frame_ms; + ++ uint8_t padding[100]; + } __attribute__((__packed__)); + + +@@ -116,7 +126,23 @@ struct splash_pic_header { + */ + uint16_t position_offset; + +- uint8_t padding[24]; + /* -+ * Type of the contents. -+ * 0 - Raw RGB data. ++ * Animation type. ++ * 0 - off ++ * 1 - forward loop + */ -+ uint16_t type; ++ uint8_t anim_type; + + /* -+ * Picture this blob is associated with. -+ * Blobs will be added to a picture in the order they are -+ * found in the file. ++ * Animation loop point. ++ * Actual meaning depends on animation type: ++ * Type 0 - Unused ++ * 1 - Frame at which to restart the forward loop ++ * (allowing for "intro" frames) + */ -+ uint8_t picture_id; ++ uint8_t anim_loop; + -+ uint8_t padding[9]; -+} __attribute__((__packed__)); ++ uint8_t padding[22]; + } __attribute__((__packed__)); + + +@@ -158,4 +184,9 @@ enum splash_position { + SPLASH_POS_FLAG_CORNER = 0x10, + }; + ++enum splash_anim_type { ++ SPLASH_ANIM_NONE = 0, ++ SPLASH_ANIM_LOOP_FORWARD = 1, ++}; + -+#endif + #endif diff --git a/0008-bootsplash.patch b/0008-bootsplash.patch index 216953762e2e..d6c6db659c56 100644 --- a/0008-bootsplash.patch +++ b/0008-bootsplash.patch @@ -1,66 +1,82 @@ +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 2ebaba16f785..416735ab6dc1 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -105,6 +105,7 @@ + #include <linux/ctype.h> + #include <linux/bsearch.h> + #include <linux/gcd.h> ++#include <linux/bootsplash.h> + + #define MAX_NR_CON_DRIVER 16 + +@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx) + } + + console_blanked = 0; ++ bootsplash_mark_dirty(); + if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) + /* Low-level driver cannot restore -> do it ourselves */ + update_screen(vc); diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c -index 843c5400fefc..815b007f81ca 100644 +index c8642142cfea..13fcaabbc2ca 100644 --- a/drivers/video/fbdev/core/bootsplash.c +++ b/drivers/video/fbdev/core/bootsplash.c -@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info) - - bootsplash_do_render_pictures(info, splash_state.file); +@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void) + && bootsplash_is_enabled(); + } -+ bootsplash_do_render_flush(info); ++void bootsplash_mark_dirty(void) ++{ ++ mutex_lock(&splash_state.data_lock); ++ splash_state.splash_fb = NULL; ++ mutex_unlock(&splash_state.data_lock); ++} + - out: - mutex_unlock(&splash_state.data_lock); - } -diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h -index 71e2a27ac0b8..0acb383aa4e3 100644 ---- a/drivers/video/fbdev/core/bootsplash_internal.h -+++ b/drivers/video/fbdev/core/bootsplash_internal.h -@@ -89,6 +89,7 @@ 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_do_render_flush(struct fb_info *info); + bool bootsplash_is_enabled(void) + { + bool was_enabled; +@@ -206,9 +213,7 @@ void bootsplash_enable(void) + if (!was_enabled) { + /* Force a full redraw when the splash is re-activated */ +- mutex_lock(&splash_state.data_lock); +- splash_state.splash_fb = NULL; +- mutex_unlock(&splash_state.data_lock); ++ bootsplash_mark_dirty(); - void bootsplash_free_file(struct splash_file_priv *fp); -diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c -index 2ae36949d0e3..8c09c306ff67 100644 ---- a/drivers/video/fbdev/core/bootsplash_render.c -+++ b/drivers/video/fbdev/core/bootsplash_render.c -@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info, - pp->pic_header->width, pp->pic_header->height); + schedule_work(&splash_state.work_redraw_vc); } - } -+ -+ -+void bootsplash_do_render_flush(struct fb_info *info) -+{ -+ /* -+ * FB drivers using deferred_io (such as Xen) need to sync the -+ * screen after modifying its contents. When the FB is mmap()ed -+ * from userspace, this happens via a dirty pages callback, but -+ * when modifying the FB from the kernel, there is no such thing. -+ * -+ * So let's issue a fake fb_copyarea (copying the FB onto itself) -+ * to trick the FB driver into syncing the screen. -+ * -+ * A few DRM drivers' FB implementations are broken by not using -+ * deferred_io when they really should - we match on the known -+ * bad ones manually for now. -+ */ -+ if (info->fbdefio -+ || !strcmp(info->fix.id, "astdrmfb") -+ || !strcmp(info->fix.id, "cirrusdrmfb") -+ || !strcmp(info->fix.id, "mgadrmfb")) { -+ struct fb_copyarea area; +@@ -272,9 +277,7 @@ static int splash_resume(struct device *device) + * Force full redraw on resume since we've probably lost the + * framebuffer's contents meanwhile + */ +- mutex_lock(&splash_state.data_lock); +- splash_state.splash_fb = NULL; +- mutex_unlock(&splash_state.data_lock); ++ bootsplash_mark_dirty(); + + if (bootsplash_would_render_now()) + schedule_work(&splash_state.work_redraw_vc); +diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h +index c6dd0b43180d..4075098aaadd 100644 +--- a/include/linux/bootsplash.h ++++ b/include/linux/bootsplash.h +@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info); + + extern bool bootsplash_would_render_now(void); + ++extern void bootsplash_mark_dirty(void); + -+ area.dx = 0; -+ area.dy = 0; -+ area.width = info->var.xres; -+ area.height = info->var.yres; -+ area.sx = 0; -+ area.sy = 0; + extern bool bootsplash_is_enabled(void); + extern void bootsplash_disable(void); + extern void bootsplash_enable(void); +@@ -31,6 +33,8 @@ extern void bootsplash_init(void); + + #define bootsplash_would_render_now() (false) + ++#define bootsplash_mark_dirty() + -+ info->fbops->fb_copyarea(info, &area); -+ } -+} + #define bootsplash_is_enabled() (false) + #define bootsplash_disable() + #define bootsplash_enable() diff --git a/0009-bootsplash.patch b/0009-bootsplash.patch index 7eb54aff7e00..e8cd479312be 100644 --- a/0009-bootsplash.patch +++ b/0009-bootsplash.patch @@ -1,215 +1,42 @@ -diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c -index 8c09c306ff67..07e3a4eab811 100644 ---- a/drivers/video/fbdev/core/bootsplash_render.c -+++ b/drivers/video/fbdev/core/bootsplash_render.c -@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info, - for (i = 0; i < fp->header->num_pics; i++) { - struct splash_blob_priv *bp; - struct splash_pic_priv *pp = &fp->pics[i]; -+ const struct splash_pic_header *ph = pp->pic_header; - long dst_xoff, dst_yoff; +diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c +index f4166263bb3a..a248429194bb 100644 +--- a/drivers/tty/vt/keyboard.c ++++ b/drivers/tty/vt/keyboard.c +@@ -47,6 +47,8 @@ - if (pp->blobs_loaded < 1) -@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info, - if (!bp || bp->blob_header->type != 0) - continue; + #include <asm/irq_regs.h> -- dst_xoff = (info->var.xres - pp->pic_header->width) / 2; -- dst_yoff = (info->var.yres - pp->pic_header->height) / 2; -+ switch (ph->position) { -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT: -+ dst_xoff = 0; -+ dst_yoff = 0; ++#include <linux/bootsplash.h> + -+ dst_xoff += ph->position_offset; -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = 0; -+ -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_yoff = 0; -+ -+ dst_xoff -= ph->position_offset; -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff -= ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ -+ dst_xoff -= ph->position_offset; -+ dst_yoff -= ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ -+ dst_yoff -= ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT: -+ dst_xoff = 0 + ph->position_offset; -+ dst_yoff = info->var.yres - pp->pic_header->height -+ - ph->position_offset; -+ break; -+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT: -+ dst_xoff = 0; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff += ph->position_offset; -+ break; -+ -+ case SPLASH_CORNER_TOP_LEFT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff -= ph->position_offset; -+ dst_yoff -= ph->position_offset; -+ break; -+ case SPLASH_CORNER_TOP: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_yoff -= ph->position_offset; -+ break; -+ case SPLASH_CORNER_TOP_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff += ph->position_offset; -+ dst_yoff -= ph->position_offset; -+ break; -+ case SPLASH_CORNER_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff += ph->position_offset; -+ break; -+ case SPLASH_CORNER_BOTTOM_RIGHT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff += ph->position_offset; -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_CORNER_BOTTOM: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_CORNER_BOTTOM_LEFT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff -= ph->position_offset; -+ dst_yoff += ph->position_offset; -+ break; -+ case SPLASH_CORNER_LEFT: -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ -+ dst_xoff -= ph->position_offset; -+ break; -+ -+ default: -+ /* As a fallback, center the picture. */ -+ dst_xoff = info->var.xres - pp->pic_header->width; -+ dst_xoff /= 2; -+ dst_yoff = info->var.yres - pp->pic_header->height; -+ dst_yoff /= 2; -+ break; -+ } - - if (dst_xoff < 0 - || dst_yoff < 0 -diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h -index 89dc9cca8f0c..71cedcc68933 100644 ---- a/include/uapi/linux/bootsplash_file.h -+++ b/include/uapi/linux/bootsplash_file.h -@@ -91,7 +91,32 @@ struct splash_pic_header { - */ - uint8_t num_blobs; - -- uint8_t padding[27]; -+ /* -+ * Corner to move the picture to / from. -+ * 0x00 - Top left -+ * 0x01 - Top -+ * 0x02 - Top right -+ * 0x03 - Right -+ * 0x04 - Bottom right -+ * 0x05 - Bottom -+ * 0x06 - Bottom left -+ * 0x07 - Left -+ * -+ * Flags: -+ * 0x10 - Calculate offset from the corner towards the center, -+ * rather than from the center towards the corner -+ */ -+ uint8_t position; -+ -+ /* -+ * Pixel offset from the selected position. -+ * Example: If the picture is in the top right corner, it will -+ * be placed position_offset pixels from the top and -+ * position_offset pixels from the right margin. -+ */ -+ uint16_t position_offset; -+ -+ uint8_t padding[24]; - } __attribute__((__packed__)); + extern void ctrl_alt_del(void); + /* +@@ -1353,6 +1355,28 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) + } + #endif -@@ -115,4 +140,22 @@ struct splash_blob_header { - uint8_t padding[9]; - } __attribute__((__packed__)); - -+ -+ -+ -+/* -+ * Enums for on-disk types -+ */ -+enum splash_position { -+ SPLASH_CORNER_TOP_LEFT = 0, -+ SPLASH_CORNER_TOP = 1, -+ SPLASH_CORNER_TOP_RIGHT = 2, -+ SPLASH_CORNER_RIGHT = 3, -+ SPLASH_CORNER_BOTTOM_RIGHT = 4, -+ SPLASH_CORNER_BOTTOM = 5, -+ SPLASH_CORNER_BOTTOM_LEFT = 6, -+ SPLASH_CORNER_LEFT = 7, -+ SPLASH_POS_FLAG_CORNER = 0x10, -+}; ++ /* Trap keys when bootsplash is shown */ ++ if (bootsplash_would_render_now()) { ++ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */ ++ if (keycode >= KEY_F1 && keycode <= KEY_F12) { ++ bootsplash_disable(); ++ ++ /* ++ * No return here since we want to actually ++ * perform the VT switch. ++ */ ++ } else { ++ if (keycode == KEY_ESC) ++ bootsplash_disable(); ++ ++ /* ++ * Just drop any other keys. ++ * Their effect would be hidden by the splash. ++ */ ++ return; ++ } ++ } + - #endif + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* + * This is extended medium raw mode, with keys above 127 diff --git a/0010-bootsplash.patch b/0010-bootsplash.patch index 2785c5e65277..8a3b715ce46a 100644 --- a/0010-bootsplash.patch +++ b/0010-bootsplash.patch @@ -1,327 +1,21 @@ -diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c -index 815b007f81ca..c8642142cfea 100644 ---- a/drivers/video/fbdev/core/bootsplash.c -+++ b/drivers/video/fbdev/core/bootsplash.c -@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored) - console_unlock(); - } - -+static void splash_callback_animation(struct work_struct *ignored) -+{ -+ if (bootsplash_would_render_now()) { -+ /* This will also re-schedule this delayed worker */ -+ splash_callback_redraw_vc(ignored); -+ } -+} -+ - - static bool is_fb_compatible(const struct fb_info *info) - { -@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info) - */ - void bootsplash_render_full(struct fb_info *info) - { -+ bool is_update = false; -+ - mutex_lock(&splash_state.data_lock); - -- if (!is_fb_compatible(info)) -- goto out; -+ /* -+ * If we've painted on this FB recently, we don't have to do -+ * the sanity checks and background drawing again. -+ */ -+ if (splash_state.splash_fb == info) -+ is_update = true; -+ -+ -+ if (!is_update) { -+ /* Check whether we actually support this FB. */ -+ splash_state.splash_fb = NULL; -+ -+ if (!is_fb_compatible(info)) -+ goto out; -+ -+ /* Draw the background only once */ -+ bootsplash_do_render_background(info, splash_state.file); - -- bootsplash_do_render_background(info, splash_state.file); -+ /* Mark this FB as last seen */ -+ splash_state.splash_fb = info; -+ } - -- bootsplash_do_render_pictures(info, splash_state.file); -+ bootsplash_do_render_pictures(info, splash_state.file, is_update); - - bootsplash_do_render_flush(info); - -+ bootsplash_do_step_animations(splash_state.file); -+ -+ /* Schedule update for animated splash screens */ -+ if (splash_state.file->frame_ms > 0) -+ schedule_delayed_work(&splash_state.dwork_animation, -+ msecs_to_jiffies( -+ splash_state.file->frame_ms)); -+ - out: - mutex_unlock(&splash_state.data_lock); - } -@@ -169,8 +204,14 @@ void bootsplash_enable(void) - - was_enabled = test_and_set_bit(0, &splash_state.enabled); - -- if (!was_enabled) -+ if (!was_enabled) { -+ /* Force a full redraw when the splash is re-activated */ -+ mutex_lock(&splash_state.data_lock); -+ splash_state.splash_fb = NULL; -+ mutex_unlock(&splash_state.data_lock); -+ - schedule_work(&splash_state.work_redraw_vc); -+ } - } - - -@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev); - */ - static int splash_resume(struct device *device) - { -+ /* -+ * Force full redraw on resume since we've probably lost the -+ * framebuffer's contents meanwhile -+ */ -+ mutex_lock(&splash_state.data_lock); -+ splash_state.splash_fb = NULL; -+ mutex_unlock(&splash_state.data_lock); -+ - if (bootsplash_would_render_now()) - schedule_work(&splash_state.work_redraw_vc); - -@@ -235,6 +284,7 @@ static int splash_resume(struct device *device) - - static int splash_suspend(struct device *device) - { -+ cancel_delayed_work_sync(&splash_state.dwork_animation); - cancel_work_sync(&splash_state.work_redraw_vc); - - return 0; -@@ -296,6 +346,8 @@ void bootsplash_init(void) - set_bit(0, &splash_state.enabled); - - INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); -+ INIT_DELAYED_WORK(&splash_state.dwork_animation, -+ splash_callback_animation); - - - if (!splash_state.bootfile || !strlen(splash_state.bootfile)) -diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h -index 0acb383aa4e3..b3a74835d90f 100644 ---- a/drivers/video/fbdev/core/bootsplash_internal.h -+++ b/drivers/video/fbdev/core/bootsplash_internal.h -@@ -37,6 +37,8 @@ struct splash_pic_priv { - - struct splash_blob_priv *blobs; - u16 blobs_loaded; -+ -+ u16 anim_nextframe; - }; - - -@@ -45,6 +47,12 @@ struct splash_file_priv { - const struct splash_file_header *header; - - struct splash_pic_priv *pics; -+ -+ /* -+ * A local copy of the frame delay in the header. -+ * We modify it to keep the code simple. -+ */ -+ u16 frame_ms; - }; - - -@@ -71,6 +79,7 @@ struct splash_priv { - struct platform_device *splash_device; - - struct work_struct work_redraw_vc; -+ struct delayed_work dwork_animation; - - /* Splash data structures including lock for everything below */ - struct mutex data_lock; -@@ -88,8 +97,10 @@ struct splash_priv { - 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); -+ const struct splash_file_priv *fp, -+ bool is_update); - void bootsplash_do_render_flush(struct fb_info *info); -+void bootsplash_do_step_animations(struct splash_file_priv *fp); - - - void bootsplash_free_file(struct splash_file_priv *fp); -diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c -index fd807571ab7d..1f661b2d4cc9 100644 ---- a/drivers/video/fbdev/core/bootsplash_load.c -+++ b/drivers/video/fbdev/core/bootsplash_load.c -@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, +diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c +index 3ffc1ce29023..bc6a24c9dfa8 100644 +--- a/drivers/tty/sysrq.c ++++ b/drivers/tty/sysrq.c +@@ -49,6 +49,7 @@ + #include <linux/syscalls.h> + #include <linux/of.h> + #include <linux/rcupdate.h> ++#include <linux/bootsplash.h> + + #include <asm/ptrace.h> + #include <asm/irq_regs.h> +@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key) { - const struct firmware *fw; - struct splash_file_priv *fp; -+ bool have_anim = false; - unsigned int i; - const u8 *walker; - -@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, - goto err; - } - -+ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) { -+ pr_warn("Picture %u: Unsupported animation type %u.\n", -+ i, ph->anim_type); -+ -+ ph->anim_type = SPLASH_ANIM_NONE; -+ } + struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; + schedule_work(SAK_work); + - pp->pic_header = ph; - pp->blobs = vzalloc(ph->num_blobs - * sizeof(struct splash_blob_priv)); -@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, - /* 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]; -+ const struct splash_pic_header *ph = pp->pic_header; - - if (pp->blobs_loaded != pp->pic_header->num_blobs) { - pr_err("Picture %u doesn't have all blob slots filled.\n", -@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, - - goto err; - } -+ -+ if (ph->anim_type -+ && ph->num_blobs > 1 -+ && ph->anim_loop < pp->blobs_loaded) -+ have_anim = true; - } - -+ if (!have_anim) -+ /* Disable animation timer if there is nothing to animate */ -+ fp->frame_ms = 0; -+ else -+ /* Enforce minimum delay between frames */ -+ fp->frame_ms = max((u16)20, fp->header->frame_ms); -+ - pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n", - fw->size, - fp->header->num_pics, -diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c -index 07e3a4eab811..76033606ca8a 100644 ---- a/drivers/video/fbdev/core/bootsplash_render.c -+++ b/drivers/video/fbdev/core/bootsplash_render.c -@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info, - - - void bootsplash_do_render_pictures(struct fb_info *info, -- const struct splash_file_priv *fp) -+ const struct splash_file_priv *fp, -+ bool is_update) - { - unsigned int i; - -@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info, - if (pp->blobs_loaded < 1) - continue; - -- bp = &pp->blobs[0]; -+ /* Skip static pictures when refreshing animations */ -+ if (ph->anim_type == SPLASH_ANIM_NONE && is_update) -+ continue; -+ -+ bp = &pp->blobs[pp->anim_nextframe]; - - if (!bp || bp->blob_header->type != 0) - continue; -@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info) - info->fbops->fb_copyarea(info, &area); - } ++ bootsplash_disable(); } -+ -+ -+void bootsplash_do_step_animations(struct splash_file_priv *fp) -+{ -+ unsigned int i; -+ -+ /* Step every animation once */ -+ for (i = 0; i < fp->header->num_pics; i++) { -+ struct splash_pic_priv *pp = &fp->pics[i]; -+ -+ if (pp->blobs_loaded < 2 -+ || pp->pic_header->anim_loop > pp->blobs_loaded) -+ continue; -+ -+ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) { -+ pp->anim_nextframe++; -+ if (pp->anim_nextframe >= pp->pic_header->num_blobs) -+ pp->anim_nextframe = pp->pic_header->anim_loop; -+ } -+ } -+} -diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h -index 71cedcc68933..b3af0a3c6487 100644 ---- a/include/uapi/linux/bootsplash_file.h -+++ b/include/uapi/linux/bootsplash_file.h -@@ -77,7 +77,17 @@ struct splash_file_header { - uint16_t num_blobs; - uint8_t num_pics; - -- uint8_t padding[103]; -+ uint8_t unused_1; -+ -+ /* -+ * Milliseconds to wait before painting the next frame in -+ * an animation. -+ * This is actually a minimum, as the system is allowed to -+ * stall for longer between frames. -+ */ -+ uint16_t frame_ms; -+ -+ uint8_t padding[100]; - } __attribute__((__packed__)); - - -@@ -116,7 +126,23 @@ struct splash_pic_header { - */ - uint16_t position_offset; - -- uint8_t padding[24]; -+ /* -+ * Animation type. -+ * 0 - off -+ * 1 - forward loop -+ */ -+ uint8_t anim_type; -+ -+ /* -+ * Animation loop point. -+ * Actual meaning depends on animation type: -+ * Type 0 - Unused -+ * 1 - Frame at which to restart the forward loop -+ * (allowing for "intro" frames) -+ */ -+ uint8_t anim_loop; -+ -+ uint8_t padding[22]; - } __attribute__((__packed__)); - - -@@ -158,4 +184,9 @@ enum splash_position { - SPLASH_POS_FLAG_CORNER = 0x10, - }; - -+enum splash_anim_type { -+ SPLASH_ANIM_NONE = 0, -+ SPLASH_ANIM_LOOP_FORWARD = 1, -+}; -+ - #endif + static struct sysrq_key_op sysrq_SAK_op = { + .handler = sysrq_handle_SAK, diff --git a/0011-bootsplash.patch b/0011-bootsplash.patch index d6c6db659c56..add68e7b275c 100644 --- a/0011-bootsplash.patch +++ b/0011-bootsplash.patch @@ -1,82 +1,21 @@ -diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c -index 2ebaba16f785..416735ab6dc1 100644 ---- a/drivers/tty/vt/vt.c -+++ b/drivers/tty/vt/vt.c -@@ -105,6 +105,7 @@ - #include <linux/ctype.h> - #include <linux/bsearch.h> - #include <linux/gcd.h> -+#include <linux/bootsplash.h> - - #define MAX_NR_CON_DRIVER 16 - -@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx) - } - - console_blanked = 0; -+ bootsplash_mark_dirty(); - if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen(vc); -diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c -index c8642142cfea..13fcaabbc2ca 100644 ---- a/drivers/video/fbdev/core/bootsplash.c -+++ b/drivers/video/fbdev/core/bootsplash.c -@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void) - && bootsplash_is_enabled(); - } - -+void bootsplash_mark_dirty(void) -+{ -+ mutex_lock(&splash_state.data_lock); -+ splash_state.splash_fb = NULL; -+ mutex_unlock(&splash_state.data_lock); -+} -+ - bool bootsplash_is_enabled(void) - { - bool was_enabled; -@@ -206,9 +213,7 @@ void bootsplash_enable(void) - - if (!was_enabled) { - /* Force a full redraw when the splash is re-activated */ -- mutex_lock(&splash_state.data_lock); -- splash_state.splash_fb = NULL; -- mutex_unlock(&splash_state.data_lock); -+ bootsplash_mark_dirty(); - - schedule_work(&splash_state.work_redraw_vc); - } -@@ -272,9 +277,7 @@ static int splash_resume(struct device *device) - * Force full redraw on resume since we've probably lost the - * framebuffer's contents meanwhile - */ -- mutex_lock(&splash_state.data_lock); -- splash_state.splash_fb = NULL; -- mutex_unlock(&splash_state.data_lock); -+ bootsplash_mark_dirty(); - - if (bootsplash_would_render_now()) - schedule_work(&splash_state.work_redraw_vc); -diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h -index c6dd0b43180d..4075098aaadd 100644 ---- a/include/linux/bootsplash.h -+++ b/include/linux/bootsplash.h -@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info); - - extern bool bootsplash_would_render_now(void); - -+extern void bootsplash_mark_dirty(void); +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 9a39a6fcfe98..8a9c67e1c5d8 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode) + int y; + int c = scr_readw((u16 *) vc->vc_pos); + ++ /* ++ * Disable the splash here so we don't have to hook into ++ * vt_console_print() in drivers/tty/vt/vt.c ++ * ++ * We'd disable the splash just before the call to ++ * hide_cursor() anyway, so this spot is just fine. ++ */ ++ if (oops_in_progress) ++ bootsplash_disable(); + - extern bool bootsplash_is_enabled(void); - extern void bootsplash_disable(void); - extern void bootsplash_enable(void); -@@ -31,6 +33,8 @@ extern void bootsplash_init(void); - - #define bootsplash_would_render_now() (false) + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); -+#define bootsplash_mark_dirty() -+ - #define bootsplash_is_enabled() (false) - #define bootsplash_disable() - #define bootsplash_enable() + if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) diff --git a/0012-bootsplash.patch b/0012-bootsplash.patch index e8cd479312be..e5c1fd0c8604 100644 --- a/0012-bootsplash.patch +++ b/0012-bootsplash.patch @@ -1,42 +1,321 @@ -diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c -index f4166263bb3a..a248429194bb 100644 ---- a/drivers/tty/vt/keyboard.c -+++ b/drivers/tty/vt/keyboard.c -@@ -47,6 +47,8 @@ - - #include <asm/irq_regs.h> - -+#include <linux/bootsplash.h> -+ - extern void ctrl_alt_del(void); - - /* -@@ -1353,6 +1355,28 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) - } - #endif - -+ /* Trap keys when bootsplash is shown */ -+ if (bootsplash_would_render_now()) { -+ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */ -+ if (keycode >= KEY_F1 && keycode <= KEY_F12) { -+ bootsplash_disable(); -+ -+ /* -+ * No return here since we want to actually -+ * perform the VT switch. -+ */ -+ } else { -+ if (keycode == KEY_ESC) -+ bootsplash_disable(); -+ -+ /* -+ * Just drop any other keys. -+ * Their effect would be hidden by the splash. -+ */ -+ return; -+ } -+ } -+ - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* - * This is extended medium raw mode, with keys above 127 +diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash +new file mode 100644 +index 000000000000..742c7b035ded +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-platform-bootsplash +@@ -0,0 +1,11 @@ ++What: /sys/devices/platform/bootsplash.0/enabled ++Date: Oct 2017 ++KernelVersion: 4.14 ++Contact: Max Staudt <mstaudt@suse.de> ++Description: ++ Can be set and read. ++ ++ 0: Splash is disabled. ++ 1: Splash is shown whenever fbcon would show a text console ++ (i.e. no graphical application is running), and a splash ++ file is loaded. +diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst +new file mode 100644 +index 000000000000..611f0c558925 +--- /dev/null ++++ b/Documentation/bootsplash.rst +@@ -0,0 +1,285 @@ ++==================== ++The Linux bootsplash ++==================== ++ ++:Date: November, 2017 ++:Author: Max Staudt <mstaudt@suse.de> ++ ++ ++The Linux bootsplash is a graphical replacement for the '``quiet``' boot ++option, typically showing a logo and a spinner animation as the system starts. ++ ++Currently, it is a part of the Framebuffer Console support, and can be found ++as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long ++as it is enabled, it hijacks fbcon's output and draws a splash screen instead. ++ ++Purely compiling in the bootsplash will not render it functional - to actually ++render a splash, you will also need a splash theme file. See the example ++utility and script in ``tools/bootsplash`` for a live demo. ++ ++ ++ ++Motivation ++========== ++ ++- The '``quiet``' boot option only suppresses most messages during boot, but ++ errors are still shown. ++ ++- A user space implementation can only show a logo once user space has been ++ initialized far enough to allow this. A kernel splash can display a splash ++ immediately as soon as fbcon can be displayed. ++ ++- Implementing a splash screen in user space (e.g. Plymouth) is problematic ++ due to resource conflicts. ++ ++ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb) ++ open, then most DRM drivers can't replace it because the address space is ++ still busy - thus leading to a VRAM reservation error. ++ ++ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750 ++ ++ ++ ++Command line arguments ++====================== ++ ++``bootsplash.bootfile`` ++ Which file in the initramfs to load. ++ ++ The splash theme is loaded via request_firmware(), thus to load ++ ``/lib/firmware/bootsplash/mytheme`` pass the command line: ++ ++ ``bootsplash.bootfile=bootsplash/mytheme`` ++ ++ Note: The splash file *has to be* in the initramfs, as it needs to be ++ available when the splash is initialized early on. ++ ++ Default: none, i.e. a non-functional splash, falling back to showing text. ++ ++ ++ ++sysfs run-time configuration ++============================ ++ ++``/sys/devices/platform/bootsplash.0/enabled`` ++ Enable/disable the bootsplash. ++ The system boots with this set to 1, but will not show a splash unless ++ a splash theme file is also loaded. ++ ++ ++ ++Kconfig ++======= ++ ++``BOOTSPLASH`` ++ Whether to compile in bootsplash support ++ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``) ++ ++ ++ ++Bootsplash file format ++====================== ++ ++A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE`` ++or specified on the command line as ``bootsplash.bootfile`` will be loaded ++and displayed as soon as fbcon is initialized. ++ ++ ++Main blocks ++----------- ++ ++There are 3 main blocks in each file: ++ ++ - one File header ++ - n Picture headers ++ - m (Blob header + payload) blocks ++ ++ ++Structures ++---------- ++ ++The on-disk structures are defined in ++``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks: ++ ++ - ``struct splash_file_header`` ++ ++ Represents the file header, with splash-wide information including: ++ ++ - The magic string "``Linux bootsplash``" on big-endian platforms ++ (the reverse on little endian) ++ - The file format version (for incompatible updates, hopefully never) ++ - The background color ++ - Number of picture and blob blocks ++ - Animation speed (we only allow one delay for all animations) ++ ++ The file header is followed by the first picture header. ++ ++ ++ - ``struct splash_picture_header`` ++ ++ Represents an object (picture) drawn on screen, including its immutable ++ properties: ++ - Width, height ++ - Positioning relative to screen corners or in the center ++ - Animation, if any ++ - Animation type ++ - Number of blobs ++ ++ The picture header is followed by another picture header, up until n ++ picture headers (as defined in the file header) have been read. Then, ++ the (blob header, payload) pairs follow. ++ ++ ++ - ``struct splash_blob_header`` ++ (followed by payload) ++ ++ Represents one raw data stream. So far, only picture data is defined. ++ ++ The blob header is followed by a payload, then padding to n*16 bytes, ++ then (if further blobs are defined in the file header) a further blob ++ header. ++ ++ ++Alignment ++--------- ++ ++The bootsplash file is designed to be loaded into memory as-is. ++ ++All structures are a multiple of 16 bytes long, all elements therein are ++aligned to multiples of their length, and the payloads are always padded ++up to multiples of 16 bytes. This is to allow aligned accesses in all ++cases while still simply mapping the structures over an in-memory copy of ++the bootsplash file. ++ ++ ++Further information ++------------------- ++ ++Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further ++details and possible values in the file. ++ ++ ++ ++Hooks - how the bootsplash is integrated ++======================================== ++ ++``drivers/video/fbdev/core/fbcon.c`` ++ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default ++ bootsplash file or the one specified on the kernel command line. ++ ++ ``fbcon_switch()`` draws the bootsplash when it's active, and is also ++ one of the callers of ``set_blitting_type()``. ++ ++ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the ++ bootsplash is active, overriding the text rendering functions. ++ ++ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is ++ being printed in order to make a kernel panic visible. ++ ++``drivers/video/fbdev/core/dummyblit.c`` ++ This contains the dummy text rendering functions used to suppress text ++ output while the bootsplash is shown. ++ ++``drivers/tty/vt/keyboard.c`` ++ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user ++ presses ESC or F1-F12 (changing VT). This is to provide a built-in way ++ of disabling the splash manually at any time. ++ ++ ++ ++FAQ: Frequently Asked Questions ++=============================== ++ ++I want to see the log! How do I show the log? ++--------------------------------------------- ++ ++Press ESC while the splash is shown, or remove the ``bootsplash.bootfile`` ++parameter from the kernel cmdline. Without that parameter, the bootsplash ++will boot disabled. ++ ++ ++Why use FB instead of modern DRM/KMS? ++------------------------------------- ++ ++This is a semantic problem: ++ - What memory to draw the splash to? ++ - And what mode will the screen be set to? ++ ++Using the fbdev emulation solves these issues. ++ ++Let's start from a bare KMS system, without fbcon, and without fbdev ++emulation. In this case, as long as userspace doesn't open the KMS ++device, the state of the screen is undefined. No framebuffer is ++allocated in video RAM, and no particular mode is set. ++ ++In this case, we'd have to allocate a framebuffer to show the splash, ++and set our mode ourselves. This either wastes a screenful of video RAM ++if the splash is to co-exist with the userspace program's own allocated ++framebuffer, or there is a flicker as we deactivate and delete the ++bootsplash's framebuffer and hand control over to userspace. Since we ++may set a different mode than userspace, we'd also have flicker due ++to mode switching. ++ ++This logic is already contained in every KMS driver that performs fbdev ++emulation. So we might as well use that. And the correct API to do so is ++fbdev. Plus, we get compatibility with old, pure fbdev drivers for free. ++With the fbdev emulation, there is *always* a well-defined framebuffer ++to draw on. And the selection of mode has already been done by the ++graphics driver, so we don't need to reinvent that wheel, either. ++Finally, if userspace decides to use /dev/fbX, we don't have to worry ++about wasting video RAM, either. ++ ++ ++Why is the bootsplash integrated in fbcon? ++------------------------------------------ ++ ++Right now, the bootsplash is drawn from within fbcon, as this allows us ++to easily know *when* to draw - i.e. when we're safe from fbcon and ++userspace drawing all over our beautiful splash logo. ++ ++Separating them is not easy - see the to-do list below. ++ ++ ++ ++TO DO list for future development ++================================= ++ ++Second enable/disable switch for the system ++------------------------------------------- ++ ++It may be helpful to differentiate between the system and the user ++switching off the bootsplash. Thus, the system may make it disappear and ++reappear e.g. for a password prompt, yet once the user has pressed ESC, ++it could stay gone. ++ ++ ++Fix buggy DRM/KMS drivers ++------------------------- ++ ++Currently, the splash code manually checks for fbdev emulation provided by ++the ast, cirrus, and mgag200 DRM/KMS drivers. ++These drivers use a manual mechanism similar to deferred I/O for their FB ++emulation, and thus need to be manually flushed onto the screen in the same ++way. ++ ++This may be improved upon in several ways: ++ ++1. Changing these drivers to expose the fbdev BO's memory directly, like ++ bochsdrmfb does. ++2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the ++ framebuffer once the bootsplash has been drawn into it. ++ ++ ++Separating from fbcon ++--------------------- ++ ++Separating these two components would yield independence from fbcon being ++compiled into the kernel, and thus lowering code size in embedded ++applications. ++ ++To do this cleanly will involve a clean separation of users of an FB device ++within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the ++legacy fbcon code and VT code co-operate to switch between fbcon and ++userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer ++between these components ensues refactoring of old code and checking for ++correct locking. +diff --git a/MAINTAINERS b/MAINTAINERS +index 5c237445761e..7ffac272434e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2709,6 +2709,8 @@ BOOTSPLASH + M: Max Staudt <mstaudt@suse.de> + L: linux-fbdev@vger.kernel.org + S: Maintained ++F: Documentation/ABI/testing/sysfs-platform-bootsplash ++F: Documentation/bootsplash.rst + F: drivers/video/fbdev/core/bootsplash*.* + F: drivers/video/fbdev/core/dummycon.c + F: include/linux/bootsplash.h diff --git a/0013-bootsplash.patch b/0013-bootsplash.patch index 8a3b715ce46a..8e87eb463187 100644 --- a/0013-bootsplash.patch +++ b/0013-bootsplash.patch @@ -1,21 +1,129 @@ -diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c -index 3ffc1ce29023..bc6a24c9dfa8 100644 ---- a/drivers/tty/sysrq.c -+++ b/drivers/tty/sysrq.c -@@ -49,6 +49,7 @@ - #include <linux/syscalls.h> - #include <linux/of.h> - #include <linux/rcupdate.h> -+#include <linux/bootsplash.h> +diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash +index 742c7b035ded..f8f4b259220e 100644 +--- a/Documentation/ABI/testing/sysfs-platform-bootsplash ++++ b/Documentation/ABI/testing/sysfs-platform-bootsplash +@@ -9,3 +9,35 @@ Description: + 1: Splash is shown whenever fbcon would show a text console + (i.e. no graphical application is running), and a splash + file is loaded. ++ ++What: /sys/devices/platform/bootsplash.0/drop_splash ++Date: Oct 2017 ++KernelVersion: 4.14 ++Contact: Max Staudt <mstaudt@suse.de> ++Description: ++ Can only be set. ++ ++ Any value written will cause the current splash theme file ++ to be unloaded and the text console to be redrawn. ++ ++What: /sys/devices/platform/bootsplash.0/load_file ++Date: Oct 2017 ++KernelVersion: 4.14 ++Contact: Max Staudt <mstaudt@suse.de> ++Description: ++ Can only be set. ++ ++ Any value written will cause the splash to be disabled and ++ internal memory structures to be freed. ++ ++ A firmware path written will cause a new theme file to be ++ loaded and the current bootsplash to be replaced. ++ The current enabled/disabled status is not touched. ++ If the splash is already active, it will be redrawn. ++ ++ The path has to be a path in /lib/firmware since ++ request_firmware() is used to fetch the data. ++ ++ When setting the splash from the shell, echo -n has to be ++ used as any trailing '\n' newline will be interpreted as ++ part of the path. +diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst +index 611f0c558925..b35aba5093e8 100644 +--- a/Documentation/bootsplash.rst ++++ b/Documentation/bootsplash.rst +@@ -67,6 +67,14 @@ sysfs run-time configuration + a splash theme file is also loaded. + - #include <asm/ptrace.h> - #include <asm/irq_regs.h> -@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key) - { - struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; - schedule_work(SAK_work); -+ -+ bootsplash_disable(); ++``/sys/devices/platform/bootsplash.0/drop_splash`` ++ Unload splash data and free memory. ++ ++``/sys/devices/platform/bootsplash.0/load_file`` ++ Load a splash file from ``/lib/firmware/``. ++ Note that trailing newlines will be interpreted as part of the file name. ++ ++ + + Kconfig + ======= +diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c +index 13fcaabbc2ca..16cb0493629d 100644 +--- a/drivers/video/fbdev/core/bootsplash.c ++++ b/drivers/video/fbdev/core/bootsplash.c +@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device, + return count; } - static struct sysrq_key_op sysrq_SAK_op = { - .handler = sysrq_handle_SAK, + ++static ssize_t splash_store_drop_splash(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct splash_file_priv *fp; ++ ++ if (!buf || !count || !splash_state.file) ++ return count; ++ ++ mutex_lock(&splash_state.data_lock); ++ fp = splash_state.file; ++ splash_state.file = NULL; ++ mutex_unlock(&splash_state.data_lock); ++ ++ /* Redraw the text console */ ++ schedule_work(&splash_state.work_redraw_vc); ++ ++ bootsplash_free_file(fp); ++ ++ return count; ++} ++ ++static ssize_t splash_store_load_file(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct splash_file_priv *fp, *fp_old; ++ ++ if (!count) ++ return 0; ++ ++ fp = bootsplash_load_firmware(&splash_state.splash_device->dev, ++ buf); ++ ++ if (!fp) ++ return -ENXIO; ++ ++ mutex_lock(&splash_state.data_lock); ++ fp_old = splash_state.file; ++ splash_state.splash_fb = NULL; ++ splash_state.file = fp; ++ mutex_unlock(&splash_state.data_lock); ++ ++ /* Update the splash or text console */ ++ schedule_work(&splash_state.work_redraw_vc); ++ ++ bootsplash_free_file(fp_old); ++ return count; ++} ++ + static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled); ++static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash); ++static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file); + + + static struct attribute *splash_dev_attrs[] = { + &dev_attr_enabled.attr, ++ &dev_attr_drop_splash.attr, ++ &dev_attr_load_file.attr, + NULL + }; + diff --git a/0014-bootsplash.patch b/0014-bootsplash.patch index add68e7b275c..5d8ea1fe295c 100644 --- a/0014-bootsplash.patch +++ b/0014-bootsplash.patch @@ -1,21 +1,511 @@ -diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c -index 9a39a6fcfe98..8a9c67e1c5d8 100644 ---- a/drivers/video/fbdev/core/fbcon.c -+++ b/drivers/video/fbdev/core/fbcon.c -@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode) - int y; - int c = scr_readw((u16 *) vc->vc_pos); +diff --git a/MAINTAINERS b/MAINTAINERS +index 7ffac272434e..ddff07cd794c 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2715,6 +2715,7 @@ 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 ++F: tools/bootsplash/* -+ /* -+ * Disable the splash here so we don't have to hook into -+ * vt_console_print() in drivers/tty/vt/vt.c -+ * -+ * We'd disable the splash just before the call to -+ * hide_cursor() anyway, so this spot is just fine. -+ */ -+ if (oops_in_progress) -+ bootsplash_disable(); -+ - ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); - - if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) + BPF (Safe dynamic programs and tools) + M: Alexei Starovoitov <ast@kernel.org> +diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore +new file mode 100644 +index 000000000000..091b99a17567 +--- /dev/null ++++ b/tools/bootsplash/.gitignore +@@ -0,0 +1 @@ ++bootsplash-packer +diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile +new file mode 100644 +index 000000000000..0ad8e8a84942 +--- /dev/null ++++ b/tools/bootsplash/Makefile +@@ -0,0 +1,9 @@ ++CC := $(CROSS_COMPILE)gcc ++CFLAGS := -I../../usr/include ++ ++PROGS := bootsplash-packer ++ ++all: $(PROGS) ++ ++clean: ++ rm -fr $(PROGS) +diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c +new file mode 100644 +index 000000000000..ffb6a8b69885 +--- /dev/null ++++ b/tools/bootsplash/bootsplash-packer.c +@@ -0,0 +1,471 @@ ++/* ++ * Kernel based bootsplash. ++ * ++ * (Splash file packer tool) ++ * ++ * Authors: ++ * Max Staudt <mstaudt@suse.de> ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#include <endian.h> ++#include <getopt.h> ++#include <stdint.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++#include <linux/bootsplash_file.h> ++ ++ ++static void print_help(char *progname) ++{ ++ printf("Usage: %s [OPTIONS] outfile\n", progname); ++ printf("\n" ++ "Options, executed in order given:\n" ++ " -h, --help Print this help message\n" ++ "\n" ++ " --bg_red <u8> Background color (red part)\n" ++ " --bg_green <u8> Background color (green part)\n" ++ " --bg_blue <u8> Background color (blue part)\n" ++ " --bg_reserved <u8> (do not use)\n" ++ " --frame_ms <u16> Minimum milliseconds between animation steps\n" ++ "\n" ++ " --picture Start describing the next picture\n" ++ " --pic_width <u16> Picture width in pixels\n" ++ " --pic_height <u16> Picture height in pixels\n" ++ " --pic_position <u8> Coarse picture placement:\n" ++ " 0x00 - Top left\n" ++ " 0x01 - Top\n" ++ " 0x02 - Top right\n" ++ " 0x03 - Right\n" ++ " 0x04 - Bottom right\n" ++ " 0x05 - Bottom\n" ++ " 0x06 - Bottom left\n" ++ " 0x07 - Left\n" ++ "\n" ++ " Flags:\n" ++ " 0x10 - Calculate offset from corner towards center,\n" ++ " rather than from center towards corner\n" ++ " --pic_position_offset <u16> Distance from base position in pixels\n" ++ " --pic_anim_type <u8> Animation type:\n" ++ " 0 - None\n" ++ " 1 - Forward loop\n" ++ " --pic_anim_loop <u8> Loop point for animation\n" ++ "\n" ++ " --blob <filename> Include next data stream\n" ++ " --blob_type <u16> Type of data\n" ++ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n" ++ " (default: number of last --picture)\n" ++ "\n"); ++ printf("This tool will write %s files.\n\n", ++#if __BYTE_ORDER == __BIG_ENDIAN ++ "Big Endian (BE)"); ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++ "Little Endian (LE)"); ++#else ++#error ++#endif ++} ++ ++ ++struct blob_entry { ++ struct blob_entry *next; ++ ++ char *fn; ++ ++ struct splash_blob_header header; ++}; ++ ++ ++static void dump_file_header(struct splash_file_header *h) ++{ ++ printf(" --- File header ---\n"); ++ printf("\n"); ++ printf(" version: %5u\n", h->version); ++ printf("\n"); ++ printf(" bg_red: %5u\n", h->bg_red); ++ printf(" bg_green: %5u\n", h->bg_green); ++ printf(" bg_blue: %5u\n", h->bg_blue); ++ printf(" bg_reserved: %5u\n", h->bg_reserved); ++ printf("\n"); ++ printf(" num_blobs: %5u\n", h->num_blobs); ++ printf(" num_pics: %5u\n", h->num_pics); ++ printf("\n"); ++ printf(" frame_ms: %5u\n", h->frame_ms); ++ printf("\n"); ++} ++ ++static void dump_pic_header(struct splash_pic_header *ph) ++{ ++ printf(" --- Picture header ---\n"); ++ printf("\n"); ++ printf(" width: %5u\n", ph->width); ++ printf(" height: %5u\n", ph->height); ++ printf("\n"); ++ printf(" num_blobs: %5u\n", ph->num_blobs); ++ printf("\n"); ++ printf(" position: %0x3x\n", ph->position); ++ printf(" position_offset: %5u\n", ph->position_offset); ++ printf("\n"); ++ printf(" anim_type: %5u\n", ph->anim_type); ++ printf(" anim_loop: %5u\n", ph->anim_loop); ++ printf("\n"); ++} ++ ++static void dump_blob(struct blob_entry *b) ++{ ++ printf(" --- Blob header ---\n"); ++ printf("\n"); ++ printf(" length: %7u\n", b->header.length); ++ printf(" type: %7u\n", b->header.type); ++ printf("\n"); ++ printf(" picture_id: %7u\n", b->header.picture_id); ++ printf("\n"); ++} ++ ++ ++#define OPT_MAX(var, max) \ ++ do { \ ++ if ((var) > max) { \ ++ fprintf(stderr, "--%s: Invalid value\n", \ ++ long_options[option_index].name); \ ++ break; \ ++ } \ ++ } while (0) ++ ++static struct option long_options[] = { ++ {"help", 0, 0, 'h'}, ++ {"bg_red", 1, 0, 10001}, ++ {"bg_green", 1, 0, 10002}, ++ {"bg_blue", 1, 0, 10003}, ++ {"bg_reserved", 1, 0, 10004}, ++ {"frame_ms", 1, 0, 10005}, ++ {"picture", 0, 0, 20000}, ++ {"pic_width", 1, 0, 20001}, ++ {"pic_height", 1, 0, 20002}, ++ {"pic_position", 1, 0, 20003}, ++ {"pic_position_offset", 1, 0, 20004}, ++ {"pic_anim_type", 1, 0, 20005}, ++ {"pic_anim_loop", 1, 0, 20006}, ++ {"blob", 1, 0, 30000}, ++ {"blob_type", 1, 0, 30001}, ++ {"blob_picture_id", 1, 0, 30002}, ++ {NULL, 0, NULL, 0} ++}; ++ ++ ++int main(int argc, char **argv) ++{ ++ FILE *of; ++ char *ofn; ++ int c; ++ int option_index = 0; ++ ++ unsigned long ul; ++ struct splash_file_header fh = {}; ++ struct splash_pic_header ph[255]; ++ struct blob_entry *blob_first = NULL; ++ struct blob_entry *blob_last = NULL; ++ struct blob_entry *blob_cur = NULL; ++ ++ if (argc < 2) { ++ print_help(argv[0]); ++ return EXIT_FAILURE; ++ } ++ ++ ++ /* Parse and and execute user commands */ ++ while ((c = getopt_long(argc, argv, "h", ++ long_options, &option_index)) != -1) { ++ switch (c) { ++ case 10001: /* bg_red */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ fh.bg_red = ul; ++ break; ++ case 10002: /* bg_green */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ fh.bg_green = ul; ++ break; ++ case 10003: /* bg_blue */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ fh.bg_blue = ul; ++ break; ++ case 10004: /* bg_reserved */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ fh.bg_reserved = ul; ++ break; ++ case 10005: /* frame_ms */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 65535); ++ fh.frame_ms = ul; ++ break; ++ ++ ++ case 20000: /* picture */ ++ if (fh.num_pics >= 255) { ++ fprintf(stderr, "--%s: Picture array full\n", ++ long_options[option_index].name); ++ break; ++ } ++ ++ fh.num_pics++; ++ break; ++ ++ case 20001: /* pic_width */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 65535); ++ ph[fh.num_pics - 1].width = ul; ++ break; ++ ++ case 20002: /* pic_height */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 65535); ++ ph[fh.num_pics - 1].height = ul; ++ break; ++ ++ case 20003: /* pic_position */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ ph[fh.num_pics - 1].position = ul; ++ break; ++ ++ case 20004: /* pic_position_offset */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ ph[fh.num_pics - 1].position_offset = ul; ++ break; ++ ++ case 20005: /* pic_anim_type */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ ph[fh.num_pics - 1].anim_type = ul; ++ break; ++ ++ case 20006: /* pic_anim_loop */ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ ph[fh.num_pics - 1].anim_loop = ul; ++ break; ++ ++ ++ case 30000: /* blob */ ++ if (fh.num_blobs >= 65535) { ++ fprintf(stderr, "--%s: Blob array full\n", ++ long_options[option_index].name); ++ break; ++ } ++ ++ blob_cur = calloc(1, sizeof(struct blob_entry)); ++ if (!blob_cur) { ++ fprintf(stderr, "--%s: Out of memory\n", ++ long_options[option_index].name); ++ break; ++ } ++ ++ blob_cur->fn = optarg; ++ if (fh.num_pics) ++ blob_cur->header.picture_id = fh.num_pics - 1; ++ ++ if (!blob_first) ++ blob_first = blob_cur; ++ if (blob_last) ++ blob_last->next = blob_cur; ++ blob_last = blob_cur; ++ fh.num_blobs++; ++ break; ++ ++ case 30001: /* blob_type */ ++ if (!blob_cur) { ++ fprintf(stderr, "--%s: No blob selected\n", ++ long_options[option_index].name); ++ break; ++ } ++ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ blob_cur->header.type = ul; ++ break; ++ ++ case 30002: /* blob_picture_id */ ++ if (!blob_cur) { ++ fprintf(stderr, "--%s: No blob selected\n", ++ long_options[option_index].name); ++ break; ++ } ++ ++ ul = strtoul(optarg, NULL, 0); ++ OPT_MAX(ul, 255); ++ blob_cur->header.picture_id = ul; ++ break; ++ ++ ++ ++ case 'h': ++ case '?': ++ default: ++ print_help(argv[0]); ++ goto EXIT; ++ } /* switch (c) */ ++ } /* while ((c = getopt_long(...)) != -1) */ ++ ++ /* Consume and drop lone arguments */ ++ while (optind < argc) { ++ ofn = argv[optind]; ++ optind++; ++ } ++ ++ ++ /* Read file lengths */ ++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) { ++ FILE *f; ++ long pos; ++ int i; ++ ++ if (!blob_cur->fn) ++ continue; ++ ++ f = fopen(blob_cur->fn, "rb"); ++ if (!f) ++ goto ERR_FILE_LEN; ++ ++ if (fseek(f, 0, SEEK_END)) ++ goto ERR_FILE_LEN; ++ ++ pos = ftell(f); ++ if (pos < 0 || pos > (1 << 30)) ++ goto ERR_FILE_LEN; ++ ++ blob_cur->header.length = pos; ++ ++ fclose(f); ++ continue; ++ ++ERR_FILE_LEN: ++ fprintf(stderr, "Error getting file length (or too long): %s\n", ++ blob_cur->fn); ++ if (f) ++ fclose(f); ++ continue; ++ } ++ ++ ++ /* Set magic headers */ ++#if __BYTE_ORDER == __BIG_ENDIAN ++ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16); ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16); ++#else ++#error ++#endif ++ fh.version = BOOTSPLASH_VERSION; ++ ++ /* Set blob counts */ ++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) { ++ if (blob_cur->header.picture_id < fh.num_pics) ++ ph[blob_cur->header.picture_id].num_blobs++; ++ } ++ ++ ++ /* Dump structs */ ++ dump_file_header(&fh); ++ ++ for (ul = 0; ul < fh.num_pics; ul++) ++ dump_pic_header(&ph[ul]); ++ ++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) ++ dump_blob(blob_cur); ++ ++ ++ /* Write to file */ ++ printf("Writing splash to file: %s\n", ofn); ++ of = fopen(ofn, "wb"); ++ if (!of) ++ goto ERR_WRITING; ++ ++ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1) ++ goto ERR_WRITING; ++ ++ for (ul = 0; ul < fh.num_pics; ul++) { ++ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of) ++ != 1) ++ goto ERR_WRITING; ++ } ++ ++ blob_cur = blob_first; ++ while (blob_cur) { ++ struct blob_entry *blob_old = blob_cur; ++ FILE *f; ++ char *buf[256]; ++ uint32_t left; ++ ++ if (fwrite(&blob_cur->header, ++ sizeof(struct splash_blob_header), 1, of) != 1) ++ goto ERR_WRITING; ++ ++ if (!blob_cur->header.length || !blob_cur->fn) ++ continue; ++ ++ f = fopen(blob_cur->fn, "rb"); ++ if (!f) ++ goto ERR_FILE_COPY; ++ ++ left = blob_cur->header.length; ++ while (left >= sizeof(buf)) { ++ if (fread(buf, sizeof(buf), 1, f) != 1) ++ goto ERR_FILE_COPY; ++ if (fwrite(buf, sizeof(buf), 1, of) != 1) ++ goto ERR_FILE_COPY; ++ left -= sizeof(buf); ++ } ++ if (left) { ++ if (fread(buf, left, 1, f) != 1) ++ goto ERR_FILE_COPY; ++ if (fwrite(buf, left, 1, of) != 1) ++ goto ERR_FILE_COPY; ++ } ++ ++ /* Pad data stream to 16 bytes */ ++ if (left % 16) { ++ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", ++ 16 - (left % 16), 1, of) != 1) ++ goto ERR_FILE_COPY; ++ } ++ ++ fclose(f); ++ blob_cur = blob_cur->next; ++ free(blob_old); ++ continue; ++ ++ERR_FILE_COPY: ++ if (f) ++ fclose(f); ++ goto ERR_WRITING; ++ } ++ ++ fclose(of); ++ ++EXIT: ++ return EXIT_SUCCESS; ++ ++ ++ERR_WRITING: ++ fprintf(stderr, "Error writing splash.\n"); ++ fprintf(stderr, "The output file is probably corrupt.\n"); ++ if (of) ++ fclose(of); ++ ++ while (blob_cur) { ++ struct blob_entry *blob_old = blob_cur; ++ ++ blob_cur = blob_cur->next; ++ free(blob_old); ++ } ++ ++ return EXIT_FAILURE; ++} diff --git a/0015-bootsplash.patch b/0015-bootsplash.patch index e5c1fd0c8604..0924d29e7d48 100644 --- a/0015-bootsplash.patch +++ b/0015-bootsplash.patch @@ -1,321 +1,102 @@ -diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash -new file mode 100644 -index 000000000000..742c7b035ded ---- /dev/null -+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash -@@ -0,0 +1,11 @@ -+What: /sys/devices/platform/bootsplash.0/enabled -+Date: Oct 2017 -+KernelVersion: 4.14 -+Contact: Max Staudt <mstaudt@suse.de> -+Description: -+ Can be set and read. -+ -+ 0: Splash is disabled. -+ 1: Splash is shown whenever fbcon would show a text console -+ (i.e. no graphical application is running), and a splash -+ file is loaded. diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst -new file mode 100644 -index 000000000000..611f0c558925 ---- /dev/null +index b35aba5093e8..d4f132eca615 100644 +--- a/Documentation/bootsplash.rst +++ b/Documentation/bootsplash.rst -@@ -0,0 +1,285 @@ -+==================== -+The Linux bootsplash -+==================== -+ -+:Date: November, 2017 -+:Author: Max Staudt <mstaudt@suse.de> -+ -+ -+The Linux bootsplash is a graphical replacement for the '``quiet``' boot -+option, typically showing a logo and a spinner animation as the system starts. -+ -+Currently, it is a part of the Framebuffer Console support, and can be found -+as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long -+as it is enabled, it hijacks fbcon's output and draws a splash screen instead. -+ -+Purely compiling in the bootsplash will not render it functional - to actually -+render a splash, you will also need a splash theme file. See the example -+utility and script in ``tools/bootsplash`` for a live demo. -+ -+ -+ -+Motivation -+========== -+ -+- The '``quiet``' boot option only suppresses most messages during boot, but -+ errors are still shown. -+ -+- A user space implementation can only show a logo once user space has been -+ initialized far enough to allow this. A kernel splash can display a splash -+ immediately as soon as fbcon can be displayed. -+ -+- Implementing a splash screen in user space (e.g. Plymouth) is problematic -+ due to resource conflicts. -+ -+ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb) -+ open, then most DRM drivers can't replace it because the address space is -+ still busy - thus leading to a VRAM reservation error. -+ -+ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750 -+ -+ -+ -+Command line arguments -+====================== -+ -+``bootsplash.bootfile`` -+ Which file in the initramfs to load. -+ -+ The splash theme is loaded via request_firmware(), thus to load -+ ``/lib/firmware/bootsplash/mytheme`` pass the command line: -+ -+ ``bootsplash.bootfile=bootsplash/mytheme`` -+ -+ Note: The splash file *has to be* in the initramfs, as it needs to be -+ available when the splash is initialized early on. -+ -+ Default: none, i.e. a non-functional splash, falling back to showing text. -+ -+ -+ -+sysfs run-time configuration -+============================ -+ -+``/sys/devices/platform/bootsplash.0/enabled`` -+ Enable/disable the bootsplash. -+ The system boots with this set to 1, but will not show a splash unless -+ a splash theme file is also loaded. -+ -+ -+ -+Kconfig -+======= -+ -+``BOOTSPLASH`` -+ Whether to compile in bootsplash support -+ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``) -+ -+ -+ -+Bootsplash file format -+====================== -+ -+A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE`` -+or specified on the command line as ``bootsplash.bootfile`` will be loaded -+and displayed as soon as fbcon is initialized. -+ -+ -+Main blocks -+----------- -+ -+There are 3 main blocks in each file: -+ -+ - one File header -+ - n Picture headers -+ - m (Blob header + payload) blocks -+ -+ -+Structures -+---------- -+ -+The on-disk structures are defined in -+``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks: -+ -+ - ``struct splash_file_header`` -+ -+ Represents the file header, with splash-wide information including: -+ -+ - The magic string "``Linux bootsplash``" on big-endian platforms -+ (the reverse on little endian) -+ - The file format version (for incompatible updates, hopefully never) -+ - The background color -+ - Number of picture and blob blocks -+ - Animation speed (we only allow one delay for all animations) -+ -+ The file header is followed by the first picture header. -+ -+ -+ - ``struct splash_picture_header`` -+ -+ Represents an object (picture) drawn on screen, including its immutable -+ properties: -+ - Width, height -+ - Positioning relative to screen corners or in the center -+ - Animation, if any -+ - Animation type -+ - Number of blobs -+ -+ The picture header is followed by another picture header, up until n -+ picture headers (as defined in the file header) have been read. Then, -+ the (blob header, payload) pairs follow. -+ -+ -+ - ``struct splash_blob_header`` -+ (followed by payload) -+ -+ Represents one raw data stream. So far, only picture data is defined. -+ -+ The blob header is followed by a payload, then padding to n*16 bytes, -+ then (if further blobs are defined in the file header) a further blob -+ header. -+ -+ -+Alignment -+--------- -+ -+The bootsplash file is designed to be loaded into memory as-is. -+ -+All structures are a multiple of 16 bytes long, all elements therein are -+aligned to multiples of their length, and the payloads are always padded -+up to multiples of 16 bytes. This is to allow aligned accesses in all -+cases while still simply mapping the structures over an in-memory copy of -+the bootsplash file. -+ -+ -+Further information -+------------------- -+ -+Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further -+details and possible values in the file. -+ -+ -+ -+Hooks - how the bootsplash is integrated -+======================================== -+ -+``drivers/video/fbdev/core/fbcon.c`` -+ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default -+ bootsplash file or the one specified on the kernel command line. -+ -+ ``fbcon_switch()`` draws the bootsplash when it's active, and is also -+ one of the callers of ``set_blitting_type()``. -+ -+ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the -+ bootsplash is active, overriding the text rendering functions. -+ -+ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is -+ being printed in order to make a kernel panic visible. -+ -+``drivers/video/fbdev/core/dummyblit.c`` -+ This contains the dummy text rendering functions used to suppress text -+ output while the bootsplash is shown. -+ -+``drivers/tty/vt/keyboard.c`` -+ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user -+ presses ESC or F1-F12 (changing VT). This is to provide a built-in way -+ of disabling the splash manually at any time. -+ -+ -+ -+FAQ: Frequently Asked Questions +@@ -195,6 +195,16 @@ Hooks - how the bootsplash is integrated + + + ++Crating a bootsplash theme file +=============================== + -+I want to see the log! How do I show the log? -+--------------------------------------------- -+ -+Press ESC while the splash is shown, or remove the ``bootsplash.bootfile`` -+parameter from the kernel cmdline. Without that parameter, the bootsplash -+will boot disabled. -+ -+ -+Why use FB instead of modern DRM/KMS? -+------------------------------------- -+ -+This is a semantic problem: -+ - What memory to draw the splash to? -+ - And what mode will the screen be set to? -+ -+Using the fbdev emulation solves these issues. -+ -+Let's start from a bare KMS system, without fbcon, and without fbdev -+emulation. In this case, as long as userspace doesn't open the KMS -+device, the state of the screen is undefined. No framebuffer is -+allocated in video RAM, and no particular mode is set. -+ -+In this case, we'd have to allocate a framebuffer to show the splash, -+and set our mode ourselves. This either wastes a screenful of video RAM -+if the splash is to co-exist with the userspace program's own allocated -+framebuffer, or there is a flicker as we deactivate and delete the -+bootsplash's framebuffer and hand control over to userspace. Since we -+may set a different mode than userspace, we'd also have flicker due -+to mode switching. -+ -+This logic is already contained in every KMS driver that performs fbdev -+emulation. So we might as well use that. And the correct API to do so is -+fbdev. Plus, we get compatibility with old, pure fbdev drivers for free. -+With the fbdev emulation, there is *always* a well-defined framebuffer -+to draw on. And the selection of mode has already been done by the -+graphics driver, so we don't need to reinvent that wheel, either. -+Finally, if userspace decides to use /dev/fbX, we don't have to worry -+about wasting video RAM, either. -+ -+ -+Why is the bootsplash integrated in fbcon? -+------------------------------------------ -+ -+Right now, the bootsplash is drawn from within fbcon, as this allows us -+to easily know *when* to draw - i.e. when we're safe from fbcon and -+userspace drawing all over our beautiful splash logo. ++A simple tool for theme file creation is included in ``tools/bootsplash``. + -+Separating them is not easy - see the to-do list below. ++There is also an example shell script, as an example on how to use the tool ++and in order to generate a reference bootsplash file. + + + -+TO DO list for future development -+================================= -+ -+Second enable/disable switch for the system -+------------------------------------------- -+ -+It may be helpful to differentiate between the system and the user -+switching off the bootsplash. Thus, the system may make it disappear and -+reappear e.g. for a password prompt, yet once the user has pressed ESC, -+it could stay gone. -+ -+ -+Fix buggy DRM/KMS drivers -+------------------------- -+ -+Currently, the splash code manually checks for fbdev emulation provided by -+the ast, cirrus, and mgag200 DRM/KMS drivers. -+These drivers use a manual mechanism similar to deferred I/O for their FB -+emulation, and thus need to be manually flushed onto the screen in the same -+way. -+ -+This may be improved upon in several ways: -+ -+1. Changing these drivers to expose the fbdev BO's memory directly, like -+ bochsdrmfb does. -+2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the -+ framebuffer once the bootsplash has been drawn into it. -+ -+ -+Separating from fbcon -+--------------------- -+ -+Separating these two components would yield independence from fbcon being -+compiled into the kernel, and thus lowering code size in embedded -+applications. -+ -+To do this cleanly will involve a clean separation of users of an FB device -+within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the -+legacy fbcon code and VT code co-operate to switch between fbcon and -+userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer -+between these components ensues refactoring of old code and checking for -+correct locking. -diff --git a/MAINTAINERS b/MAINTAINERS -index 5c237445761e..7ffac272434e 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -2709,6 +2709,8 @@ BOOTSPLASH - M: Max Staudt <mstaudt@suse.de> - L: linux-fbdev@vger.kernel.org - S: Maintained -+F: Documentation/ABI/testing/sysfs-platform-bootsplash -+F: Documentation/bootsplash.rst - F: drivers/video/fbdev/core/bootsplash*.* - F: drivers/video/fbdev/core/dummycon.c - F: include/linux/bootsplash.h + FAQ: Frequently Asked Questions + =============================== + +diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore +index 091b99a17567..5dfced41ba82 100644 +--- a/tools/bootsplash/.gitignore ++++ b/tools/bootsplash/.gitignore +@@ -1 +1,4 @@ + bootsplash-packer ++bootsplash ++logo.rgb ++throbber*.rgb +diff --git a/tools/bootsplash/bootsplash-tux.sh b/tools/bootsplash/bootsplash-tux.sh +new file mode 100755 +index 000000000000..1078f87644b9 +--- /dev/null ++++ b/tools/bootsplash/bootsplash-tux.sh +@@ -0,0 +1,66 @@ ++#!/bin/bash ++# ++# A simple script to show how to create a bootsplash. ++# Do with it whatever you wish. ++# ++# This needs ImageMagick for the 'convert' and 'identify' tools. ++# ++ ++LOGO=../../Documentation/logo.gif ++LOGO_WIDTH=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 1) ++LOGO_HEIGHT=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 2) ++ ++THROBBER=ajax-loader.gif ++THROBBER_WIDTH=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \ ++ cut -d x -f 1) ++THROBBER_HEIGHT=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \ ++ cut -d x -f 2) ++ ++convert -alpha remove \ ++ -background "#ff3a40" \ ++ $LOGO \ ++ logo.rgb ++ ++convert -alpha remove \ ++ -background "#ff3a40" \ ++ $THROBBER \ ++ throbber%02d.rgb ++ ++ ++make clean ++make bootsplash-packer ++ ++ ++# Let's put Tux in the center of an orange background. ++./bootsplash-packer \ ++ --bg_red 0xff \ ++ --bg_green 0x3a \ ++ --bg_blue 0x40 \ ++ --frame_ms 48 \ ++ --picture \ ++ --pic_width $LOGO_WIDTH \ ++ --pic_height $LOGO_HEIGHT \ ++ --pic_position 0 \ ++ --blob logo.rgb \ ++ --picture \ ++ --pic_width $THROBBER_WIDTH \ ++ --pic_height $THROBBER_HEIGHT \ ++ --pic_position 0x14 \ ++ --pic_position_offset 20 \ ++ --pic_anim_type 1 \ ++ --pic_anim_loop 0 \ ++ --blob throbber00.rgb \ ++ --blob throbber01.rgb \ ++ --blob throbber02.rgb \ ++ --blob throbber03.rgb \ ++ --blob throbber04.rgb \ ++ --blob throbber05.rgb \ ++ --blob throbber06.rgb \ ++ --blob throbber07.rgb \ ++ --blob throbber08.rgb \ ++ --blob throbber09.rgb \ ++ --blob throbber10.rgb \ ++ --blob throbber11.rgb \ ++ bootsplash ++ ++rm *.rgb diff --git a/0016-bootsplash.patch b/0016-bootsplash.patch deleted file mode 100644 index 8e87eb463187..000000000000 --- a/0016-bootsplash.patch +++ /dev/null @@ -1,129 +0,0 @@ -diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash -index 742c7b035ded..f8f4b259220e 100644 ---- a/Documentation/ABI/testing/sysfs-platform-bootsplash -+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash -@@ -9,3 +9,35 @@ Description: - 1: Splash is shown whenever fbcon would show a text console - (i.e. no graphical application is running), and a splash - file is loaded. -+ -+What: /sys/devices/platform/bootsplash.0/drop_splash -+Date: Oct 2017 -+KernelVersion: 4.14 -+Contact: Max Staudt <mstaudt@suse.de> -+Description: -+ Can only be set. -+ -+ Any value written will cause the current splash theme file -+ to be unloaded and the text console to be redrawn. -+ -+What: /sys/devices/platform/bootsplash.0/load_file -+Date: Oct 2017 -+KernelVersion: 4.14 -+Contact: Max Staudt <mstaudt@suse.de> -+Description: -+ Can only be set. -+ -+ Any value written will cause the splash to be disabled and -+ internal memory structures to be freed. -+ -+ A firmware path written will cause a new theme file to be -+ loaded and the current bootsplash to be replaced. -+ The current enabled/disabled status is not touched. -+ If the splash is already active, it will be redrawn. -+ -+ The path has to be a path in /lib/firmware since -+ request_firmware() is used to fetch the data. -+ -+ When setting the splash from the shell, echo -n has to be -+ used as any trailing '\n' newline will be interpreted as -+ part of the path. -diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst -index 611f0c558925..b35aba5093e8 100644 ---- a/Documentation/bootsplash.rst -+++ b/Documentation/bootsplash.rst -@@ -67,6 +67,14 @@ sysfs run-time configuration - a splash theme file is also loaded. - - -+``/sys/devices/platform/bootsplash.0/drop_splash`` -+ Unload splash data and free memory. -+ -+``/sys/devices/platform/bootsplash.0/load_file`` -+ Load a splash file from ``/lib/firmware/``. -+ Note that trailing newlines will be interpreted as part of the file name. -+ -+ - - Kconfig - ======= -diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c -index 13fcaabbc2ca..16cb0493629d 100644 ---- a/drivers/video/fbdev/core/bootsplash.c -+++ b/drivers/video/fbdev/core/bootsplash.c -@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device, - return count; - } - -+static ssize_t splash_store_drop_splash(struct device *device, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct splash_file_priv *fp; -+ -+ if (!buf || !count || !splash_state.file) -+ return count; -+ -+ mutex_lock(&splash_state.data_lock); -+ fp = splash_state.file; -+ splash_state.file = NULL; -+ mutex_unlock(&splash_state.data_lock); -+ -+ /* Redraw the text console */ -+ schedule_work(&splash_state.work_redraw_vc); -+ -+ bootsplash_free_file(fp); -+ -+ return count; -+} -+ -+static ssize_t splash_store_load_file(struct device *device, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct splash_file_priv *fp, *fp_old; -+ -+ if (!count) -+ return 0; -+ -+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev, -+ buf); -+ -+ if (!fp) -+ return -ENXIO; -+ -+ mutex_lock(&splash_state.data_lock); -+ fp_old = splash_state.file; -+ splash_state.splash_fb = NULL; -+ splash_state.file = fp; -+ mutex_unlock(&splash_state.data_lock); -+ -+ /* Update the splash or text console */ -+ schedule_work(&splash_state.work_redraw_vc); -+ -+ bootsplash_free_file(fp_old); -+ return count; -+} -+ - static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled); -+static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash); -+static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file); - - - static struct attribute *splash_dev_attrs[] = { - &dev_attr_enabled.attr, -+ &dev_attr_drop_splash.attr, -+ &dev_attr_load_file.attr, - NULL - }; - diff --git a/0017-bootsplash.patch b/0017-bootsplash.patch deleted file mode 100644 index 5d8ea1fe295c..000000000000 --- a/0017-bootsplash.patch +++ /dev/null @@ -1,511 +0,0 @@ -diff --git a/MAINTAINERS b/MAINTAINERS -index 7ffac272434e..ddff07cd794c 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -2715,6 +2715,7 @@ 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 -+F: tools/bootsplash/* - - BPF (Safe dynamic programs and tools) - M: Alexei Starovoitov <ast@kernel.org> -diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore -new file mode 100644 -index 000000000000..091b99a17567 ---- /dev/null -+++ b/tools/bootsplash/.gitignore -@@ -0,0 +1 @@ -+bootsplash-packer -diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile -new file mode 100644 -index 000000000000..0ad8e8a84942 ---- /dev/null -+++ b/tools/bootsplash/Makefile -@@ -0,0 +1,9 @@ -+CC := $(CROSS_COMPILE)gcc -+CFLAGS := -I../../usr/include -+ -+PROGS := bootsplash-packer -+ -+all: $(PROGS) -+ -+clean: -+ rm -fr $(PROGS) -diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c -new file mode 100644 -index 000000000000..ffb6a8b69885 ---- /dev/null -+++ b/tools/bootsplash/bootsplash-packer.c -@@ -0,0 +1,471 @@ -+/* -+ * Kernel based bootsplash. -+ * -+ * (Splash file packer tool) -+ * -+ * Authors: -+ * Max Staudt <mstaudt@suse.de> -+ * -+ * SPDX-License-Identifier: GPL-2.0 -+ */ -+ -+#include <endian.h> -+#include <getopt.h> -+#include <stdint.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+ -+#include <linux/bootsplash_file.h> -+ -+ -+static void print_help(char *progname) -+{ -+ printf("Usage: %s [OPTIONS] outfile\n", progname); -+ printf("\n" -+ "Options, executed in order given:\n" -+ " -h, --help Print this help message\n" -+ "\n" -+ " --bg_red <u8> Background color (red part)\n" -+ " --bg_green <u8> Background color (green part)\n" -+ " --bg_blue <u8> Background color (blue part)\n" -+ " --bg_reserved <u8> (do not use)\n" -+ " --frame_ms <u16> Minimum milliseconds between animation steps\n" -+ "\n" -+ " --picture Start describing the next picture\n" -+ " --pic_width <u16> Picture width in pixels\n" -+ " --pic_height <u16> Picture height in pixels\n" -+ " --pic_position <u8> Coarse picture placement:\n" -+ " 0x00 - Top left\n" -+ " 0x01 - Top\n" -+ " 0x02 - Top right\n" -+ " 0x03 - Right\n" -+ " 0x04 - Bottom right\n" -+ " 0x05 - Bottom\n" -+ " 0x06 - Bottom left\n" -+ " 0x07 - Left\n" -+ "\n" -+ " Flags:\n" -+ " 0x10 - Calculate offset from corner towards center,\n" -+ " rather than from center towards corner\n" -+ " --pic_position_offset <u16> Distance from base position in pixels\n" -+ " --pic_anim_type <u8> Animation type:\n" -+ " 0 - None\n" -+ " 1 - Forward loop\n" -+ " --pic_anim_loop <u8> Loop point for animation\n" -+ "\n" -+ " --blob <filename> Include next data stream\n" -+ " --blob_type <u16> Type of data\n" -+ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n" -+ " (default: number of last --picture)\n" -+ "\n"); -+ printf("This tool will write %s files.\n\n", -+#if __BYTE_ORDER == __BIG_ENDIAN -+ "Big Endian (BE)"); -+#elif __BYTE_ORDER == __LITTLE_ENDIAN -+ "Little Endian (LE)"); -+#else -+#error -+#endif -+} -+ -+ -+struct blob_entry { -+ struct blob_entry *next; -+ -+ char *fn; -+ -+ struct splash_blob_header header; -+}; -+ -+ -+static void dump_file_header(struct splash_file_header *h) -+{ -+ printf(" --- File header ---\n"); -+ printf("\n"); -+ printf(" version: %5u\n", h->version); -+ printf("\n"); -+ printf(" bg_red: %5u\n", h->bg_red); -+ printf(" bg_green: %5u\n", h->bg_green); -+ printf(" bg_blue: %5u\n", h->bg_blue); -+ printf(" bg_reserved: %5u\n", h->bg_reserved); -+ printf("\n"); -+ printf(" num_blobs: %5u\n", h->num_blobs); -+ printf(" num_pics: %5u\n", h->num_pics); -+ printf("\n"); -+ printf(" frame_ms: %5u\n", h->frame_ms); -+ printf("\n"); -+} -+ -+static void dump_pic_header(struct splash_pic_header *ph) -+{ -+ printf(" --- Picture header ---\n"); -+ printf("\n"); -+ printf(" width: %5u\n", ph->width); -+ printf(" height: %5u\n", ph->height); -+ printf("\n"); -+ printf(" num_blobs: %5u\n", ph->num_blobs); -+ printf("\n"); -+ printf(" position: %0x3x\n", ph->position); -+ printf(" position_offset: %5u\n", ph->position_offset); -+ printf("\n"); -+ printf(" anim_type: %5u\n", ph->anim_type); -+ printf(" anim_loop: %5u\n", ph->anim_loop); -+ printf("\n"); -+} -+ -+static void dump_blob(struct blob_entry *b) -+{ -+ printf(" --- Blob header ---\n"); -+ printf("\n"); -+ printf(" length: %7u\n", b->header.length); -+ printf(" type: %7u\n", b->header.type); -+ printf("\n"); -+ printf(" picture_id: %7u\n", b->header.picture_id); -+ printf("\n"); -+} -+ -+ -+#define OPT_MAX(var, max) \ -+ do { \ -+ if ((var) > max) { \ -+ fprintf(stderr, "--%s: Invalid value\n", \ -+ long_options[option_index].name); \ -+ break; \ -+ } \ -+ } while (0) -+ -+static struct option long_options[] = { -+ {"help", 0, 0, 'h'}, -+ {"bg_red", 1, 0, 10001}, -+ {"bg_green", 1, 0, 10002}, -+ {"bg_blue", 1, 0, 10003}, -+ {"bg_reserved", 1, 0, 10004}, -+ {"frame_ms", 1, 0, 10005}, -+ {"picture", 0, 0, 20000}, -+ {"pic_width", 1, 0, 20001}, -+ {"pic_height", 1, 0, 20002}, -+ {"pic_position", 1, 0, 20003}, -+ {"pic_position_offset", 1, 0, 20004}, -+ {"pic_anim_type", 1, 0, 20005}, -+ {"pic_anim_loop", 1, 0, 20006}, -+ {"blob", 1, 0, 30000}, -+ {"blob_type", 1, 0, 30001}, -+ {"blob_picture_id", 1, 0, 30002}, -+ {NULL, 0, NULL, 0} -+}; -+ -+ -+int main(int argc, char **argv) -+{ -+ FILE *of; -+ char *ofn; -+ int c; -+ int option_index = 0; -+ -+ unsigned long ul; -+ struct splash_file_header fh = {}; -+ struct splash_pic_header ph[255]; -+ struct blob_entry *blob_first = NULL; -+ struct blob_entry *blob_last = NULL; -+ struct blob_entry *blob_cur = NULL; -+ -+ if (argc < 2) { -+ print_help(argv[0]); -+ return EXIT_FAILURE; -+ } -+ -+ -+ /* Parse and and execute user commands */ -+ while ((c = getopt_long(argc, argv, "h", -+ long_options, &option_index)) != -1) { -+ switch (c) { -+ case 10001: /* bg_red */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ fh.bg_red = ul; -+ break; -+ case 10002: /* bg_green */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ fh.bg_green = ul; -+ break; -+ case 10003: /* bg_blue */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ fh.bg_blue = ul; -+ break; -+ case 10004: /* bg_reserved */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ fh.bg_reserved = ul; -+ break; -+ case 10005: /* frame_ms */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 65535); -+ fh.frame_ms = ul; -+ break; -+ -+ -+ case 20000: /* picture */ -+ if (fh.num_pics >= 255) { -+ fprintf(stderr, "--%s: Picture array full\n", -+ long_options[option_index].name); -+ break; -+ } -+ -+ fh.num_pics++; -+ break; -+ -+ case 20001: /* pic_width */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 65535); -+ ph[fh.num_pics - 1].width = ul; -+ break; -+ -+ case 20002: /* pic_height */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 65535); -+ ph[fh.num_pics - 1].height = ul; -+ break; -+ -+ case 20003: /* pic_position */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ ph[fh.num_pics - 1].position = ul; -+ break; -+ -+ case 20004: /* pic_position_offset */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ ph[fh.num_pics - 1].position_offset = ul; -+ break; -+ -+ case 20005: /* pic_anim_type */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ ph[fh.num_pics - 1].anim_type = ul; -+ break; -+ -+ case 20006: /* pic_anim_loop */ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ ph[fh.num_pics - 1].anim_loop = ul; -+ break; -+ -+ -+ case 30000: /* blob */ -+ if (fh.num_blobs >= 65535) { -+ fprintf(stderr, "--%s: Blob array full\n", -+ long_options[option_index].name); -+ break; -+ } -+ -+ blob_cur = calloc(1, sizeof(struct blob_entry)); -+ if (!blob_cur) { -+ fprintf(stderr, "--%s: Out of memory\n", -+ long_options[option_index].name); -+ break; -+ } -+ -+ blob_cur->fn = optarg; -+ if (fh.num_pics) -+ blob_cur->header.picture_id = fh.num_pics - 1; -+ -+ if (!blob_first) -+ blob_first = blob_cur; -+ if (blob_last) -+ blob_last->next = blob_cur; -+ blob_last = blob_cur; -+ fh.num_blobs++; -+ break; -+ -+ case 30001: /* blob_type */ -+ if (!blob_cur) { -+ fprintf(stderr, "--%s: No blob selected\n", -+ long_options[option_index].name); -+ break; -+ } -+ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ blob_cur->header.type = ul; -+ break; -+ -+ case 30002: /* blob_picture_id */ -+ if (!blob_cur) { -+ fprintf(stderr, "--%s: No blob selected\n", -+ long_options[option_index].name); -+ break; -+ } -+ -+ ul = strtoul(optarg, NULL, 0); -+ OPT_MAX(ul, 255); -+ blob_cur->header.picture_id = ul; -+ break; -+ -+ -+ -+ case 'h': -+ case '?': -+ default: -+ print_help(argv[0]); -+ goto EXIT; -+ } /* switch (c) */ -+ } /* while ((c = getopt_long(...)) != -1) */ -+ -+ /* Consume and drop lone arguments */ -+ while (optind < argc) { -+ ofn = argv[optind]; -+ optind++; -+ } -+ -+ -+ /* Read file lengths */ -+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) { -+ FILE *f; -+ long pos; -+ int i; -+ -+ if (!blob_cur->fn) -+ continue; -+ -+ f = fopen(blob_cur->fn, "rb"); -+ if (!f) -+ goto ERR_FILE_LEN; -+ -+ if (fseek(f, 0, SEEK_END)) -+ goto ERR_FILE_LEN; -+ -+ pos = ftell(f); -+ if (pos < 0 || pos > (1 << 30)) -+ goto ERR_FILE_LEN; -+ -+ blob_cur->header.length = pos; -+ -+ fclose(f); -+ continue; -+ -+ERR_FILE_LEN: -+ fprintf(stderr, "Error getting file length (or too long): %s\n", -+ blob_cur->fn); -+ if (f) -+ fclose(f); -+ continue; -+ } -+ -+ -+ /* Set magic headers */ -+#if __BYTE_ORDER == __BIG_ENDIAN -+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16); -+#elif __BYTE_ORDER == __LITTLE_ENDIAN -+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16); -+#else -+#error -+#endif -+ fh.version = BOOTSPLASH_VERSION; -+ -+ /* Set blob counts */ -+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) { -+ if (blob_cur->header.picture_id < fh.num_pics) -+ ph[blob_cur->header.picture_id].num_blobs++; -+ } -+ -+ -+ /* Dump structs */ -+ dump_file_header(&fh); -+ -+ for (ul = 0; ul < fh.num_pics; ul++) -+ dump_pic_header(&ph[ul]); -+ -+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) -+ dump_blob(blob_cur); -+ -+ -+ /* Write to file */ -+ printf("Writing splash to file: %s\n", ofn); -+ of = fopen(ofn, "wb"); -+ if (!of) -+ goto ERR_WRITING; -+ -+ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1) -+ goto ERR_WRITING; -+ -+ for (ul = 0; ul < fh.num_pics; ul++) { -+ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of) -+ != 1) -+ goto ERR_WRITING; -+ } -+ -+ blob_cur = blob_first; -+ while (blob_cur) { -+ struct blob_entry *blob_old = blob_cur; -+ FILE *f; -+ char *buf[256]; -+ uint32_t left; -+ -+ if (fwrite(&blob_cur->header, -+ sizeof(struct splash_blob_header), 1, of) != 1) -+ goto ERR_WRITING; -+ -+ if (!blob_cur->header.length || !blob_cur->fn) -+ continue; -+ -+ f = fopen(blob_cur->fn, "rb"); -+ if (!f) -+ goto ERR_FILE_COPY; -+ -+ left = blob_cur->header.length; -+ while (left >= sizeof(buf)) { -+ if (fread(buf, sizeof(buf), 1, f) != 1) -+ goto ERR_FILE_COPY; -+ if (fwrite(buf, sizeof(buf), 1, of) != 1) -+ goto ERR_FILE_COPY; -+ left -= sizeof(buf); -+ } -+ if (left) { -+ if (fread(buf, left, 1, f) != 1) -+ goto ERR_FILE_COPY; -+ if (fwrite(buf, left, 1, of) != 1) -+ goto ERR_FILE_COPY; -+ } -+ -+ /* Pad data stream to 16 bytes */ -+ if (left % 16) { -+ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", -+ 16 - (left % 16), 1, of) != 1) -+ goto ERR_FILE_COPY; -+ } -+ -+ fclose(f); -+ blob_cur = blob_cur->next; -+ free(blob_old); -+ continue; -+ -+ERR_FILE_COPY: -+ if (f) -+ fclose(f); -+ goto ERR_WRITING; -+ } -+ -+ fclose(of); -+ -+EXIT: -+ return EXIT_SUCCESS; -+ -+ -+ERR_WRITING: -+ fprintf(stderr, "Error writing splash.\n"); -+ fprintf(stderr, "The output file is probably corrupt.\n"); -+ if (of) -+ fclose(of); -+ -+ while (blob_cur) { -+ struct blob_entry *blob_old = blob_cur; -+ -+ blob_cur = blob_cur->next; -+ free(blob_old); -+ } -+ -+ return EXIT_FAILURE; -+} diff --git a/0018-bootsplash.patch b/0018-bootsplash.patch deleted file mode 100644 index 0924d29e7d48..000000000000 --- a/0018-bootsplash.patch +++ /dev/null @@ -1,102 +0,0 @@ -diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst -index b35aba5093e8..d4f132eca615 100644 ---- a/Documentation/bootsplash.rst -+++ b/Documentation/bootsplash.rst -@@ -195,6 +195,16 @@ Hooks - how the bootsplash is integrated - - - -+Crating a bootsplash theme file -+=============================== -+ -+A simple tool for theme file creation is included in ``tools/bootsplash``. -+ -+There is also an example shell script, as an example on how to use the tool -+and in order to generate a reference bootsplash file. -+ -+ -+ - FAQ: Frequently Asked Questions - =============================== - -diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore -index 091b99a17567..5dfced41ba82 100644 ---- a/tools/bootsplash/.gitignore -+++ b/tools/bootsplash/.gitignore -@@ -1 +1,4 @@ - bootsplash-packer -+bootsplash -+logo.rgb -+throbber*.rgb -diff --git a/tools/bootsplash/bootsplash-tux.sh b/tools/bootsplash/bootsplash-tux.sh -new file mode 100755 -index 000000000000..1078f87644b9 ---- /dev/null -+++ b/tools/bootsplash/bootsplash-tux.sh -@@ -0,0 +1,66 @@ -+#!/bin/bash -+# -+# A simple script to show how to create a bootsplash. -+# Do with it whatever you wish. -+# -+# This needs ImageMagick for the 'convert' and 'identify' tools. -+# -+ -+LOGO=../../Documentation/logo.gif -+LOGO_WIDTH=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 1) -+LOGO_HEIGHT=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 2) -+ -+THROBBER=ajax-loader.gif -+THROBBER_WIDTH=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \ -+ cut -d x -f 1) -+THROBBER_HEIGHT=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \ -+ cut -d x -f 2) -+ -+convert -alpha remove \ -+ -background "#ff3a40" \ -+ $LOGO \ -+ logo.rgb -+ -+convert -alpha remove \ -+ -background "#ff3a40" \ -+ $THROBBER \ -+ throbber%02d.rgb -+ -+ -+make clean -+make bootsplash-packer -+ -+ -+# Let's put Tux in the center of an orange background. -+./bootsplash-packer \ -+ --bg_red 0xff \ -+ --bg_green 0x3a \ -+ --bg_blue 0x40 \ -+ --frame_ms 48 \ -+ --picture \ -+ --pic_width $LOGO_WIDTH \ -+ --pic_height $LOGO_HEIGHT \ -+ --pic_position 0 \ -+ --blob logo.rgb \ -+ --picture \ -+ --pic_width $THROBBER_WIDTH \ -+ --pic_height $THROBBER_HEIGHT \ -+ --pic_position 0x14 \ -+ --pic_position_offset 20 \ -+ --pic_anim_type 1 \ -+ --pic_anim_loop 0 \ -+ --blob throbber00.rgb \ -+ --blob throbber01.rgb \ -+ --blob throbber02.rgb \ -+ --blob throbber03.rgb \ -+ --blob throbber04.rgb \ -+ --blob throbber05.rgb \ -+ --blob throbber06.rgb \ -+ --blob throbber07.rgb \ -+ --blob throbber08.rgb \ -+ --blob throbber09.rgb \ -+ --blob throbber10.rgb \ -+ --blob throbber11.rgb \ -+ bootsplash -+ -+rm *.rgb @@ -80,8 +80,9 @@ source=( "enable_additional_cpu_optimizations-$_gcc_more_v.tar.gz::https://github.com/graysky2/kernel_gcc_patch/archive/$_gcc_more_v.tar.gz" 0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch 0002-ZEN-Add-CONFIG-for-unprivileged_userns_clone.patch - 0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch - 0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch + 0003-bootsplash.patch + 0004-bootsplash.patch + 0005-bootsplash.patch 0006-bootsplash.patch 0007-bootsplash.patch 0008-bootsplash.patch @@ -92,16 +93,13 @@ source=( 0013-bootsplash.patch 0014-bootsplash.patch 0015-bootsplash.patch - 0016-bootsplash.patch - 0017-bootsplash.patch - 0018-bootsplash.patch 'ajax-loader.gif' ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman ) -sha256sums=('b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6' +sha256sums=('0c2a831f993dc8a8a8e1ca4186b467de72ff173c6f5855e2aab70f6f7fb033f9' 'SKIP' '1c4d5500a3b4995035c2e940fc0ad2a2dae7be047c8eb20c097444e348258f87' 'ae2e95db94ef7176207c690224169594d49445e04249d2499e9d2fbc117a0b21' @@ -109,8 +107,6 @@ sha256sums=('b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6' 'ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65' 'f1abc13a8d859fbf6350040e45d7f04ad551a6d39f113ba96fbbd820118c0e36' '91fafa76bf9cb32159ac7f22191b3589278b91e65bc4505cf2fc6013b8037bf3' - '63e4378e69e2f23ed87af32a4951477a6d82d4ac0de2295db46502c8120da9d9' - 'fc96300831506965383ef30bc46b72735dc45bb97dea2ccb8b9450c005d2f020' 'ef926edbd866d95464eb86f7565de572eb97ecfa0369d3b2e078016a0e71a871' 'a504f6cf84094e08eaa3cc5b28440261797bf4f06f04993ee46a20628ff2b53c' 'e096b127a5208f56d368d2cb938933454d7200d70c86b763aa22c38e0ddb8717' |