mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Juergen Borleis <jbe@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH 7/7] docs: rework and extend the 'state' and 'bootchooser' documentation
Date: Tue, 15 Aug 2017 15:46:36 +0200	[thread overview]
Message-ID: <20170815134636.21236-8-jbe@pengutronix.de> (raw)
In-Reply-To: <20170815134636.21236-1-jbe@pengutronix.de>

Many links between sections and examples were added to give the developer
the help to get it work.

Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 .../devicetree/bindings/barebox/barebox,state.rst  | 332 ++++++----
 Documentation/user/bootchooser.rst                 | 493 +++++++++++----
 Documentation/user/state.rst                       | 696 +++++++++++++++++++--
 3 files changed, 1204 insertions(+), 317 deletions(-)

diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst
index 40d7bc2e6..4b1aade66 100644
--- a/Documentation/devicetree/bindings/barebox/barebox,state.rst
+++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst
@@ -1,55 +1,89 @@
 .. _barebox,state:
 
-barebox state
+Barebox state
 =============
 
-Overview
---------
+A *state* variable set can be fully described as a devicetree based *state* node.
+This *state* node could be part of the regular platform's devicetree blob or it
+could be an extra devicetree solely for the *state*.
 
+Devicetree *state* Node
+-----------------------
 
-Boards often have the need to store variables in persistent memory.
-The constraints are often different from what the regular environment
-can do:
+A *state* node contains a description of a set of variables along with a
+place where the variable set gets stored.
 
-* compact binary format to make it suitable for small EEPROMs/MRAMs
-* atomic save/restore of the whole variable set
-* redundancy
+Required Properties
+###################
 
-``barebox,state`` is a framework to describe, access, store and
-restore a set of variables. A state variable set can be fully
-described in a devicetree node. This node could be part of the regular
-devicetree blob or it could be an extra devicetree solely for the
-state. The state variable set contains variables of different types
-and a place to store the variable set.
+* ``compatible``: should be ``barebox,state``
+* ``magic``: a 32bit number
+* ``backend``: phandle to persistent memory
+* ``backend-type``: defines the *state* variable set storage format
+* additionally a *state* node must have an alias in the ``/aliases`` node pointing
+  to it.
 
-A state node contains a description of a set of variables along with a
-place where the variables are stored.
+.. _barebox,state_magic:
 
-Required properties:
+The ``magic`` property is a unique number which identifies the *state* variable
+set's variable types and their layout. It should be kept stable as long as the
+variable types and the layout are kept stable. It should also be kept stable
+if new trailing variables are added to the existing layout to be backward
+compatible. Only if the *state* variable set's variable types and/or their layout
+change, the ``magic`` property's number must be changed to be unique again
+with the new *state* variable set's content.
 
-* ``compatible``: should be ``barebox,state``;
-* ``magic``: A 32bit number used as a magic to identify the state
-* ``backend``: contains a phandle to the device/partition which holds the
-  actual state data.
-* ``backend-type``: should be ``raw`` or ``dtb``.
-* additionally a state node must have an alias in the /aliases/ node pointing
-  to it.
+.. important:: You should not use the values 0x2354fdf3 and 0x14fa2d02 for your
+   magic value. They're already reserved by the ``direct`` and ``circular``
+   storage backends.
 
-Optional properties:
+The ``backend`` property uses the *phandle* mechanism to link the *state* to
+a real persistent memory. Refer :ref:`Backend <state_framework,backends>` for
+supported persistent memories.
 
-* ``algo``: A HMAC algorithm used to detect manipulation of the data
-  or header, sensible values follow this pattern ``hmac(<HASH>)``,
-  e.g. ``hmac(sha256)``. Only used for ``raw``.
-* ``backend-stridesize``: Maximum size per copy of the data. Only important for
-  non-MTD devices
-* ``backend-storage-type``: Normally the correct storage type is detected auto-
-  matically. The circular backend supports the option ``noncircular`` to fall
-  back to an old storage format.
+The ``backend-type`` should be ``raw`` or ``dtb``. Refer
+:ref:`Backend Types <state_framework,backend_types>` for further details.
 
-Variable nodes
---------------
+Optional Properties
+###################
 
-These are subnodes of a state node each describing a single
+* ``backend-stridesize``: stride counted in bytes. See note below.
+* ``backend-storage-type``: Defines the backend storage type to ``direct`` or
+  ``circular``. Defaults to ``circular`` for media which requires erase cycles.
+* ``algo``: A HMAC algorithm used to detect manipulation of the data
+  or header, sensible values follow this pattern ``hmac(<HASH>)``,
+  e.g. ``hmac(sha256)``. Only available for the ``backend-type`` ``raw``.
+
+.. note:: For the ``backend-storage-type`` the keyword ``noncircular`` is still
+   supported as a fall back to an old storage format. Recommendation is to not
+   use this type anymore.
+
+.. _barebox,state_backend_stridesize:
+
+The ``backend-stridesize`` is still optional but required whenever the
+underlaying backend doesn't provide an information how to pad an instance of a
+*state* variable set. This is valid for all underlaying backends which supports
+writes on a byte-by-byte manner or don't have eraseblocks (EEPROM, SRAM and NOR
+type flash backends).
+The ``backend-stridesize`` value is used by the ``direct`` backend storage type
+to place the redundant *state* variable set copies side by side in the backend.
+And it's used by the ``circular`` backend storage type to place the *state*
+variable set copies side by side into the eraseblock.
+You should calculate the ``backend-stridesize`` value very carefully based on
+the used ``backend-type``, the size of the used backend (e.g. partition size
+for example) and its eraseblock size. Refer
+:ref:`Backend Types <state_framework,backend_types>`.
+
+.. note:: It might be useful to add some spare space to the
+   ``backend-stridesize`` to ensure the ability to extend the *state* variable
+   set later on.
+
+.. _barebox,state_variable:
+
+Variable Subnodes
+-----------------
+
+These are subnodes of a *state* node each describing a single
 variable. The node name may end with ``@<ADDRESS>``, but the suffix is
 stripped from the variable name.
 
@@ -57,105 +91,161 @@ State variables have a type. Currenty supported types are: ``uint8``,
 ``uint32``, ``enum32``, ``mac`` address or ``string`` (fixed length string).
 Variable length strings are not planned.
 
-Required properties:
+Required Properties
+###################
 
 * ``reg``: Standard ``reg`` property with ``#address-cells = <1>`` and
   ``#size-cells = <1>``. Defines the ``offset`` and ``size`` of the
-  variable in the ``raw`` backend. ``size`` must fit the node
+  variable in the ``raw`` backend. ``size`` **must fit** the node
   ``type``. Variables are not allowed to overlap.
-* ``type``: Should be ``uint8``, ``uint32``, ``int32``. ``enum32``, ``mac``
+* ``type``: Should be ``uint8``, ``uint32``, ``enum32``, ``mac``
   or ``string`` for the type of the variable
