====================
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.


``/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
=======

``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.



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
===============================

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.
