238 lines
7.3 KiB
ReStructuredText
238 lines
7.3 KiB
ReStructuredText
barebox bootstate
|
|
=================
|
|
|
|
Overview
|
|
--------
|
|
|
|
There are several use cases where a redundant Linux system is needed.
|
|
The ``barebox,bootstate`` framework provides the building blocks to
|
|
model different use cases without the need to start from the scratch
|
|
over and over again.
|
|
|
|
The ``barebox,bootstate`` works on abstract boot targets, each with a
|
|
set of properties and implements an algorithm which selects the
|
|
highest priority target to boot.
|
|
|
|
A set of boot targets can be described in a devicetree node. This
|
|
node could be part of the regular devicetree blob or it could be an
|
|
extra devicetree for the bootstate.
|
|
|
|
A bootstate node contains a description of a set of boot targets along
|
|
with a place where to store the mutable state. Currently implemented
|
|
backends are :ref:`barebox,state` and ``nv`` (:ref:`command_nv`)
|
|
variables.
|
|
|
|
Required properties:
|
|
|
|
* ``compatible``: should be ``barebox,bootstate``;
|
|
* ``backend-type``: should be ``state`` or ``nv``.
|
|
|
|
Optional properties:
|
|
|
|
* ``backend``: phandle to the :ref:`barebox,state` backend
|
|
|
|
|
|
boot target nodes - immutable description
|
|
-----------------------------------------
|
|
|
|
These are subnodes of a bootstate node, each describing a boot
|
|
target. The node name may end with ``@<ADDRESS>``, but the suffix is
|
|
sripped from the target name.
|
|
|
|
Optional properties:
|
|
|
|
* ``default_attempts``: If the boot attempts counter is reset, this
|
|
value is used.
|
|
|
|
Example::
|
|
|
|
bootstate: bootstate {
|
|
compatible = "barebox,bootstate";
|
|
backend-type = "state";
|
|
backend = <&state>;
|
|
|
|
system0 {
|
|
default_attempts = <3>;
|
|
};
|
|
|
|
system1 {
|
|
default_attempts = <3>;
|
|
};
|
|
};
|
|
|
|
In this example a bootstate, using a :ref:`barebox,state` backend with
|
|
two boot target ``system0`` and ``system1`` is defined. When the boot
|
|
attempts counter is reset, the default value of ``3`` is used for both
|
|
targets.
|
|
|
|
|
|
boot target nodes - mutable state
|
|
---------------------------------
|
|
|
|
The above example uses a :ref:`barebox,state` backend, which requires
|
|
some additional configuration to hold the mutable
|
|
state. :ref:`barebox,state` has to be explicidly configured, while
|
|
``nv`` (:ref:`command_nv`) variables are created on the fly.
|
|
|
|
The state of each boot target consists of the following ``uint32``
|
|
varibles:
|
|
|
|
* ``remaining_attempts``: holds the number of remaining boot
|
|
attempts. This variable is changed the the bootstate algorithm
|
|
during boot.
|
|
* ``priority``: defines the priority of the boot target. Higher number
|
|
indicate a higher priority, If two boot target have the same
|
|
priority the one defined first in the device tree has precedence.
|
|
The ``priority`` can optionally be changed by the algorithm to 0, if
|
|
the boot target is decremented to ``0`` remaining boot attempts. A
|
|
``priority`` of ``0`` means the boot target is **deactivated** and
|
|
will not be considered a valid target during further boots. If the
|
|
remaining attempts counter is reset, a target with priority 0 is
|
|
**not** changed.
|
|
* ``ok``: this is an opaque value, it's not accessed by the bootstate
|
|
algorithm. It can be used be the Linux system to track the first
|
|
boot after an update.
|
|
|
|
The bootstate can also hold a default watchdog timeout (in seconds),
|
|
which can be activated by the bootstate algorithm.
|
|
|
|
Example::
|
|
|
|
state: state {
|
|
magic = <0x4d433230>;
|
|
compatible = "barebox,state";
|
|
backend-type = "raw";
|
|
backend = <&backend_state>;
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
bootstate {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
system0 {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
remaining_attempts {
|
|
reg = <0x0 0x4>;
|
|
type = "uint32";
|
|
};
|
|
priority {
|
|
reg = <0x4 0x4>;
|
|
type = "uint32";
|
|
};
|
|
ok {
|
|
reg = <0x8 0x4>;
|
|
type = "uint32";
|
|
};
|
|
};
|
|
|
|
system1 {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
remaining_attempts {
|
|
reg = <0x10 0x4>;
|
|
type = "uint32";
|
|
};
|
|
priority {
|
|
reg = <0x14 0x4>;
|
|
type = "uint32";
|
|
};
|
|
ok {
|
|
reg = <0x18 0x4>;
|
|
type = "uint32";
|
|
};
|
|
};
|
|
|
|
watchdog_timeout {
|
|
reg = <0x20 0x4>;
|
|
type = "uint32";
|
|
default = <60>;
|
|
};
|
|
};
|
|
};
|
|
|
|
This example defines two boot target (``system0`` and ``system1``) and
|
|
a watchdog timeout of ``60`` seconds.
|
|
|
|
|
|
Backends
|
|
--------
|
|
|
|
Currently two backends exist. The :ref:`barebox,state` backend is a
|
|
bit more complicated to setup, as all boot target have to be described
|
|
in the referenced :ref:`barebox,state` in the device tree. On the
|
|
upside, the advantages of the (possible redundant storage, etc...) of
|
|
the :ref:`barebox,state` is gained for free.
|
|
|
|
The :ref:`command_nv` backend is a lot simpler, no special setup is
|
|
needed, it should run on every board, which already implements a
|
|
read/writeable barebox environment.
|
|
|
|
|
|
Algorithm
|
|
---------
|
|
|
|
The low level algorithm is implemented by the
|
|
``bootstate_get_target()`` function. Its job is to iterate over all
|
|
boot sources and return the name (as a string) of the choosen boot
|
|
target.
|
|
|
|
The algorithm iterates over all boot target defined under the
|
|
associated device tree node and picks the one with the highest
|
|
``priority`` (higher number have a higher priority) where the
|
|
``remaining_attempts`` is greater than zero. A pointer to the name of
|
|
the boot target is returned, the string should be freed via ``free()``.
|
|
|
|
The behaviour can be modified with the flags paramter. The following
|
|
flags are currently supported:
|
|
|
|
* ``BOOTCHOOSER_FLAG_ATTEMPTS_KEEP``: the ``remaining_attempts``
|
|
counter of the choosen boot target is not changed.
|
|
* ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC``: the ``remaining_attempts``
|
|
counter of the choosen boot target is decremented by one.
|
|
* ``BOOTCHOOSER_FLAG_ATTEMPTS_RESET``: the ``remaining_attempts``
|
|
counter of all *active* boot targets (those with ``priority > 0``)
|
|
are reset to their default values as defined in the immutable
|
|
description by ``default_attempts``.
|
|
* ``BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS``: if used together
|
|
with ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC`` and the
|
|
``remaining_attempts`` counter of the choosen boot target is
|
|
decremented to ``0``, the boot target is deactivated for further
|
|
boot attempts (although *this* boot is attemped as usual). This is
|
|
done by setting the ``priority`` to ``0``.
|
|
* ``BOOTCHOOSER_FLAG_VERBOSE``: increases the verbosity of the output
|
|
|
|
|
|
Frontend
|
|
--------
|
|
|
|
The shell command ``bootchooser`` (:ref:`command_bootchooser`) can be
|
|
used to choose and start a boot target by a shell one-liner. The
|
|
command picks the boot target with the highes priority and calls the
|
|
``boot`` (:ref:`command_boot`) command with the selected boot target
|
|
as its first and only parameter.
|
|
|
|
The ``bootchooser`` command implements command line paramter versions
|
|
of the above described flags:
|
|
|
|
* ``-k``: keep boot attempts
|
|
* ``-d``: decrement boot attempts
|
|
* ``-r``: reset boot attempts
|
|
* ``-z``: deactivate on zero remaining attempts
|
|
* ``-v``: verbose output
|
|
|
|
Next to the standard parameters, these additional options are
|
|
implemented:
|
|
|
|
* ``-D``: dryrun - do not boot (all other functionality is active) - a
|
|
specified watchdog timeout will be activated.
|
|
* ``-R``: retry - if booting fails, the chose next target, but
|
|
decrement its attemts. Note: if the current target has still the
|
|
highes priority and remaining attemts, it will be selected again.
|
|
* ``-w <TIMEOUT_IN_SEC>``: activate watchdog - if no parameter is
|
|
given, the timeout from the device tree is used. A given parameter
|
|
overwrites the device tree default.
|