04 - RAUC - A/B System Updates

Objectives

  • Best practices in OTA (Over the Air) upgrading embedded systems;
  • Installing Debian (finally!) as embedded rootfs!
  • Building fully-featured A/B images using RAUC;

Contents

Lecture

Welcome to the RAUC Image Creation exercise!

Mender (an alternative OTA solution) has a really good lecture about how A/B updates work. Though we will be using RAUC as lightweight update framework.

You will create a bootable disk image for an embedded system with multiple partitions (boot, rootfsA, rootfsB, data), install a kernel, configure U-Boot with environment support, and install RAUC in both rootfs partitions.

Oh, and you will also finally get to use a more familiar Linux distro as root filesystem: yep, Debian!

Everything will be scripted for reusability (don't worry, they are almost written, though you will need to fill in some TODOs).

Tasks

01. Preparations

Download here the starter archive containing skeleton files + scripts.

Extract it somewhere in a new directory (e.g., create rauc-lab).

The code structure will become (mostly is, but some are TODO) as follows:

rauc-lab/
├── artifacts/       # <-- you'll create this
│   ├── flash_spl.bin         # A working flash.bin image you already have
│   ├── flash_emmc.bin        # Your new flash.bin (see tasks)
│   ├── linux.itb             # A kernel image (after removing the initrd)
│   ├── uboot.env             # U-Boot environment variables (just the var file)
├── utils/
│   ├── ca.cert.pem
│   ├── rauc-mark-good.service
│   ├── system.conf
│   └── fstab                 # Optional custom fstab
├── scripts/         # <-- your main job to finish those!
│   ├── 05-debootstrap.sh
│   ├── 10-create-base-disk.sh
│   ├── 11-populate-disk-image.sh
│   ├── 20-modify-bootcmd.sh
│   ├── 21-install-boot.sh
│   └── 30-install-rauc.sh
├── run-all.sh               # Will run all scripts in order

Prerequisites

First, make sure you have these packages installed on your host system (they were already installed on the VM, so you can skip this):

sudo apt install qemu-user-static binfmt-support debootstrap parted dosfstools e2fsprogs u-boot-tools

Then, check that binfmt_misc is active and register the QEMU handler for aarch64:

grep aarch64 /proc/sys/fs/binfmt_misc/qemu-aarch64

If it’s empty, run:

sudo su
echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff:/usr/bin/qemu-aarch64-static:CF' > /proc/sys/fs/binfmt_misc/register
exit

For Arch Linux users: check out this guide for installable dependencies!

02. Disk image & Debian

You’ll be running scripts in ./scripts, either one by one or all together via ./run-all.sh.

The scripts are templates — you may need to complete missing parts (search for TODOs)!

2.1. Install Debian into an empty directory

Yes, really, you can easily do this!

You will use the debootstrap official tool to install a minimal Debian (you can also install deb-based derivatives like Ubuntu!) base system.

📄 Edit the 05-debootstrap.sh script.

Since we need to install the Debian binaries executable on a 64-bit ARM architecture, we will need to split the installation into two stages: first, the .deb (Debian install packages) are downloaded from a Debian mirror server and unpacked into the target rootfs directory. Afterwards, since Debian will need to run some scripts to setup its distro system, we must emulate the target architecture. Enter qemu which will help us to just that!

Finally, we need to obtain the artifacts/debrootfs.tar.gz archive with the contents of our newly-created Aarch64 Debian. Use tar to create a gzipped archive, and be sure to preserve permissions!

The final results should be something like:

-rw-r--r--  1 root  root  148M 2025-08-07 14:23 debrootfs.tar.gz

2.2. Create the base disk image

📄 File: 10-create-base-disk.sh

Your task:

  1. Use truncate or dd to allocate the image with the desired size;
  2. Modify the parted invocation (script);
  3. Add partitions for:
    1. rootfsA (ext4)
    2. rootfsB (ext4)
    3. data (ext4)

Make the partition have the labels documented above (as they are used throughout the RAUC scripts and/or in u-boot)!

2.3. Populate the rootfs partitions

📄 File: 25-populate-base-disk.sh

Subtasks:

  1. Mount the partitions created previously (already in script);
  2. Extract the previously-obtained Debian debrootfs.tar.gz on each rootfs A/B partition (a simple tar xf will suffice);

Note: you will lack flash_emmc.bin required by this script. So let's proceed without testing, for now.

Entering the rootfs

If you wish to enter your newly bootstrapped Debian rootfs, you can use the following script:

enter-rootfs.sh
#!/bin/bash
set -e
 
ROOTFS=$1
 
if [[ -z "$ROOTFS" ]] || [[ ! -d "$ROOTFS/usr/bin" ]]; then
    echo "[!] Invalid rootfs argument: '$ROOTFS'"
    exit 1
fi
 
cleanup() {
    echo "[*] Cleaning up..."
    for sub in dev/pts dev proc sys run; do
        if mountpoint -q "$ROOTFS/$sub"; then
            echo "    Unmounting $ROOTFS/$sub"
            sudo umount "$ROOTFS/$sub" || true
        fi
    done
}
trap cleanup EXIT
 
echo "[+] Binding chroot filesystems..."
for fs in dev dev/pts proc sys run; do
  sudo mount --bind "/$fs" "$ROOTFS/$fs"
done
 
echo "[+] Ensuring /etc/resolv.conf for DNS inside chroot"
sudo cp /etc/resolv.conf "$ROOTFS/etc/resolv.conf"
 
echo "[+] Entering your chroot shell..."
echo "Type exit to leave"
sudo chroot "$ROOTFS" /usr/bin/qemu-aarch64-static /bin/bash

You can even run apt install in there ;)

