Raw flash

This chapter introduces the technical details of raw flash support in Mender.

Overview

Support for raw flash memory under Linux is in general more complicated than
working with block devices. It is advised to have a fully working bootloader,
kernel and rootfs before introducing Mender.

As an example, to illustrate potential pain points we will use a Versatile
Express CortexA9x4 board, emulated under QEMU (vexpress-a9 target). The board
comes with 128MB of CFI NOR flash, provided in form of 2 * 64MB dies. Respective
details may slightly differ for NAND flash or SPI NOR flash devices.

Mender

The Mender Yocto layer comes with support for the following raw flash boards in
the main tree:

Toradex Colibri VF50/VF61 meta-mender-toradex-nxp

vexpress-a9 emulated by QEMU meta-mender-qemu

Both layers provide a set of patches based on their respective upstream U-Boot
sources and can be used as a reference when implementing your raw flash based
machine.

QEMU

It is possible to build a Yocto image and inspect all the details of Mender
integration by adding the meta-mender-qemu layer to the build. The layer
defines a vexpress-qemu-flash machine and includes all necessary pieces to
enable MTD and UBI support.

In order to test raw flash support under QEMU, a QEMU version >= 2.9 is required (see the output of qemu-system-arm --version command). Earlier versions contain a bug in CFI flash support that renders flash support on vexpress-a9 unusable.

The QEMU_SYSTEM_ARM environment variable can be used to provide a path to qemu-system-arm binary. When empty or not defined, the script will call qemu-system-arm available in your $PATH.

Raw flash devices, partitioning

Using raw flash devices under Linux is more complicated compared to typical
block devices such as hard disks or eMMC flash. Block devices typically come
with a partition table, using either the MBR or GPT formats, that enables
discovery and identification of existing partitions. In the case of raw flash
devices, no partition tables are in use. Instead, the kernel must be informed
about existing partitions, their start locations and sizes. This can achieved
using a number of different methods:

UBI and UBI File System

The ubinize and mkfs.ubifs arguments are a little complicated to get right.
One can use mtdinfo in a running system to obtain a set a reasonable defaults.
Using the vexpress-a9 QEMU target as an example:

Note that these settings will generally be different depending on the type of
flash memory.

Once determined, the parameters for mkfs.ubifs and ubinize must be set in
the Yocto configuration using MKUBIFS_ARGS and UBINIZE_ARGS variables
respectively. Since these parameters are a specific for given board, it is
possible they may already be set by a corresponding machine configuration.

U-Boot

To enable UBI support in U-Boot and integrate it with the kernel you will need
to enable at least these configuration options in U-Boot:

CONFIG_CMD_UBI

CONFIG_CMD_UBIFS

CONFIG_MTD_DEVICE

CONFIG_MTD_PARTITIONS

CONFIG_CMD_MTDPARTS

CONFIG_LZO

Optionally, to match the kernel configuration, you may need to set
CONFIG_MTD_CONCAT to enable automatic concatenation of neighboring flash
devices into a single one.

When using UBI you may need to set MENDER_STORAGE_RESERVED_RAW_SPACE to
account for space lost to UBI metadata.

These settings affect the calculated rootfs size.

Note that the calculated rootfs size (i.e. volume size) is different from the actual amount of data that can be stored in rootfs. The difference is caused by compression. To set an upper boundary on the amount of rootfs data, you can define IMAGE_ROOTFS_MAXSIZE.

U-Boot integration

For U-Boot, on top of options listed in U-Boot you will need to
enable the options required by Mender listed
in U-Boot integration.

The U-Boot boot process remains very much the same as described
in integration points with the
addition of a call to mender_setup script (using vexpress-a9 as an example):

Note that U-Boot places some constraints on parameter expansion, for this reason
the parameter ubiargs is no longer set by default environment. Instead it is
set by the intermediate set_ubiargs script.