10. Working with Rauc System

The RAUC is the software update mechanism used to update the CC pilot devices starting from CC Linux 4.0. The detailed information about the RAUC can be found in the CCLinux-RaucGuide [2] and how to update the device with RAUC can be found in the CCLinux-SoftwareGuide [1]. This section gives more details about how to work with RAUC related things such as boot up scripts, configurations and the location of configurations,etc.

10.1 Recipe for creating Rauc bundles

Once the RAUC is setup on the target, we need to create update bundles to update the target. Yocto support for using RAUC is provided by the meta-rauc layer *[4.2.17]*. Here is an example yocto rauc bundle recipe for ‘*CCpilot-v700-4.x.x.x-system-update-bundle.bb*

DESCRIPTION = "V700 system update bundle generator"

inherit bundle

RAUC_BUNDLE_COMPATIBLE = "CrossControl V700"
RAUC_BUNDLE_SLOTS = "bootloader rootfs appfs"
RAUC_BUNDLE_FORMAT = "verity"

# Slot bootloader
RAUC_SLOT_bootloader = "imx-boot"
RAUC_SLOT_bootloader[file] = "imx-boot.img"
RAUC_SLOT_bootloader[depends] = "imx-boot:do_deploy"

# Slot rootfs
RAUC_SLOT_rootfs = "ccpilot-v700-release"
RAUC_SLOT_rootfs[fstype] = "ext4"
RAUC_SLOT_rootfs[adaptive] = "block-hash-index"

# Slot appfs
RAUC_SLOT_appfs = "ccpilot-v700-appfs"
RAUC_SLOT_appfs[fstype] = "ext4"
RAUC_SLOT_appfs[adaptive] = "block-hash-index"

RAUC_KEY_FILE = "${COREBASE}/../meta-cc/meta-bsp-v700/recipes-core/rauc/files/development-1.key.pem"
RAUC_CERT_FILE = "${COREBASE}/../meta-cc/meta-bsp-v700/recipes-core/rauc/files/development-1.cert.pem"

10.1.1 Rauc Development Certificates

The RAUC bundle format consists of the images and a manifest, contained in a SquashFS image. The SquashFS is followed by a public key signature over the full image. The signature is stored (together with the signer’s certificate) in the CMS format. Before installation, the signer certificate is verified against the keyring(s) already stored on the system and the signer’s public key is then used to verify the bundle signature.

RAUC uses OpenSSL as a library for signing and verification of bundles.

For development purpose, a CA root certificate file, a developement keyring and a development certificate file based on the CA root certificate is created using OpenSSL. These files will be located in the recipes-core of meta-bsp-<platform>. refer *[4.2.5]*

The CA ceritificate will end up in ‘*system.conf*’ file

[keyring]
path=/etc/rauc/ca.cert.pem

and the development certificate and keyring will be used to create a bundle

RAUC_KEY_FILE = "${COREBASE}/../meta-cc/meta-bsp-v700/recipes-core/rauc/files/development-1.key.pem"
RAUC_CERT_FILE = "${COREBASE}/../meta-cc/meta-bsp-v700/recipes-core/rauc/files/development-1.cert.pem"

The rauc bundle created with the development keyring and ceritificate will be verified against the CA root certificate in the ‘*system.conf*’ file when updating the system.

10.2 Rauc System Conf File

A configuration file named system.conf which is a part of root file system describes the number and type of available slots. This file is loaded from /etc/rauc/ and it is used to validate storage locations for update images. Each board type requires its special configuration.

Below is an example of how the *system.conf* file looks for one of the platform:

[system]
compatible=CrossControl V700
bootloader=uboot
data-directory=/data/rauc
bundle-formats=-plain

[keyring]
path=/etc/rauc/ca.cert.pem

[log.install-log]
filename=install.log
events=install
format=readable
max-size=100K
max-files=5

[slot.bootloader.0]
device=/dev/mmcblk1
type=boot-emmc
install-same=false

[slot.rootfs.0]
device=/dev/mmcblk1p2
type=ext4
bootname=A
install-same=false

[slot.rootfs.1]
device=/dev/mmcblk1p3
type=ext4
bootname=B
install-same=false

[slot.appfs.0]
device=/dev/mmcblk1p4
type=ext4
parent=rootfs.0
install-same=false

[slot.appfs.1]
device=/dev/mmcblk1p5
type=ext4
parent=rootfs.1
install-same=false

The system conf file will be same for all the platforms with uboot bootloader, but for X1200 the bootloader is grub. So the system conf file will be different only on the bootloader part, but rest of the conf will be same.

[system]
compatible=CrossControl X1200
bootloader=grub
grubenv=/efi/EFI/BOOT/grubenv
data-directory=/data/rauc
bundle-formats=-plain

[slot.efi.0]
device=/dev/mmcblk0
type=boot-gpt-switch
region-start=1M
region-size=256M
install-same=false

10.3 Utils needed by Rauc

Rauc binary needs certain firmware utils on the kernel to set certain bootloader environmental variables from the kernel after the system update. The utils needed is same for all the platforms which uses uboot as bootloader and only differs for X1200 which uses grub as a bootloader.

Table 1 shows the kernel utils needed for different platforms.

Table 1: Kernel Utilities needed by RAUC

V700/V1x00/Vx10/Yukon

X1200

fw_setenv / fw_printenv

grub-editenv

Note

‘fw-setenv’ and ‘fw-printenv’ are the uboot fw utils will be installed into the target by the libubootenv package. Make sure libubootenv image ends up in the image.

Note

‘grub-editenv’ will be installed into the target by default by the Grub bootloader.

10.4 Firmware environment config