03. Bootloader [re]configuration

Modify the U-Boot script

For this task, you will need to configure u-boot with a default environment as documented in this previous lab.

Simply paste the recommended default and use menuconfig to enable it (don't worry about the bootcmd, we will replace it here with a custom script).

Now, edit the 20-modify-bootcmd.sh script and set the path to your default.env file. Read its source code to see what it does and run it!

Check out your default file again. It shoule have a quite large boot command concatenated from the source utils/boot.cmd.in script.

Now pay attention: make a backup of your current flash.bin file you used to boot using uuu -b spl. You'll need it later to flash the emmc, as the one you'll build in the following instructions will not work (you will override the boot command!). Put the backup file into artifacts as flash_spl.bin!

Let's get this over with: re-build your u-boot, copy all resulting binaries (uboot-imx/*.bin, uboot-imx/spl/*.bin) back into imx-mkimage/iMX93/, invoke the imx-mkimage make command again to obtain a new flash.bin file. Store it as artifacts/flash_emmc.bin (will get to reside on the eMMC persistent storage).

Kernel

We still have some work to do before generating the disk image…

We must pack our kernel + device tree again, but this time without the Buildroot initramfs (we don't need it since we've got 2xDebians now!). So back up your linux.its (surely you don't want to waste your work so far, right?), then modify the original and simply delete the initrd block from images and the ramdisk = “initrd”; property.

Rebuild the Linux FIT uImage to obtain your new linux.itb, which you'll then copy to rauc-lab/artifacts/linux.itb.

Now it's time to run 21-install-boot.sh. What's that? it wants a .env file? You can create an empty one ;)

04. RAUC

Finally, it comes down to installing RAUC into the Debian partitions.

📄 Our script: 15-install-rauc.sh is already complete. Feel free to read and understand it.

This script will:

  1. Mount both rootfsA and rootfsB
  2. Uses QEMU and chroot to install:
    1. rauc
    2. your ca.cert.pem (certificate used to sign the update images)
    3. system.conf
    4. rauc-mark-good.service
  3. Sets up /etc/fw_env.config, fstab, and enables systemd services

Finally, run it!

Just make sure:

  1. Ensure QEMU works inside chroot;
  2. Make sure rauc.service is enabled in both roots;

Generate the disk image

We can now run 25-populate-disk-image.sh. The artifacts/disk.img will be updated, Debian will be copied to the first 2 EXT4 partitions and the bootloader will be installed at 32KB offset (the SoC's BL1/BOOTROM wants it there).

Flashing the board

Power up the board. Use uuu -b emmc_all flash_spl.bin disk.img to flash it (hope you backed it up, since the modified flash_emmc.bin version won't work)!

Our Debian's default login: root + root ;)

Once Debian booted, check:

mount | grep rootfs
cat /etc/rauc/system.conf
ass/labs-2025/04.txt · Last modified: 2025/08/07 12:26 by florin.stancu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0