-* ``names``: For ``enum32`` values only, this specifies the values
-  possible for ``enum32``.
-
-Optional properties:
-
-* ``default``: The default value if the variable cannot be read from
-  storage. For ``enum32`` values it is an integer representing an
-  offset into the names array.
-
-Example::
-
-  /aliases {
-  	state = &state;
-  };
-
-  state: state {
-  	magic = <0x27031977>;
-  	compatible = "barebox,state";
-  	backend-type = "raw";
-  	backend = <&state_part>;
-
-  	foo {
-  		reg = <0x00 0x4>;
-  		type = "uint32";
-  		default = <0x0>;
-  	};
-
-  	bar {
-  		reg = <0x10 0x4>;
-  		type = "enum32";
-  		names = "baz", "qux";
-  		default = <1>;
-  	};
-  };
-
-  &nand_flash {
-  	partitions {
-  		compatible = "fixed-partitions";
-  		#address-cells = <1>;
-  		#size-cells = <1>;
-  		state_part: state@10000 {
-  			label = "state";
-  			reg = <0x10000 0x10000>;
-  		};
-  	};
-  };
-
-Variable Types
---------------
-
-* ``uint8``:
-* ``uint32``:
-* ``int32``:
-* ``enum32``: The ``default`` value is an integer representing an
-  offset into the names array.
-* ``mac``:
-* ``string``: The length of the string excluding the trailing 0 is
-  determined by the length given in the ``reg`` property.
-
-Backends
---------
-
-Currently two backends exist. The raw backend is a very compact format
-consisting of a magic value for identification, the raw values and a
-CRC. Two copies are maintained for making sure that during update the
-storage device still contains a valid state. The dtb backend stores
-the state as a devicetree binary blob. This is exactly the original
-devicetree description of the state itself, but additionally contains
-the actual values of the variables. Unlike the raw state backend the
-dtb state backend can describe itself.
+* ``names``: For ``enum32`` values only, this specifies the possible values for
+  ``enum32``.
+
+Optional Properties
+###################
+
+* ``default``: The default value if the variable's content cannot be read from
+  the backend. For ``enum32`` values it is an integer representing an offset
+  into the names array.
+
+.. note:: Since the ``default`` property is optional, keep in mind you may need
+   a valid default value if other instances (like the bootchooser for example)
+   depends on it. Due to this, a ``default`` might be a required property instead.
+
+Variable Examples
+#################
+
+``uint8``:
+
+.. code-block:: text
+
+   uint8_example@0 {
+       reg = <0x0 0x1>;
+       type = "uint8";
+       default = <0x00>;
+   };
+
+``uint32``:
+
+.. code-block:: text
+
+   uint32_example@0 {
+       reg = <0x0 0x4>;
+       type = "uint32";
+       default = <100>;
+   };
+
+``enum32``:
+
+.. code-block:: text
+
+   enum_example@0 {
+       reg = <0x0 0x4>;
+       type = "enum32";
+       names = "value#1", "value#2";
+       default = <1>; /* selects "value#2" as the default */
+   };
+
+``mac``:
+
+.. code-block:: text
+
+   mac_example@0 {
+       reg = <0x0 0x6>;
+       type = "mac";
+   };
+
+Since a 'MAC' is a unique system identifier it makes no sense for a default
+value here. It must be set individually at run-time instead.
+
+``string``:
+
+.. code-block:: text
+
+   name {
+       reg = <0x0 0x10>;
+       type = "string";
+   };
+
+In this example the length of the string is limited to 16 characters.
+
+.. _barebox,state_hmac:
 
 HMAC
 ----
 
-With the optional property ``algo = "hmac(<HASH>)";`` a HMAC algorithm
-can be defined to detect unauthorized modification of the state's
+With the optional property ``algo = "hmac(<HASH>)";`` an HMAC algorithm
+can be defined to detect unauthorized modification of the state's variable set
 header and/or data. For this to work the HMAC and the selected hash
 algorithm have to be compiled into barebox.
 
 The shared secret for the HMAC is requested via
 ``keystore_get_secret()``, using the state's name, from the barebox
 simple keystore. It's up to the developer to populate the keystore via
-``keystore_set_secret()`` in beforehand.
+``keystore_set_secret()`` in beforehand. Refer :ref:`command_keystore` for
+further details.
+
+.. _barebox,state_setup:
+
+Configuring the *state* variable set
+------------------------------------
+
+Since the *state* variable set is intended to be shared between the bootloader
+and the kernel, the view to the *state* variable set must be the same in both
+worlds.
+
+This can be achieved by defining all *state* variable set related definitions
+inside the barebox's devicetree only. It's **not** required to keep and maintain
+the same information inside the Linux kernel's devicetree again.
+
+When barebox is instructed to load and forward a devicetree to a Linux kernel
+to be started, it "silently" copies all *state* variable set related definitions
+from its own devicetree into the Linux kernel devicetree. This way both worlds
+behave the same when *state* variable sets should be read or modified.
+
+In order to enable barebox to copy the required information to a dedicated
+location inside the Linux kernel devicetree the name of the memory node to
+store the *state* variable set must be the same in the barebox's devicetree
+and the operating system's devicetree.
+
+With this "interconnection" barebox extends the operating system's devicetree
+with:
+
+- the layout and variable definition of the *state* variable set (in case of
+  the ``raw`` backend-type)
+- the store definition (backend type, backend storage type and so on)
+- partitioning information for the persistent memory in question (on demand)
+- the connection between the backend and the memory (device, partition)
+
+Example:
+
+Lets assume the barebox's devicetree uses the name ``persistent_state_memory@01``
+to define its own *state* variable set backend.
+
+Barebox's devicetree defines:
+
+.. code-block:: text
+
+   persistent_state_memory@01 {
+       compatible = "somevalue";
+       reg = <1>;
+
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       state: partition@0 {
+            label = "state";
+            reg = <0x0 0x100>;
+       };
+   };
 
-Frontend
---------
+The operating system's devicetree defines instead:
 
-As frontend a state instance is a regular barebox device which has
-device parameters for the state variables. With this the variables can
-be accessed like normal shell variables. The ``state`` command is used
-to save/restore a state to the backend device.
+.. code-block:: text
 
-After initializing the variable can be accessed with ``$state.foo``.
-``state -s`` stores the state to eeprom.
+   persistent_state_memory@01 {
+       compatible = "somevalue";
+       reg = <1>;
+   };
diff --git a/Documentation/user/bootchooser.rst b/Documentation/user/bootchooser.rst
index cef1d4abb..3d473b596 100644
--- a/Documentation/user/bootchooser.rst
+++ b/Documentation/user/bootchooser.rst
@@ -1,178 +1,217 @@
+.. _bootchooser:
+
 Barebox Bootchooser
 ===================
 
 In many cases embedded systems are layed out redundantly with multiple
