Yocto for Cubieboard in QEMU
- April 21, 2024
Root filesystem options
The root filesystem is an important part of the BSP (Board Support Package), since it holds all of the applications, configuration files and kernel modules.
There are several ways to obtain root filesystem for an embedded Linux system
- Prebuilt root filesystem - Ubuntu Base, Armbian
- Manual custom-built root filesystem using Busybox
- Guided/managed custom-built root filesystem using Buildroot or Yocto
In the previous newsletter a prebuilt root filesystem from OpenWRT was used, and in the QEMU Board Emulation tutorials Ubuntu base was used as the root filesystem.
While using a prebuilt root filesystem is quick and easy, it also has some downsides:
- not everyone has the same needs - there can be a lot of packages that are not used and need to be removed, and also a lot of packages can be missing, which would need to be installed somehow
- fixed versions of packages - prebuilt root filesystem comes with certain, fixed versions of packages and it can be hard/impossible to change them
- hard to maintain - once prebuilt image is customized to the needs, any future changes or improvements can be hard to handle, since everything has to be repackaged again
The prebuilt root filesystem can be an acceptable solution for rapid prototyping, or educational purposes, but it lacks the flexibility provided by the custom-built solutions.
In this post I will focus on Yocto, as a tool for guided/managed generation of custom-built root filesystem.
Yocto introduction
Yocto project provides tools and instructions used to build Board Support Package (BSP) and Linux distributions, especially for embedded targets. It is very configurable and provides fine grained control of output images.
Yocto builds everything, from native tools used to build the output products, cross-compiler and required libraries, to the final binary files and output image. This makes it also a reliable tool for reproducing builds.
A project in Yocto is organized into layers which contain configuration items and recipes for building applications and images. What is going to be build depends on image, machine and distribution that is selected, as well as local configuration parameters.
In the picture above, there are three layers with recipes for different packages. As mentioned previously, the image, machine and distribution that are selected influence the recipes that will be built into the output image.
Recipe B is present in both layers 3 and 1, but since layer 3 has higher priority, recipe B from layer 3 will be used.
Yocto layers
The specification of available layers is contained in the file called bblayers.conf
. That file holds list of paths to
layers on the disk.
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "1"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
${TOPDIR}/../sources/poky/meta \
${TOPDIR}/../sources/poky/meta-poky \
${TOPDIR}/../sources/poky/meta-yocto-bsp \
${TOPDIR}/../sources/meta-openembedded/meta-oe \
${TOPDIR}/../sources/meta-openembedded/meta-python \
${TOPDIR}/../sources/meta-sunxi \
"
The poky
is the starting layer, or to be precise a collection of layers, which hold all the tools for building a Yocto
distribution, as well as classes and recipes templates for building basic images.
The meta-openembedded
layer has recipes for a lot of useful applications. It contains additional layers for python,
networking, multimedia, etc.
The meta-sunxi
layer contains machine definitions for the Allwinner-based Systems on Chip, as well as adaptations to
some of the packages (like bootloader and Linux kernel, but also graphics support) so they are better suited for the
Allwinner chips.
In this example we will use only layers and options provided by the standard available layers.
Local configuration
The local configuration can be used to define overall build-system behavior or to override certain configuration settings.
In the poky
layer there is a default local.conf
that will be used.
Building and running images in QEMU
Prerequisites
Before Yocto image can be built, several packages must be installed:
sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib \
build-essential chrpath socat cpio python3 python3-pip python3-pexpect \
xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa \
libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev
For details look at Yocto reference manual
Preparing environment
There are several ways to organize and maintain the Yocto build environment:
- using google
repo
tool to manage the layers - using a standard git repository with layers as submodules
In this post we will use a third approach, where we will manually clone all needed repositories and prepare the
bblayers.conf
and local.conf
files. This is done this way only for educational purposes, in a real use-case one of
the two approaches listed above should be used.
Environment organization
The file structure we will use is sketched in the following block
.
├─ build/
│ └─ conf/
│ ├─ bblayers.conf
│ └─ local.conf
├─ downloads/
├─ sources/
│ ├─ meta-openembedded/
│ ├─ meta-sunxi/
│ └─ poky/
└─ sstate-cache/
The build
and build/conf
directories will be created automatically during the environment initialization, we just
need to create the .conf
layers inside it.
Besides the files and directories we have already mentioned, two additional directories will be created
downloads
, where archives and git repositores with sources for packages are downloaded and kept,sstate-cache
, where intermediate build products for reuse will be stored during the build process.
The sstate-cache
directory can speed up rebuilds, or different flavor builds, since packages that are not changed will
be reused.
Initializing environment
We will start by downloading the layers
mkdir -p yocto/sources && cd yocto
git clone git://git.yoctoproject.org/poky -b kirkstone sources/poky
git clone https://github.com/openembedded/meta-openembedded -b kirkstone sources/meta-openembedded
git clone https://github.com/linux-sunxi/meta-sunxi -b kirkstone sources/meta-sunxi
After the layers have been downloaded, we can initialize the environment and create build/conf
using
. ./sources/poky/oe-init-build-env build
This command will create the bblayers.conf
and local.conf
from templates and enter the build
directory.
The conf/bblayers.conf
should be edited to add the meta-openembedded
and meta-sunxi
layers. The final
bblayers.conf
file should look like
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
${TOPDIR}/../sources/poky/meta \
${TOPDIR}/../sources/poky/meta-poky \
${TOPDIR}/../sources/poky/meta-yocto-bsp \
${TOPDIR}/../sources/meta-openembedded/meta-oe \
${TOPDIR}/../sources/meta-openembedded/meta-python \
${TOPDIR}/../sources/meta-sunxi \
"
We can also add two extra lines to the conf/local.conf
, in order to make use of the downloads
and sstate-cache
directories.
cat >> conf/local.conf <<EOF
DL_DIR = "\${TOPDIR}/../downloads/"
SSTATE_DIR = "\${TOPDIR}/../sstate-cache/"
EOF
Building and running images
Before running a build, we need to enter the build
directory,
The build is started using the following command
# build command
DISTRO=<selected_distribution> MACHINE=<selected_machine> bitbake <selected_image>
In our case, the MACHINE
will be set to cubieboard
, the DISTRO
to poky
, and we will use the core-image-minimal
image, so the build command will be
DISTRO=poky MACHINE=cubieboard bitbake core-image-minimal
Important build products will be placed in ./tmp/deploy/images/cubieboard
. The image file will have extension
*.sunxi-sdimg
. This is the SD card image which can be either copied (dd
) to an SD card image created with
qemu-img
, or can be just resized using qemu-img
to a power of 2 size. For instance
qemu-img resize ./tmp/deploy/images/cubieboard/core-image-minimal-cubieboard.sunxi-sdimg 1G
For instructions on using
qemu-img
instructions from QEMU Board Emulation tutorial can be used
Testing SD card boot
QEMU can be started using the following command
qemu-system-arm -M cubieboard -m 1G -nographic \
-drive file=./tmp/deploy/images/cubieboard/core-image-minimal-cubieboard.sunxi-sdimg,format=raw,if=sd \
-net nic -net tap,ifname=qemu-tap0,script=no
Poky (Yocto Project Reference Distro) 4.0.17 cubieboard /dev/ttyS0
cubieboard login:
The board went through the SPL -> U-Boot -> Linux boot process and waits for login. There is only the root
account
(without password) configured, so it can be used to login to the system.
The network connectivity can be enabled following instructions from QEMU Board Emulation Tutorial
For more details about the Yocto configuration, with more detailed example, the Cubieboard Yocto tutorial can be followed.