The environmental variables either from U-Boot or Grub will end up in the boot partition on the target.

  1. The U-Boot fw utils (fw_setenv / fw_printenv) will look for config file ‘fw_env.config’ file in the /etc directory where to set or edit the U-Boot environmental variables.

  2. The Grub util (grub_editenv) will look for ‘grubenv’ file in the /efi/EFI/BOOT directory of boot partition to set or edit the Grub environmental variables.

10.5 Rauc Boot Script

To enable handling of redundant booting into Slot A or B, manual boot scripting is required. The boot script will be same for all the devices (V700/V1x00/Vx10/Yukon) that uses U-Boot, but differs for X1200 which uses Grub as bootloader. The boot script differs for U-Boot and grub, to store and modify variables in its Environment. Properly configured, the environment can be accessed both from the bootloader itself as well as from Linux userspace.

The default RAUC U-Boot and Grub boot selection implementation requires a boot script using specific set of variables that are persisted to the environment as stateful slot selection information.

Note

The boot script variables will be different for U-Boot and Grub.

10.5.1 Rauc boot script for U-Boot

The U-Boot Rauc boot script will be into implemented into the board header file in the uboot source as a patch.

"test -n "${BOOT_ORDER}" || env set BOOT_ORDER "A B"; "
"test -n "${BOOT_A_LEFT}" || env set BOOT_A_LEFT 3; "
"test -n "${BOOT_B_LEFT}" || env set BOOT_B_LEFT 3; "
"env set rauc_slot; "
"env set mmcpartroot; "
"env set mmcroot; "
"for BOOT_SLOT in "${BOOT_ORDER}"; do "
    "if test "x${mmcpartroot}" != "x"; then "
    "; "
    "elif test "x${BOOT_SLOT}" = "xA"; then "
        "if itest ${BOOT_A_LEFT} -gt 0; then "
            "setexpr BOOT_A_LEFT ${BOOT_A_LEFT} - 1; "
            "echo "Booting valid RAUC slot A, ${BOOT_A_LEFT} attempts remaining"; "
            "setenv rauc_slot "A"; "
            "setenv mmcpartroot 2; "
            "setenv mmcroot /dev/mmcblk1p2; "
        "fi; "
    "elif test "x${BOOT_SLOT}" = "xB"; then "
        "if itest ${BOOT_B_LEFT} -gt 0; then "
            "setexpr BOOT_B_LEFT ${BOOT_B_LEFT} - 1; "
            "echo "Booting valid RAUC slot B, ${BOOT_B_LEFT} attempts remaining"; "
            "setenv rauc_slot "B"; "
            "setenv mmcpartroot 3; "
            "setenv mmcroot /dev/mmcblk1p3; "
        "fi; "
    "fi; "
"done; "
"if test -n "${mmcpartroot}"; then "
    "run mmcrootargs; "
    "run mmcargs; "
    "saveenv; "
"else "
    "echo "No valid RAUC slot found. Resetting attempts to 3"; "
    "setenv BOOT_A_LEFT 3; "
    "setenv BOOT_B_LEFT 3; "
    "saveenv; "
    "reset; "
"fi; "

10.5.2 Rauc boot script for Grub

The Grub Rauc boot script will be implemented in the ‘grub.cfg’ file of grub-bootconf which will end up in the boot partition /efi/EFI/BOOT/

serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
# default boot to Main A
default=0
# timeout 1 second
timeout=1

set ORDER="A B"
set A_OK=0
set B_OK=0
set A_TRY=0
set B_TRY=0
set RAUC_SLOT=A
load_env --file=(hd0,1)/EFI/BOOT/grubenv

# select bootable slot
for SLOT in $ORDER; do
    if [ "$SLOT" == "A" ]; then
        INDEX=0
        OK=$A_OK
        TRY=$A_TRY
        A_TRY=1
    fi
    if [ "$SLOT" == "B" ]; then
        INDEX=1
        OK=$B_OK
        TRY=$B_TRY
        B_TRY=1
    fi
    if [ "$OK" -eq 1 -a "$TRY" -eq 0 ]; then
        default=$INDEX
        break
    fi
done

# reset booted flags
if [ "$default" -eq 0 ]; then
    if [ "$A_OK" -eq 1 -a "$A_TRY" -eq 1 ]; then
        A_TRY=0
    fi
    if [ "$B_OK" -eq 1 -a "$B_TRY" -eq 1 ]; then
        B_TRY=0
    fi
fi

save_env --file=(hd0,1)/EFI/BOOT/grubenv A_TRY A_OK B_TRY B_OK ORDER FACTORY_RESET

ROOTARGS="rootwait ro rootfstype=ext4 device=/dev/mmcblk0 rwdevice=/dev/mmcblk0p6 rwfstype=ext4 rwreset=no"
BOOTARGS="console=ttyS5,115200 net.ifnames=0 panic=60 quiet intel_iommu=off"

menuentry "Main A (OK=$A_OK TRY=$A_TRY)"{
    linux (hd0,2)/boot/bzImage LABEL=root_A root=/dev/mmcblk0p2 $ROOTARGS $BOOTARGS rauc.slot=A
    initrd (hd0,2)/boot/microcode.cpio
    set RAUC_SLOT=A
    save_env --file=(hd0,1)/EFI/BOOT/grubenv RAUC_SLOT
}

menuentry "Main B (OK=$B_OK TRY=$B_TRY)"{
    linux (hd0,3)/boot/bzImage LABEL=root_B root=/dev/mmcblk0p3 $ROOTARGS $BOOTARGS rauc.slot=B
    initrd (hd0,3)/boot/microcode.cpio
    set RAUC_SLOT=B
    save_env --file=(hd0,1)/EFI/BOOT/grubenv RAUC_SLOT
}