summaryrefslogtreecommitdiffstats
path: root/Documentation/user/state.rst
blob: 07743df0cbda6ccc065622d3293a058924730e33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
.. _state_framework:

Barebox State Framework
=======================

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 needed for storing a *state* variable set:

- disk like devices: SD, (e)MMC, ATA
- all kinds of NAND and NOR flash memories (mtd)
- 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) default 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).
- memory cells 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**

- memory cells 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**

- it is 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 in 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, it's a good practice to always
reserve multiple eraseblocks for the barebox' *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, it's a good practice to always
reserve multiple eraseblocks for the barebox' *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 intend 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 it's 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@0 {
			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 it's 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@0 {
			reg = <0x0 0x1>;
			type ="uint8";
			default = <0x1>;
		};
	};

SD/eMMC and ATA
###############

The following devicetree node entry defines some kind of SD/eMMC memory and
a partition at a specific offset inside it to be used as the backend for the
*state* variable set. Note that currently there is no support for on-disk
partition tables. Instead, an ofpart partition description must be used. You
have to make sure that this partition does not conflict with any other partition
in the partition table.

.. code-block:: text

	backend_state_sd: part@100000 {
		label = "state";
		reg = <0x100000 0x20000>;
	};

With this 'backend' definition it's possible to define the *state* variable set
content, its backend-type and *state* variable layout.

.. code-block:: text

	aliases {
		state = &state_sd;
	};

	state_sd: state_memory {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "barebox,state";
		magic = <0xab67421f>;
		backend-type = "raw";
		backend = <&backend_state_sd>;
		backend-stridesize = <0x40>;

		variable@0 {
			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 it's 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@0 {
			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 it's 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@0 {
			reg = <0x0 0x1>;
			type ="uint8";
			default = <0x1>;
		};
	};

Frontend
--------

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.

After initializing the variable can be accessed with ``$state.foo``.
``state -s`` stores the *state* to the backend device.