-kernels and multiple root file systems. The bootchooser framework provides
+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
+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
+A *bootchooser* boot 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:
+following configuration variables are needed to describe a *bootchooser* boot 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.
+  This controls what barebox actually boots for this boot 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.
+  The default number of attempts that a boot target shall be tried before skipping it.
 ``global.bootchooser.<targetname>.default_priority``
-  The default priority of a target.
+  The default priority of a boot target.
 
 
-Additionally the following runtime variables are needed. Unlinke the configuration
-variables these are automatically changed by the bootchooser algorithm:
+Additionally the following run-time variables are needed. Unlike the configuration
+variables their values are automatically updated 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.
+  The current ``priority`` of the boot target. Higher numbers have higher priorities.
+  A ``priority`` of 0 means the boot 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 ``remaining_attempts`` counter. Only boot targets with a ``remaining_attempts``
+  counter > 0 are started.
+
+The *bootchooser* algorithm generally only starts boot targets that have a ``priority``
+> 0 and a ``remaining_attempts`` counter > 0.
 
-The bootchooser algorithm generally only starts targets that have a priority
-> 0 and a remaining_attempts counter > 0.
+.. _bootchooser,algorithm:
 
 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.
+The *bootchooser* algorithm is very simple. It works with two variables per boot target
+and some optional flags. The variables are the ``remaining_attempts`` counter that
+tells how many times the boot target will be started. The other variable is the ``priority``,
+the boot target with the highest ``priority`` will be used first, a zero ``priority``
+means the boot target is disabled.
+
+When booting, *bootchooser* starts the boot target with the highest ``priority`` that
+has a non-zero ``remaining_attempts`` counter. With every start of a boot target the
+``remaining_attempts`` counter of this boot target is decremented by one. This means
+every boot target's ``remaining_attempts`` counter reaches zero sooner or later and
+the boot 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:
+
+- empty: counters will never be reset
+- ``power-on``: The ``remaining_attempts`` counters of all enabled boot targets are reset
+  after a ``power-on`` reset (``$global.system.reset="POR"``). This means after a power
+  cycle all boot targets will be tried again for the configured number of retries.
+- ``all-zero``: The ``remaining_attempts`` counters of all enabled boot targets are
+  reset when none of them has any ``remaining_attempts`` left.
+
+Additionally the ``remaining_attempts`` counter can be reset manually using the
+:ref:`bootchoser command <command_bootchooser>`. 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 be used to reset the remaining_attempts
-counter from the currently running system.
+barebox-state tool from the dt-utils_ package can be used to reset the
+``remaining_attempts`` counter from the running system.
 
 .. _dt-utils: http://git.pengutronix.de/?p=tools/dt-utils.git;a=summary
 
-Bootchooser General Options
+General Bootchooser Options
 ---------------------------
 
-Additionally to the target options described above, bootchooser has some general
-options not specific to any target.
+In addition to the boot target options described above, *bootchooser* has some general
+options not specific to any boot target.
 
 ``global.bootchooser.disable_on_zero_attempts``
-  Boolean flag. If set to 1, bootchooser disables a target (sets priority to 0) whenever
-  the remaining attempts counter reaches 0.
+  Boolean flag. If set to 1, *bootchooser* disables a boot 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.
+  The default number of attempts that a boot target shall be tried before skipping
+  it, used when not overwritten with the boot 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.
+  The default priority of a boot 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
+  Already described in :ref:`Bootchooser Algorithm <bootchooser,algorithm>`
 ``global.bootchooser.reset_priorities``
-  A space separated list of events that cause bootchooser to reset the priorities of
-  all targets. Possible values:
+  A space separated list of events that cause *bootchooser* to reset the priorities of
+  all boot targets. Possible values:
 
   * empty: priorities will never be reset
-  * all-zero: priorities will be reset when all targets have zero priority
+  * ``all-zero``: priorities will be reset when all targets have zero priority
 ``global.bootchooser.retry``
-  If set to 1, bootchooser retries booting until one succeeds or no more valid targets
-  exist.
+  If set to 1, *bootchooser* retries booting until one succeeds or no more valid
+  boot targets exist.
+  Otherwise the ``boot`` command will return with an error after the first failed
+  boot target.
 ``global.bootchooser.state_prefix``
-  Variable prefix when bootchooser is used with the state framework as backend for storing
-  runtime data, see below.
+  Variable prefix when *bootchooser* is used with the *state* framework as backend
+  for storing run-time data, see below.
 ``global.bootchooser.targets``
-  Space separated list of targets that are used. For each entry in the list a corresponding
+  Space separated list of boot targets that are used. For each entry in the list
+  a corresponding
   set of ``global.bootchooser.<targetname>.<variablename>`` 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``.
+  *bootchooser* sets this to the boot target that was chosen on last boot (index).
 
-Example
--------
+.. _bootchooser,setup_example:
+
+Setup Example
+-------------
+
+We want to set up a redundant machine with two bootable systems within one shared
+memory, here a NAND type flash memory with a UBI partition. We have a 512 MiB NAND
+type flash, to be used only for the root filesystem. The devicetree doesn't
+define any partition, because we want to run one UBI partition with two volumens
+for the redundant root filesystems on this flash memory.
+
+.. code-block:: text
 
-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'.
+   nand@0 {
+      [...]
+   };
+
+In order to configure this machine the following steps can be used:
 
 .. 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
+   ubiformat /dev/nand0 -y
+   ubiattach /dev/nand0
+   ubimkvol /dev/nand0.ubi root_filesystem_1 256MiB
+   ubimkvol /dev/nand0.ubi root_filesystem_2 0
+
+The last command creates a volume which fills the remaining available space
+on the NAND type flash memory, which will be most of the time smaller than
+256 MiB due to factory bad blocks and lost data blocks for UBI's management.
+
+After this preparation we can find two devices in ``/dev``:
+
+- ``nand0.ubi.root_filesystem_1``
+- ``nand0.ubi.root_filesystem_2``
+
+These two devices can now be populated with their filesystem content. In our
+example here we additionally assume, that these root filesystems contain a Linux
+kernel with its corresponding devicetree via boot spec (refer to
+:ref:`Bootloader Spec <bootloader_spec>` for further details).
+
+Either device can be booted with the :ref:`boot <command_boot>` command command,
+and thus can be used by the *bootchooser* and we can start to configure the
+*bootchooser* variables.
+
+The following example shows how to initialize two boot targets, ``system1`` and
+``system2``. Both boot from a UBIFS on ``nand0``, the former has a priority of
+21 and boots from the volume ``root_filesystem_1`` whereas the latter has a
+priority of 20 and boots from the volume ``root_filesystem_2``.
+
+.. code-block:: sh
 
   # initialize target 'system1'
-  nv bootchooser.system1.boot=nand0.ubi.system1
+  nv bootchooser.system1.boot=nand0.ubi.root_filesystem_1
   nv bootchooser.system1.default_attempts=3
