6.2. Barebox state¶
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.
6.2.1. Devicetree state Node¶
A state node contains a description of a set of variables along with a place where the variable set gets stored.
6.2.1.1. Required Properties¶
compatible
: should bebarebox,state
magic
: a 32bit numberbackend
: phandle to persistent memorybackend-type
: defines the state variable set storage format- additionally a state node must have an alias in the
/aliases
node pointing to it.
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.
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.
The backend
property uses the phandle mechanism to link the state to
a real persistent memory. Refer Backend for
supported persistent memories.
The backend-type
should be raw
or dtb
. Refer
Backend Types for further details.
6.2.1.2. Optional Properties¶
backend-stridesize
: stride counted in bytes. See note below.backend-storage-type
: Defines the backend storage type todirect
,circular
ornoncircular
. If the backend memory needs to be erased prior a write it defaults to thecircular
storage backend type, for backend memories like RAMs or EEPROMs it defaults to thedirect
storage backend type.algo
: A HMAC algorithm used to detect manipulation of the data or header, sensible values follow this patternhmac(<HASH>)
, e.g.hmac(sha256)
. Only available for thebackend-type
raw
.keep-previous-content
: Check if a the bucket meta magic field contains other data than the magic value. If so, the backend will not write the state to prevent unconditionally overwrites of existing data.
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.
The backend-stridesize
is still optional but required whenever the
underlying backend doesn’t provide an information how to pad an instance of a
state variable set. This is valid for all underlying backends which support
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
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.
6.2.2. 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.
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.
6.2.2.1. Required Properties¶
reg
: Standardreg
property with#address-cells = <1>
and#size-cells = <1>
. Defines theoffset
andsize
of the variable in theraw
backend.size
must fit the nodetype
. Variables are not allowed to overlap.type
: Should beuint8
,uint32
,enum32
,mac
orstring
for the type of the variablenames
: Forenum32
values only, this specifies the possible values forenum32
.
6.2.2.2. Optional Properties¶
default
: The default value if the variable’s content cannot be read from the backend. Forenum32
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.
6.2.2.3. Variable Examples¶
uint8
:
uint8_example@0 {
reg = <0x0 0x1>;
type = "uint8";
default = <0x00>;
};
uint32
:
uint32_example@0 {
reg = <0x0 0x4>;
type = "uint32";
default = <100>;
};
enum32
:
enum_example@0 {
reg = <0x0 0x4>;
type = "enum32";
names = "value#1", "value#2";
default = <1>; /* selects "value#2" as the default */
};
mac
:
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
:
name {
reg = <0x0 0x10>;
type = "string";
};
In this example the length of the string is limited to 16 characters.
6.2.3. HMAC¶
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. Refer keystore - manage keys for
further details.
6.2.4. 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:
persistent_state_memory@01 {
compatible = "somevalue";
reg = <1>;
#address-cells = <1>;
#size-cells = <1>;
state: partition@0 {
label = "state";
reg = <0x0 0x100>;
};
};
The operating system’s devicetree defines instead:
persistent_state_memory@01 {
compatible = "somevalue";
reg = <1>;
};