summaryrefslogtreecommitdiffstats
path: root/Documentation/user/bootchooser.rst
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/user/bootchooser.rst')
-rw-r--r--Documentation/user/bootchooser.rst274
1 files changed, 274 insertions, 0 deletions
diff --git a/Documentation/user/bootchooser.rst b/Documentation/user/bootchooser.rst
new file mode 100644
index 0000000000..5baa66d9b9
--- /dev/null
+++ b/Documentation/user/bootchooser.rst
@@ -0,0 +1,274 @@
+Barebox Bootchooser
+===================
+
+In many cases embedded systems are layed out redundantly with multiple
+kernels and multiple root file systems. The bootchooser framework provides
+the building blocks to model different use cases without the need to start
+from scratch over and over again.
+
+The bootchooser works on abstract boot targets, each with a set of properties
+and implements an algorithm which selects the highest priority target to boot.
+
+Bootchooser Targets
+-------------------
+
+A bootchooser target represents one target that barebox can boot. It consists
+of a set of variables in the ``global.bootchooser.<targetname>`` namespace. The
+following configuration variables are needed to describe a bootchooser target:
+
+``global.bootchooser.<targetname>.boot``
+ This controls what barebox actually boots for this target. This string can contain
+ anything that the :ref:`boot <command_boot>` command understands.
+
+``global.bootchooser.<targetname>.default_attempts``
+ The default number of attempts that a target shall be tried starting.
+``global.bootchooser.<targetname>.default_priority``
+ The default priority of a target.
+
+
+Additionally the following runtime variables are needed. Unlinke the configuration
+variables these are automatically changed by the bootchooser algorithm:
+
+``global.bootchooser.<targetname>.priority``
+ The current priority of the target. Higher numbers have higher priorities. A priority
+ of 0 means the target is disabled and won't be started.
+``global.bootchooser.<targetname>.remaining_attempts``
+ The remaining_attempts counter. Only targets with a remaining_attempts counter > 0
+ are started.
+
+The bootchooser algorithm generally only starts targets that have a priority
+> 0 and a remaining_attempts counter > 0.
+
+The Bootchooser Algorithm
+-------------------------
+
+The bootchooser algorithm is very simple. It works with two variables per target
+and some optional flags. The variables are the remaining_attempts counter that
+tells how many times the target will be started. The other variable is the priority,
+the target with the highest priority will be used first, a zero priority means
+the target is disabled.
+
+When booting, bootchooser starts the target with the highest priority that has a
+nonzero remaining_attempts counter. With every start of a target the remaining
+attempts counter of this target is decremented by one. This means every targets
+remaining_attempts counter reaches zero sooner or later and the target won't be
+booted anymore. To prevent that, the remaining_attempts counter must be reset to
+its default. There are different flags in the bootchooser which control resetting
+the remaining_attempts counter, controlled by the ``global.bootchooser.reset_attempts``
+variable. It holds a list of space separated flags. Possible values are:
+
+- ``power-on``: The remaining_attempts counters of all enabled targets are reset
+ after a power-on reset (``$global.system.reset="POR"``). This means after a power
+ cycle all targets will be tried again for the configured number of retries
+- ``all-zero``: The remaining_attempts counters of all enabled targets are reset
+ when none of them has any remaining_attempts left.
+
+Additionally the remaining_attempts counter can be reset manually using the
+:ref:`command_bootchooser` command. This allows for custom conditions under which
+a system is marked as good.
+In case only the booted system itself knows when it is in a good state, the
+barebox-state tool from the dt-utils_ package can used to reset the remaining_attempts
+counter from the currently running system.
+
+.. _dt-utils: http://git.pengutronix.de/?p=tools/dt-utils.git;a=summary
+
+Bootchooser General Options
+---------------------------
+
+Additionally to the target options described above, bootchooser has some general
+options not specific to any target.
+
+``global.bootchooser.disable_on_zero_attempts``
+ Boolean flag. if 1, bootchooser disables a target (sets priority to 0) whenever the
+ remaining attempts counter reaches 0.
+``global.bootchooser.default_attempts``
+ The default number of attempts that a target shall be tried starting, used when not
+ overwritten with the target specific variable of the same name.
+``global.bootchooser.default_priority``
+ The default priority of a target when not overwritten with the target specific variable
+ of the same name.
+``global.bootchooser.reset_attempts``
+ A space separated list of events that cause bootchooser to reset the
+ remaining_attempts counters of each target that has a non zero priority. possible values:
+ * empty: counters will never be reset``
+ * power-on: counters will be reset after power-on-reset
+ * all-zero: counters will be reset when all targets have zero remaining attempts
+``global.bootchooser.reset_priorities``
+ A space separated list of events that cause bootchooser to reset the priorities of
+ all targets. Possible values:
+ * empty: priorities will never be reset
+ * all-zero: priorities will be reset when all targets have zero priority
+``global.bootchooser.retry``
+ If 1, bootchooser retries booting until one succeeds or no more valid targets exist.
+``global.bootchooser.state_prefix``
+ Variable prefix when bootchooser used with state framework as backend for storing runtime
+ data, see below.
+``global.bootchooser.targets``
+ Space separated list of targets that are used. For each entry in the list a corresponding
+ set of ``global.bootchooser.<name>``. variables must exist.
+``global.bootchooser.last_chosen``
+ bootchooser sets this to the target that was chosen on last boot (index)
+
+Using the State Framework as Backend for Runtime Variable Data
+--------------------------------------------------------------
+
+Normally the data that is modified by the bootchooser during runtime is stored
+in global variables (backed with NV). Alternatively the :ref:`state_framework`
+can be used for this data, which allows to store this data redundantly
+and in small EEPROM spaces. See :ref:`state_framework` to setup the state framework.
+During barebox runtime each state instance will create a device
+(usually named 'state' when only one is used) with a set of parameters. Set
+``global.bootchooser.state_prefix`` to the name of the device and optionally the
+namespace inside this device. For example when your state device is called 'state'
+and inside that the 'bootchooser' namespace is used for describing the targets,
+then set ``global.bootchooser.state_prefix`` to ``state.bootchooser``.
+
+Example
+-------
+
+The following example shows how to initialize two targets, 'system0' and 'system1'.
+Both boot from an UBIFS on nand0, the former has a priority of 21 and boots from
+the volume 'system0' whereas the latter has a priority of 20 and boots from
+the volume 'system1'.
+
+.. code-block:: sh
+
+ # initialize target 'system0'
+ nv bootchooser.system0.boot=nand0.ubi.system0
+ nv bootchooser.system0.default_attempts=3
+ nv bootchooser.system0.default_priority=21
+
+ # initialize target 'system1'
+ nv bootchooser.system1.boot=nand0.ubi.system1
+ nv bootchooser.system1.default_attempts=3
+ nv bootchooser.system1.default_priority=20
+
+ # make targets known
+ nv bootchooser.targets="system0 system1"
+
+ # retry until one target succeeds
+ nv bootchooser.retry="true"
+
+ # First try bootchooser, when no targets remain boot from network
+ nv boot.default="bootchooser net"
+
+Note that this example is for testing, normally the NV variables would be
+initialized directly by files in the default environment, not with a script.
+
+Scenarios
+---------
+
+This section describes some scenarios that can be solved with bootchooser. All
+scenarios assume multiple slots that can be booted, where 'multiple' is anything
+higher than one.
+
+Scenario 1
+##########
+
+A system that shall always boot without user interaction. Staying in the bootloader
+is not an option. In this scenario a target is started for the configured number
+of remaining attempts. If it cannot successfully be started, the next target is chosen.
+This happens until no targets are left to start, then all remaining attempts are
+reset to their defaults and the first target is tried again.
+
+Settings
+^^^^^^^^
+- ``global.bootchooser.reset_attempts="all-zero"``
+- ``global.bootchooser.reset_priorities="all-zero"``
+- ``global.bootchooser.disable_on_zero_attempts=0``
+- ``global.bootchooser.retry=1``
+- ``global.boot.default="bootchooser recovery"``
+- Userspace marks as good
+
+Deployment
+^^^^^^^^^^
+
+#. barebox or flash robot fills all slots with valid systems.
+#. The all-zero settings will lead to automatically enabling the slots, no
+ default settings are needed here.
+
+Recovery
+^^^^^^^^
+
+Recovery will only be called when all targets are not startable (That is, no valid
+Kernel found or read failure). Once a target is startable (A valid kernel is found
+and started) Bootchooser will never fall through to the recovery target.
+
+Scenario 2
+##########
+
+A system with multiple slots, a slot that was booted three times without success
+shall never be booted again (except after update or user interaction).
+
+Settings
+^^^^^^^^
+
+- ``global.bootchooser.reset_attempts=""``
+- ``global.bootchooser.reset_priorities=""``
+- ``global.bootchooser.disable_on_zero_attempts=0``
+- ``global.bootchooser.retry=1``
+- ``global.boot.default="bootchooser recovery"``
+- Userspace marks as good
+
+Deployment
+^^^^^^^^^^
+
+#. barebox or flash robot fills all slots with valid systems
+#. barebox or flash robot marks slots as good or state contains non zero
+ defaults for the remaining_attempts / priorities
+
+Recovery
+^^^^^^^^
+done by 'recovery' boot target which is booted after the bootchooser falls through due to
+the lack of bootable targets. This target can be:
+- A system that will be booted as recovery
+- A barebox script that will be started
+
+Scenario 3
+##########
+
+A system with multiple slots and one recovery system. Booting a slot three times
+without success disables it. A power cycle shall not be counted as failed boot.
+
+Settings
+^^^^^^^^
+
+- ``global.bootchooser.reset_attempts="power-on"``
+- ``global.bootchooser.reset_priorities=""``
+- ``global.bootchooser.disable_on_zero_attempts=1``
+- ``global.bootchooser.retry=1``
+- ``global.boot.default="bootchooser recovery"``
+- Userspace marks as good
+
+Deployment
+^^^^^^^^^^
+
+- barebox or flash robot fills all slots with valid systems
+- barebox or flash robot marks slots as good
+
+Recovery
+^^^^^^^^
+
+Done by 'recovery' boot target which is booted after the bootchooser falls through
+due to the lack of bootable targets. This target can be:
+- A system that will be booted as recovery
+- A barebox script that will be started
+
+Updating systems
+----------------
+
+Updating a slot is the same among the different scenarios. It is assumed that the
+update is done under a running Linux system which can be one of the regular bootchooser
+slots or a dedicated recovery system. For the regular slots updating is done like:
+
+- Set the priority of the inactive slot to 0.
+- Update the inactive slot
+- Set priority of the inactive slot to a higher value than the active slot
+- Set remaining_attempts of the inactive slot to nonzero
+- Reboot
+- If necessary update the now inactive, not yet updated slot the same way
+
+One way of updating systems is using RAUC_ which integrates well with the bootchooser
+in barebox.
+
+.. _RAUC: https://rauc.readthedocs.io/en/latest/ RAUC (