-  nv bootchooser.system1.default_priority=20
+  nv bootchooser.system1.default_priority=21
+
+  # initialize target 'system2'
+  nv bootchooser.system2.boot=nand0.ubi.root_filesystem_2
+  nv bootchooser.system2.default_attempts=3
+  nv bootchooser.system2.default_priority=20
 
   # make targets known
-  nv bootchooser.targets="system0 system1"
+  nv bootchooser.targets="system1 system2"
 
   # retry until one target succeeds
-  nv bootchooser.retry="true"
+  nv bootchooser.retry=1
 
   # 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.
+.. note:: This example is for testing only, normally the NV variables would be
+   initialized directly by files in the default environment, not with a script.
+
+The run-time values are stored in environment variables as well. Alternatively,
+they can be stored in a *state* variable set instead. Refer to
+:ref:`using the state framework <bootchooser,state_framework>` for further
+details.
 
 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.
+This section describes some scenarios that can be handled by bootchooser. All
+scenarios assume multiple boot targets 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.
+- a system that shall always boot without user interaction
+- staying in the bootloader is not an option.
+
+In this scenario a boot target is started for the configured number of remaining
+attempts. If it cannot be started successfully, the next boot target is chosen.
+This repeats until no boot targets are left to start, then all remaining attempts
+are reset to their defaults and the first boot target is tried again.
 
 Settings
 ^^^^^^^^
@@ -186,22 +225,26 @@ Settings
 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.
+#. barebox or flash robot fills all boot targets with valid systems.
+#. The all-zero settings will lead to automatically enabling the boot targets,
+   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.
+Recovery will only be called when all boot targets are not startable (That is,
+no valid kernel found or read failure). Once a boot target is startable (a
+valid kernel is found and started) *bootchooser* will never fall through to
+the recovery boot 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).
+- a system with multiple boot targets
+- one recovery system
+
+A boot target that was booted three times without success shall never be booted
+again (except after update or user interaction).
 
 Settings
 ^^^^^^^^
@@ -216,23 +259,27 @@ Settings
 Deployment
 ^^^^^^^^^^
 
-#. barebox or flash robot fills all slots with valid systems.
-#. barebox or flash robot marks slots as good or state contains non zero
+#. barebox or flash robot fills all boot targets with valid systems.
+#. barebox or flash robot marks boot targets 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.
+Done by 'recovery' boot target which is booted after the *bootchooser* falls
+through due to the lack of bootable targets. This boot 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.
+- a system with multiple boot targets
+- one recovery system
+- a power cycle shall not be counted as failed boot.
+
+Booting a boot target three times without success disables it.
 
 Settings
 ^^^^^^^^
@@ -247,33 +294,205 @@ Settings
 Deployment
 ^^^^^^^^^^
 
-#. barebox or flash robot fills all slots with valid systems.
-#. barebox or flash robot marks slots as good.
+#. barebox or flash robot fills all boot targets with valid systems.
+#. barebox or flash robot marks boot targets 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:
+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.
 
-- A system that will be booted as recovery.
-- A barebox script that will be started.
+.. _bootchooser,state_framework:
+
+Using the *State* Framework as Backend for Run-Time Variable Data
+-----------------------------------------------------------------
+
+Usually the *bootchooser* modifies its data in global variables which are
+connected to :ref:`non volatile variables <config_device>`.
+
+Alternatively the :ref:`state_framework` can be used for this data, which
+allows to store this data redundantly in some kind of persistent memory.
+
+In order to let the *bootchooser* use the *state* framework for its storage
+backend, configure the ``bootchooser.state_prefix`` variable with the *state*
+variable set instance name.
+
+Usually a generic *state* variable set in the devicetree is defined like this
+(refer to :ref:`barebox,state` for more details):
+
+.. code-block:: text
+
+   some_kind_of_state {
+      [...]
+   };
+
+At barebox run-time this will result in a *state* variable set instance called
+*some_kind_of_state*. You can also store variables unrelated to *bootchooser* (a
+serial number, MAC address, …) in it.
+
+Extending this *state* variable set by information required by the *bootchooser*
+is simply done by adding so called 'boot targets' and optionally one ``last_chosen``
+node. It then looks like:
+
+.. code-block:: text
+
+   some_kind_of_state {
+     [...]
+     boot_target_1 {
+         [...]
+     };
+     boot_target_2 {
+         [...]
+     };
+   };
+
+It could makes sense to store the result of the last *bootchooser* operation
+in the *state* variable set as well. In order to do so, add a node with the name
+``last_chosen`` to the *state* variable set. *bootchooser* will use it if present.
+The *state' variable set definition then looks like:
+
+.. code-block:: text
+
+   some_kind_of_state {
+     [...]
+     boot_target_1 {
+         [...]
+     };
+     boot_target_2 {
+         [...]
+     };
+     last_chosen {
+         reg = <offset 0x4>;
+         type = "uint32";
+     };
+   };
+
+The ``boot_target_*`` names shown above aren't variables themselves (like the other
+variables in the *state* variable set), they are named containers instead, which
+are used to group variables specific to *bootchooser*.
+
+A 'boot target' container has the following fixed content:
+
+.. code-block:: text
+
+   some_boot_target {
+          #address-cells = <1>;
+          #size-cells = <1>;
+
+          remaining_attempts {
+              [...]
+              default = <some value>; /* -> read note below */
+          };
+
+          priority {
+              [...]
+              default = <some value>; /* -> read note below */
+          };
+   };
+
+.. important:: Since each variable in a *state* variable set requires a ``reg``
+   property, the value of its ``reg`` property must be unique, e.g. the offsets
+   must be consecutive from a global point of view, as they describe the
+   storage layout in the backend memory.
+
+So, ``remaining_attempts`` and ``priority`` are required variable nodes and are
+used to setup the corresponding run-time environment variables in the
+``global.bootchooser.<targetname>`` namespace.
+
+.. important:: It is important to provide a ``default`` value for each variable
+   for the case when the *state* variable set backend memory is uninitialized.
+   This is also true if default values through the *bootchooser's* environment
+   variables are defined (e.g. ``bootchooser.default_attempts``,
+   ``bootchooser.default_priority`` and their corresponding boot target specific
+   variables). The former ones are forwarded to the *bootchooser* to make a
+   decision, the latter ones are used by the *bootchooser* to make a decision
+   the next time.
+
+Example
+#######
+
+For this example we use the same system and its setup described in
+:ref:`setup example <bootchooser,setup_example>`. The resulting devicetree
+content for the *state* variable set looks like:
+
+.. code-block:: text
+
+   system_state {
+        [...]
+        system1 {
+             #address-cells = <1>;
+             #size-cells = <1>;
+             remaining_attempts@0 {
+                 reg = <0x0 0x4>;
+                 type = "uint32";
+                 default = <3>;
+             };
+             priority@4 {
+                 reg = <0x4 0x4>;
+                 type = "uint32";
+                 default = <20>;
+             };
+        };
+
+        system2 {
+             #address-cells = <1>;
+             #size-cells = <1>;
+             remaining_attempts@8 {
+                 reg = <0x8 0x4>;
+                 type = "uint32";
+                 default = <3>;
+             };
+             priority@c {
+                 reg = <0xc 0x4>;
+                 type = "uint32";
+                 default = <21>;
+             };
+        };
+
+        last_chosen@10 {
+             reg = <0x10 0x4>;
+             type = "uint32";
+        };
+   };
+
+.. important:: While the ``system1/2`` nodes suggest a different namespace inside the
+   *state* variable set, the actual variable's ``reg``-properties and their offset
+   part are always relative to the whole *state* variable set and thus must be
+   consecutive globally.
+
+To make *bootchooser* use the so called ``system_state`` *state* variable set
+instead of the NV run-time environment variables, we just set:
+
+.. code-block:: text
+
+   global.bootchooser.state_prefix=system_state
+
+.. note:: Its a good idea to keep the ``bootchooser.<targetname>.default_priority``
+   and ``bootchooser.<targetname>.default_attempts`` values in sync with the
+   corresponding default values in the devicetree.
 
 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.
