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,state``; * ``magic``: A 32bit number used as a magic to identify the state Optional properties: * ``backend-type``: should be ``state`` or ``nv``. * ``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 ``@
``, 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 in a 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 the 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 ``: activate watchdog - if no parameter is given, the timeout from the device tree is used. A given parameter overwrites the device tree default.