Skip to content

Commit

Permalink
docs: improve boot flow docs
Browse files Browse the repository at this point in the history
  • Loading branch information
koehlma committed Nov 24, 2023
1 parent 3e1c7db commit 64450ce
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 24 deletions.
8 changes: 4 additions & 4 deletions www/docs/guide/over-the-air-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ The usual partition layout of a Rugpi installation comprises seven partitions:
- Partition 6: The root partition of the B set.
- Partition 7: Contains any persistent state (see [State Management](./state-management)).

The bootloader specification specifies the default set of partitions.
The bootloader configuration specifies the default set of partitions.
We call the other, non-default set, the *spare set*.
An update is only possible if the hot set is also the default set.
That way, if anything goes wrong while installing the update, the system will boot into the previous known-good version by default.
Expand Down Expand Up @@ -101,10 +101,10 @@ rugpi-ctrl system commit
### On Atomicity of Commits

Note that commits are the only critical operation because they modify the default set.
This is done by temporarily remounting the config partition with the `autoboot.txt` such that it is writeable.
The `autoboot.txt` is then replaced as suggested by [Raspberry Pi's documentation on the `tryboot` mechanism](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#fail-safe-os-updates-tryboot).
This is done by temporarily remounting the bootloader configuration partition such that it is writeable.
For the `tryboot` and U-Boot boot flow, the `autoboot.txt` file and `bootpart.default.env` file are then replaced as suggested by [Raspberry Pi's documentation on the `tryboot` mechanism](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#fail-safe-os-updates-tryboot).
As the filesystem is FAT32, the automitcity of this operation cannot be guaranteed.
Still, Rugpi Ctrl does its best by first creating the new `autoboot.txt` and then replacing the old one with the new one by renaming it, and, the Linux kernel does guarantee atomicity for renaming.
Still, Rugpi Ctrl does its best by first creating a new file and then replacing the old one with the new one by renaming it, and, the Linux kernel does guarantee atomicity for renaming.
However, should the system crash during this process, the FAT32 filesystem may still be corrupted.
We think that this is an acceptable risk as the likelihood of it happening is very low and any alternatives, like swapping the MBR, may be problematic for other reasons.[^4]

Expand Down
38 changes: 18 additions & 20 deletions www/docs/internals/boot-flows.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,30 @@ sidebar_position: 2

## Tryboot

The `tryboot` boot flow works almost as described in [Raspberry Pi's documentation on the `tryboot` mechanism](https://www.raspberrypi.com/documentation/computers/config_txt.html#example-update-flow-for-ab-booting).
Instead of reading the `tryboot` flag, the hot partition is compared with the default partition to determine whether a commit is necessary.

## U-Boot

On older Raspberry Pi's, without the `tryboot` bootloader feature, we use [U-Boot](https://docs.u-boot.org/en/latest/) as an intermediate bootloader.
Instead of directly loading the Linux kernel, Raspberry Pi's bootloader is instructed to load U-Boot.
U-Boot is then responsible for booting the Linux kernel from the correct partition set.
This works in two stages.
First, U-Boot loads the first stage boot script `boot.scr` from the first partition.
This first stage is responsible for determining the hot partition set (default or spare).
After doing so, it will load the boot environment `boot.env` and second stage boot script `second.scr` from the hot partition set.
After loading these files, the first stage invokes the second stage boot script.
This has the advantage that the second stage script can be updated via the normal update mechanism.
Hence, additional device tree overlays or other boot time configurations can be deployed in a fail-safe way.

We use three *environment files*:

```text title="bootpart.default.env"
bootpart=2
```

```text title="boot_spare.env"
boot_spare=1
```

```text title="boot.env"
bootargs=console=...
...
```
For the first stage, two U-Boot environment files are used to determine the hot partition set.
The file `bootpart.default.env` specifies the default partition set.
The file `boot_spare.env` indicates whether to boot from the spare partition.

### On Atomicity of Commits
For the second stage, one U-Boot environment file is used.
The file `boot.env` contains the kernel command line arguments (generated from `cmdline.txt`) stored in the `bootargs` variable and may also override the kernel to boot (`kernel_file`).

The file `bootpart.default.env` takes over the role of `autoboot.txt`.
As it is stored on the FAT filesystem of the first partition, it is subject to the same atomicity guarantees.
We use U-Boot environment files with a CRC32 checksum.
Hence, if files are corrupted, they will not be loaded.

The file `boot_spare.env` takes over the role of `tryboot`.
It uses a CRC32 checksum.
Should it be corrupted, the default partition will be booted.
For further details, we refer to the [boot scripts](https://github.com/silitics/rugpi/tree/main/boot/u-boot/scripts).

0 comments on commit 64450ce

Please sign in to comment.