+Updating a boot target 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* boot targets or a dedicated recovery system. For the
+regular *bootchooser* boot targets updating is done like:
+
+- Disable the inactive (e.g. not used right now) boot target by setting its
+  ``priority`` to 0.
+- Update the inactive boot target.
+- Set ``remaining_attempts`` of the inactive boot target to nonzero.
+- Enable the inactive boot target by setting its ``priority`` to a higher value
+  than any other boot target (including the used one right now).
 - Reboot.
-- If necessary update the now inactive, not yet updated slot the same way.
+- If necessary update the now inactive, not yet updated boot target the same way.
 
-One way of updating systems is using RAUC_ which integrates well with the bootchooser
+One way of updating systems is using RAUC_ which integrates well with the *bootchooser*
 in barebox.
 
-.. _RAUC: https://rauc.readthedocs.io/en/latest/ RAUC (
+.. _RAUC: https://rauc.readthedocs.io/en/latest/
diff --git a/Documentation/user/state.rst b/Documentation/user/state.rst
index 73c4be815..7d6c5770d 100644
--- a/Documentation/user/state.rst
+++ b/Documentation/user/state.rst
@@ -3,65 +3,643 @@
 Barebox State Framework
 =======================
 
-The state framework is build to exchange data between Barebox and Linux
-userspace using a non-volatile storage. There are several components involved.
-Barebox has a state driver to access the variables. For the Linux Userspace
-there is a userspace tool.
-
-Devicetree
-----------
-
-Currently the devicetree defines the layout of the variables and data.
-Variables are fixed size. Several types are supported, see the binding
-documentation for details.
-
-Data Formats
-------------
-
-The state data can be stored in different ways. Currently two formats are
-available, ``raw`` and ``dtb``. Both format the state data differently.
-Basically these are serializers. The raw serializer additionally supports a
-HMAC algorithm to detect manipulations.
-
-The data is always stored in a logical unit called ``bucket``. A ``bucket`` has
-its own size depending on some external contraints. These contraints are listed
-in more detail below depending on the used memory type and storage backend. A
-``bucket`` stores exactly one state. A default number of three buckets is used
-to store data redundantely.
-
-Redundancy
-----------
-
-The state framework is safe against powerfailures during write operations. To
-archieve that multiple buckets are stored to disk. When writing all buckets are
-written in order. When reading, the buckets are read in order and the first
-one found that passes CRC tests is used. When all data is read the buckets
-containing invalid or outdated data are written with the data just read. Also
-NAND blocks need cleanup due to excessive bitflips are rewritten in this step.
-With this it is made sure that after successful initialization of a state the
-data on the storage device is consistent and redundant.
-
-Storage Backends
-----------------
-
-The serialized data can be stored to different backends. Currently two
-implementations exist, ``circular`` and ``direct``. The state framework automatically
-selects the correct backend depending on the storage medium. Media requiring
-erase operations (NAND, NOR flash) use the ``circular`` backend, others use the ``direct``
-backend. The purpose of the ``circular`` backend is to save erase cycles which may
-wear out the flash blocks. It continuously fills eraseblocks with updated data
-and only when an eraseblock if fully written erases it and starts over writing
-new data to the same eraseblock again.
-
-For all backends multiple copies are written to handle read errors.
-
-Commands
+Boards often have the need to store variable sets in persistent memory. barebox
+could handle that with its regular environment. But the constraints for such a
+variable set are often different from what the regular environment can do:
+
+* compact binary format to make it suitable for small non-volatile memories
+* atomic save/restore of the whole variable set
+* redundancy
+
+*state* is a framework to describe, access, store and restore a set of variables
+and is prepared to exchange/share data between barebox and Linux userspace using
+some kind of persistent memory.
+
+Already known users of the *state* information are the :ref:`bootchooser` and
+RAUC_.
+
+.. _RAUC: https://rauc.readthedocs.io/en/latest/
+
+barebox itself uses a *state* driver to access the variables in the
+persistent memory. For the Linux run-time there is a userspace tool_ to do
+the same.
+
+.. _tool: https://git.pengutronix.de/cgit/tools/dt-utils/
+
+To define a *state* variable set, a devicetree based description is used. Refer to
+:ref:`barebox,state` for further details.
+
+There are several software components involved, which are described in this
+section.
+
+.. _state_framework,backends:
+
+Backends (e.g. Supported Memory Types)
+--------------------------------------
+
+Some non-volatile memory is need for storing a *state* variable set:
+
+- all kinds of NOR flash memories
+- all kinds of NAND flash memories
+- MRAM
+- EEPROM
+- all kind of SRAMs (backup battery assumed)
+
+For classic MTDs (NOR/NAND/SRAM), a partition is required and understood by
+the Linux kernel as well to define the location inside the device where to store
+the *state* variable set. For non-MTDs (MRAM/EEPROM) a different approach is
+required to define the location where to store the *state* variable set.
+
+.. _state_framework,backend_types:
+
+Backend-Types (e.g. *state* storage format)
+-------------------------------------------
+
+The *state* variable set itself can be stored in different ways. Currently two
+formats are available, ``raw`` and ``dtb``.
+
+Both serialize the *state* variable set differently.
+
+.. note:: The ``raw`` serializer additionally supports an HMAC algorithm to
+   detect manipulations. Refer to :ref:`HMAC <barebox,state_hmac>` for further
+   details.
+
+.. _state_framework,raw:
+
+The ``raw`` *state* storage format
+##################################
+
+``raw`` means the *state* variable set is a simple binary data blob only. In
+order to handle it, the *state* framework puts a management header in front of
+the binary data blob with the following content and layout:
+
+ +---------+---------+---------------------------------------------------+
+ | Offset  |   Size  |    Content                                        |
+ +---------+---------+---------------------------------------------------+
+ |  0x00   | 4 bytes | 'magic value'                                     |
+ +---------+---------+---------------------------------------------------+
+ |  0x04   | 2 bytes | reserved, filled with zero bits                   |
+ +---------+---------+---------------------------------------------------+
+ |  0x06   | 2 bytes | byte count of binary data blob                    |
+ +---------+---------+---------------------------------------------------+
+ |  0x08   | 4 bytes | CRC32 of binary data blob (offset 0x10...)        |
+ +---------+---------+---------------------------------------------------+
+ |  0x0c   | 4 bytes | CRC32 of header (offset 0x00...0x0b)              |
+ +---------+---------+---------------------------------------------------+
+ | 0x10... |         | binary data blob                                  |
+ +---------+---------+---------------------------------------------------+
+
+- 'magic value' is an unsigned value with native endianness, refer to
+  :ref:`'magic' property <barebox,state_magic>` about its value.
+- 'byte count' is an unsigned value with native endianness
+- 'binary data blob CRC32' is an unsigned value with native endianness
+- 'header CRC32' is an unsigned value with native endianness
+
+.. note:: the 32-bit CRC calculation uses the polynomial:
+
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
+
+Since the binary data blob has no built-in description of the embedded *state*
+variable set, it depends on an external layout definition to encode
+and decode it correctly. A devicetree based description is used to describe the
+embedded *state* variable set. Refer to
+:ref:`Variable Subnodes <barebox,state_variable>` for further details.
+
+.. important:: It is important to share this layout definition in all
+   'worlds' which want to read or manipulate the *state* variable set. This
+   includes offsets, sizes and endianesses of the binary data. Refer to
+   :ref:`Configuring the state variable set <barebox,state_setup>` on how to
+   setup barebox to ensure this is done automatically for devicetree based
+   operating systems.
+
+.. note:: When calculating the ``backend-stridesize`` take the header overhead
+   into account. The header overhead is always 16 bytes.
+
+.. _state_framework,dtb:
+
+The ``dtb`` *state* storage format
+##################################
+
+.. note:: The ``dtb`` backend type isn't well tested. Use the ``raw`` backend
+          when in doubt.
+
+The ``dtb`` backend type stores the *state* variable set as a devicetree binary
+blob. This is exactly the original devicetree description of the *state* variable
+set itself, but additionally contains the actual values of the variable set.
+Unlike the ``raw`` *state* backend the ``dtb`` *state* backend can describe itself.
+
+.. _state_framework,backend_storage_type:
+
+Backend Storage Types (e.g. media storage layout)
+-------------------------------------------------
+
+The serialized data (``raw`` or ``dtb``) can be stored to different backend
+storage types. These types are dedicated to different memory types.
+
+Currently two backend storage type implementations do exist, ``circular`` and
+``direct``.
+
+The state framework can select the correct backend storage type depending on the
+backend medium. Media requiring erase operations (NAND, NOR flash) defaults to
+the ``circular`` backend storage type automatically. In contrast EEPROMs and
+RAMs are candidates for the ``direct`` backend storage type.
+
+Direct Storage Backend
+######################
+
+This kind of backend storage type is intended to be used with persistent RAMs or
+EEPROMs.
+These media are characterized by:
+
+- memory cells can be simply written at any time (no previous erase required)
+- memory cells can be written as often as required (unlimted or very high endurance)
+- can be written on a byte-by-byte manner
+
+Example: MRAM with 64 bytes at device's offset 0:
+
+.. code-block:: text
+
+    0                                                                 0x3f
+    +-------------------------------------------------------------------+
+    |                                                                   |
+    +-------------------------------------------------------------------+
+
+Writing the *state* variable set always happens at the same offset:
+
+.. code-block:: text
+
+    0                                                                 0x3f
+    +-------------------------------------------+-----------------------+
+    |                 copy                      |                       |
+    +-------------------------------------------+-----------------------+
+
+.. important:: The ``direct`` storage backend needs 8 bytes of additional space
+   per *state* variable set for its meta data.
+
+Circular Storage Backend
+########################
+
+This kind of backend storage type is intended to be used with regular flash memory devices.
+
+Flash memories are characterized by:
+
+- only erased memory cells can be written with new data
+- written data cannot be written twice (at least not for modern flash devices)
+- erase can happen on eraseblock sizes only (detectable, physical value)
+- an eraseblock only supports a limited number of write-erase-cycles (as low as a few thousand cycles)
+
+The purpose of the ``circular`` backend storage type is to save erase cycles
+which may wear out the flash's eraseblocks. This type instead incrementally fills
+an eraseblock with updated data and only when an eraseblock
+is fully written, it erases it and starts over writing new data to the same
+eraseblock again.
+
+**NOR type flash memory is additionally characterized by**
+
+- can be written on a byte-by-byte manner
+
+.. _state_framework,nor:
+
+Example: NOR type flash memory with 64 kiB eraseblock size
+
+.. code-block:: text
+
+    0                                                                0x0ffff
+    +--------------------------------------------------------------------+
+    |                                                                    |
+    +--------------------------------------------------------------------+
+    |<--------------------------- eraseblock --------------------------->|
+
+Writing the *state* variable set the very first time:
+
+.. code-block:: text
+
+    0
+    +------------+------------
+    |   copy     |
+    |    #1      |
+    +------------+------------
+    |<- stride ->|
+    |<---- eraseblock -------
+
+'copy#1' will be used.
+
+Changing the *state* variable set the first time (e.g. writing it the second time):
+
+.. code-block:: text
+
+    0
+    +------------+------------+------------
+    |   copy     |   copy     |
+    |    #1      |    #2      |
+    +------------+------------+------------
+    |<- stride ->|<- stride ->|
+    |<------------- eraseblock -----------
+
+'copy#2' will now be used and 'copy#1' will be ignored.
+
+Changing the *state* variable set the n-th time:
+
+.. code-block:: text
+
+    0                                                                0x0ffff
+    +------------+------------+-------- -------+------------+------------+
+    |   copy     |   copy     |                |    copy    |   copy     |
+    |    #1      |    #2      |                |    #n-1    |    #n      |
+    +------------+------------+-------- -------+------------+------------+
+    |<- stride ->|<- stride ->|                |<- stride ->|<- stride ->|
+    |<---------------------------- eraseblock -------------------------->|
+
+'copy#n' will now be used and all other copies will be ignored.
+
+The next time the *state* variable set changes again, the whole block will be
+erased and the *state* variable set gets stored at the first position inside
+the eraseblock again. This reduces the need for a flash memory erase by factors.
+
+**NAND type flash memory is additionally characterized by**
+
+- organized in pages (size is a detectable, physical value)
+- writes can only happen in multiples of the page size (which much less than the eraseblock size)
+- partially writing a page can be limited in count or be entirely forbidden (in
+  the case of *MLC* NANDs)
+
+Example: NAND type flash memory with 128 kiB eraseblock size and 2 kiB page
+size and a 2 kiB write size
+
+.. code-block:: text
+
+    0                                                             0x20000
+    +------+------+------+------+---- ----+------+------+------+------+
+    | page | page | page | page |         | page | page | page | page |
+    |  #1  |  #2  |  #3  |  #4  |         | #61  | #62  | #63  | #64  |
+    +------+------+------+------+---- ----+------+------+------+------+
+    |<-------------------------- eraseblock ------------------------->|
+
+Writing the *state* variable set the very first time:
+
+.. code-block:: text
+
+    |<--- page #1---->|
+    +-------+---------+--
+    | copy  |         |
+    |  #1   |         |
+    +-------+---------+--
+    |<---- eraseblock ---
+
+'copy#1' will be used.
+
+Changing the *state* variable set the first time (e.g. writing it the second time):
+
+.. code-block:: text
+
+    |<-- page #1 -->|<-- page #2 -->|
+    +-------+-------+-------+-------+----
+    | copy  |       | copy  |       |
+    |  #1   |       |  #2   |       |
+    +-------+-------+-------+-------+----
+    |<--------- eraseblock --------------
+
+'copy#2' will now be used and 'copy#1' will be ignored.
+
+Changing the *state* variable set the 64th time:
+
+.. code-block:: text
+
+    |<-- page #1 -->|<-- page #2 -->|        |<- page #63 -->|<- page #64 -->|
+    +-------+-------+-------+-------+--    --+-------+-------+-------+-------+
+    | copy  |       | copy  |       |        | copy  |       | copy  |       |
+    |  #1   |       |  #2   |       |        |  #63  |       |  #64  |       |
+    +-------+-------+-------+-------+--    --+-------+-------+-------+-------+
+    |<----------------------------- eraseblock ----------------------------->|
+
+'copy#n' will now be used and all other copies will be ignored.
+
+The next time the *state* variable set changes again, the eraseblock will be
+erased and the *state* variable set gets stored at the first position inside
+the eraseblock again. This significantly reduces the need for a block erases.
+
+.. important:: One copy of the *state* variable set is limited to the page size
+   of the used backend (e.g. NAND type flash memory)
+
+Redundant *state* variable set copies
+-------------------------------------
+
+To avoid data loss when changing the *state* variable set, more than one
+*state* variable set copy can be stored into the backend. Whenever the *state*
+variable set changes, only one *state* variable set copy gets changed at a time.
+In the case of an interruption and/or power loss resulting into an incomplete
+write to the backend, the system can fall back to a different *state* variable
+set copy (previous *state* variable set).
+
+Direct Storage Backend Redundancy
+#################################
+
+For this kind of backend storage type a value for the stride size must be
+defined by the developer (refer to
+:ref:`backend-stridesize <barebox,state_backend_stridesize>`).
+
+It always stores **three** redundant copies of the backend-type. Keep this in
+mind when calculating the stride size and defining the backend size (e.g. the
+size of a partition).
+
+.. code-block:: text
+
+    +----------------+------+----------------+------+----------------+------+
+    | redundant copy | free | redundant copy | free | redundant copy | free |
+    +----------------+------+----------------+------+----------------+------+
+    |<---- stride size ---->|<---- stride size ---->|<---- stride size ---->|
+
+.. important:: The ``direct`` storage backend needs 8 bytes of additional space
+   per *state* variable set for its meta data. Keep this in mind when calculating
+   the stridesize. For example, if your variable set needs 8 bytes, the ``raw``
+   header needs 16 bytes and the ``direct`` storage backend additionally 8 bytes.
+   The full space for one *state* variable set is now 8 + 16 + 8 = 32 bytes.
+
+Circular Storage Backend Redundancy
+###################################
+
+**NOR type flash memory**
+
+Redundant copies of the *state* variable set are stored based on the memory's
+eraseblocks and this size is automatically detected at run-time.
+It needs a stride size as well, because a NOR type flash memory can be written
+on a byte-by-byte manner.
+In contrast to the ``direct`` storage backend redundancy, the
+stride size for the ``circular`` storage backend redundancy defines the
+side-by-side location of the *state* variable set copies.
+
+.. code-block:: text
+
+    |<X>|<X>|...
+    +--------------------------------+--------------------------------+--
+    |C#1|C#2|C#3|C#4|C#5|            |C#1|C#2|C#3|C#4|C#5|            |
+    +--------------------------------+--------------------------------+--
+    |<--------- eraseblock --------->|<--------- eraseblock --------->|<-
+    |<------- redundant area ------->|<------- redundant area ------->|<-
+
+*<X>* defines the stride size, *C#1*, *C#2* the *state* variable set copies.
+
+Since these kinds of MTD devices are partitioned, its a good practice to always
+reserve multiple eraseblocks for the barebox's *state* feature. Keep in mind:
+Even NOR type flash memories can be worn out.
+
+**NAND type flash memory**
+
+Redundant copies of the *state* variable set are stored based on the memory's
+eraseblocks and this size is automatically detected at run-time.
+
+.. code-block:: text
+
+    +------+------+--- ---+------+------+------+------+--- ---+------+------+--
+    | copy | copy |       | copy | copy | copy | copy |       | copy | copy |
+    |  #1  |  #2  |       | #63  | #64  |  #1  |  #2  |       | #63  | #64  |
+    +------+------+--- ---+------+------+------+------+--- ---+------+------+--
+    |<----------- eraseblock ---------->|<----------- eraseblock ---------->|<-
+    |<-------- redundant area --------->|<-------- redundant area --------->|<-
+
+Since these kinds of MTD devices are partitioned, its a good practice to always
+reserve multiple eraseblocks for the barebox's *state* feature. Keep in mind:
+NAND type flash memories can be worn out, factory bad blocks can exist from the
+beginning.
+
+Handling of Bad Blocks
+----------------------
+
+NAND type flash memory can have factory bad eraseblocks and more bad
+eraseblocks can appear over the life time of the memory. They are detected by
+the MTD layer, marked as bad and never used again.
+
+.. important:: If NAND type flash memory should be used as a backend, at least
+   three eraseblocks are used to keep three redundant copies of the *state*
+   variable set. You should add some spare eraseblocks to the backend
+   partition by increasing the partition's size to a suitable value to handle
+   factory bad eraseblocks and worn-out eraseblocks.
+
+Examples
+--------
+
+The following examples intends to show how to setup and interconnect all
+required components for various non-volatile memories.
+
+All examples use just one *state* variable of type *uint8* named ``variable``
+to keep them simple. For the ``raw`` backend-type it means one *state*
+variable set has a size of 17 bytes (16 bytes header plus one byte variables).
+
+.. note:: The mentioned ``aliases`` and the *state* variable set node entries
+   are members of the devicetree's root node.
+
+.. note:: For a more detailed description of the used *state* variable set
+   properties here, refer to :ref:`barebox,state`.
+
+NOR flash memories
+##################
+
+This type of memory can be written on a single byte/word basis (depending on its bus
+width), but must be erased prior writing the same byte/word again and erasing
+must happen on an eraseblock basis. Typical eraseblock sizes are 128 kiB or
+(much) larger for parallel NOR flashes and 4 kiB or larger for serial NOR
+flashes.
+
+From the Linux kernel perspective this type of memory is a *Memory Technologie
+Device* (aka 'MTD') and handled by barebox in the same manner. It needs a
+partition configuration.
+
+The following devicetree node entry defines some kind of NOR flash memory and
+a partition at a specific offset to be used as the backend for the
+*state* variable set.
+
+.. code-block:: text
+
+	norflash@0 {
+		backend_state_nor: partition@120000 {
+			[...]
+		};
+	};
+
+With this 'backend' definition its possible to define the *state* variable set
+content, its backend-type and *state* variable set layout.
+
+.. code-block:: text
+
+	aliases {
+		state = &state_nor;
+	};
+
+	state_nor: nor_state_memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "barebox,state";
+		magic = <0x512890a0>;
+		backend-type = "raw";
+		backend = <&backend_state_nor>;
+		backend-storage-type = "circular";
+		backend-stridesize = <32>;
+
+		variable {
+			reg = <0x0 0x1>;
+			type ="uint8";
+			default = <0x1>;
+		};
+	};
+
+NAND flash memories
+###################
+
+This type of memory can be written on a *page* base (typically 512 bytes,
+2048 or (much) larger), but must be erased prior writing the same page again and
+erasing must happen on an eraseblock base. Typical eraseblock sizes are
+64 kiB or (much) larger.
+
+From the Linux kernel perspective this type of memory is a *Memory Technologie
+Device* (aka 'MTD') and handled by barebox in the same manner. It needs a
+partition configuration.
+
+The following devicetree node entry defines some kind of NAND flash memory and
+a partition at a specific offset inside it to be used as the backend for the
+*state* variable set.
+
+.. code-block:: text
+
+	nandflash@0 {
+		backend_state_nand: partition@500000 {
+			[...]
+		};
+	};
+
+With this 'backend' definition its possible to define the *state* variable set
+content, its backend-type and *state* variable layout.
+
+.. code-block:: text
+
+	aliases {
+		state = &state_nand;
+	};
+
+	state_nand: nand_state_memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "barebox,state";
+		magic = <0xab67421f>;
+		backend-type = "raw";
+		backend = <&backend_state_nand>;
+		backend-storage-type = "circular";
+
+		variable {
+			reg = <0x0 0x1>;
+			type ="uint8";
+			default = <0x1>;
+		};
+	};
+
+SRAM
+####
+
+This type of memory can be written on a byte base and there is no need for an
+erase prior writing a new value.
+
+From the Linux kernel perspective this type of memory is a *Memory Technologie
+Device* (aka 'MTD') and handled by barebox in the same manner. It needs a
+partition definition.
+
+The following devicetree node entry defines some kind of SRAM memory and
+a partition at a specific offset inside it to be used as the backend for the
+*state* variable set.
+
+.. code-block:: text
+
+	sram@0 {
+		backend_state_sram: partition@10000 {
+			[...]
+		};
+	};
+
+With this 'backend' definition its possible to define the *state* variable set
+content, its backend-type and *state* variable layout.
+
+.. code-block:: text
+
+	aliases {
+		state = &state_sram;
+	};
+
+	state_sram: sram_state_memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "barebox,state";
+		magic = <0xab67421f>;
+		backend-type = "raw";
+		backend = <&backend_state_sram>;
+		backend-storage-type = "direct";
+		backend-stridesize = <32>;
+
+		variable {
+			reg = <0x0 0x1>;
+			type ="uint8";
+			default = <0x1>;
+		};
+	};
+
+EEPROM
+######
+
+This type of memory can be written on a byte base and must be erased prior
+writing, but in contrast to the other flash memories, an EEPROM does the erase
+of the address to be written to by its own, so its transparent to the
+application.
+
+While from the Linux kernel perspective this type of memory does not support
+partitions, barebox and the *state* userland tool will use partition definitions
+on an EEPROM memory as well, to exactly define the location in a generic manner
+within the EEPROM.
+
+.. code-block:: text
+
+	eeprom@50 {
+		partitions {
+			compatible = "fixed-partitions";
+			#size-cells = <1>;
+			#address-cells = <1>;
+			backend_state_eeprom: eeprom_state_memory@400 {
+				reg = <0x400 0x100>;
+				label = "state-eeprom";
+			};
+		};
+	};
+};
+
+With this 'backend' definition its possible to define the *state* variable set
+content, its backend-type and *state* variable layout.
+
+.. code-block:: text
+
+	aliases {
+		state = &state_eeprom;
+	};
+
+	state_eeprom: eeprom_memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "barebox,state";
+		magic = <0x344682db>;
+		backend-type = "raw";
+		backend = <&backend_state_eeprom>;
+		backend-storage-type = "direct";
+		backend-stridesize = <32>;
+
+		variable {
+			reg = <0x0 0x1>;
+			type ="uint8";
+			default = <0x1>;
+		};
+	};
+
+Frontend
 --------
 
-The ``state`` command can be used to store and manipulate the state. Using
-``state`` without argument lists you all available states with their name.
-``devinfo STATE_NAME`` shows you all variables and their values. ``state -s``
-stores the state.
+As frontend a *state* instance is a regular barebox device which has
+device parameters for the *state* variables. With this the variables can
+be accessed like normal shell variables. The ``state`` command is used
+to save/restore a *state* variable set to the backend device.
 
-Starting Barebox will automatically load the last written state. If loading the
-state fails the defaults are used.
+After initializing the variable can be accessed with ``$state.foo``.
+``state -s`` stores the *state* to the backend device.
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2017-08-15 13:47 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-15 13:46 Rework of the state/bootchooser feature documentaiton Juergen Borleis
2017-08-15 13:46 ` [PATCH 1/7] docs/DS1307: fix layout Juergen Borleis
2017-08-15 13:46 ` [PATCH 2/7] state: keep backward compatibility Juergen Borleis
2017-08-15 13:46 ` [PATCH 3/7] bootchooser: avoid a use after free Juergen Borleis
2017-08-15 13:46 ` [PATCH 4/7] bootchooser: allow an empty namespace Juergen Borleis
2017-08-15 13:46 ` [PATCH 5/7] docs: remove build warning Juergen Borleis
2017-08-15 13:46 ` [PATCH 6/7] state: add debugging help Juergen Borleis
2017-08-15 13:46 ` Juergen Borleis [this message]
2017-09-06 12:19 ` Rework of the state/bootchooser feature documentaiton Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170815134636.21236-8-jbe@pengutronix.de \
    --to=jbe@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox