Pre-requisites: a Yocto Board Support Package (BSP) layer for your particular board. It should be compatible to the Yocto releases balenaOS supports.
Repositories used to build balenaOS host Operating System (OS) are typically named balena-<board-family>
. For example, consider balena-raspberrypi which is used for building the OS for Raspberryi Pi, or balena-intel repository which can be used to build a balena.io image for the Intel NUC boards.
Contributing support for a new board consists of creating a Yocto layer that includes:
- general hardware support for the specific board,
- the balenaOS-specific software features,
- deployment-specific features (i.e. settings to create SD card, USB thumb drive, or self-flashing images)
The following documentations walks you through the steps of creating such a Yocto package. Because of the substantial difference between the hardware of many boards, this document provides general directions, and often it might be helpful to see the examples of already supported boards. The list of the relevant repositories is found at the end of this document.
The balena-<board-family>
repositories use git submodules for including required Yocto layers from the relevant sub-projects.
The root directory contains:
Directories |
---|
layers |
balena-yocto-scripts (git submodule) |
and
Files |
---|
CHANGELOG.md |
LICENSE |
README.md |
VERSION |
repo.yml |
<board-name>.svg |
coffee file(s) |
Note: you add submodules by git submodule add <url> <directory>
, see the git documentation for more details.
One or more files named <board-name>.coffee
, where <board-name>
is equal to the corresponding yocto-machine-name
. Should add one for each of the boards that the repository adds support for (eg. raspberry-pi3.coffee
for Raspberry Pi 3 in balena-raspberrypi
). This file contains information on the Yocto build for the specific board, in CoffeeScript format. A minimal version of this file, using Raspberry Pi 3 as the example, would be:
module.exports =
yocto:
machine: 'raspberrypi3'
image: 'resin-image'
fstype: 'resinos-img'
version: 'yocto-jethro'
deployArtifact: 'resin-image-raspberrypi3.resinos-img'
compressed: true
The layout for the layers
directory:
├── CHANGELOG.md
├── LICENSE
├── README.md
├── VERSION
├── repo.yml
├── <board-name-1>.svg
├── <board-name-2>.svg
├── layers
│ ├── meta-openembedded
│ ├── meta-<vendor>
│ ├── meta-balena
│ ├── meta-balena-<board-family>
│ ├── oe-meta-go
│ └── poky
├── <board-name-1>.coffee
├── <board-name-2>.coffee
...
└── balena-yocto-scripts
The layers
directory contains the git submodules of the yocto layers used in the build process. This normally means the following components are present:
- poky at the version/revision required by the board BSP
- meta-openembedded at the revision poky uses
- meta-balena using the master branch
- meta-rust at the revision poky uses
- Yocto BSP layer for the board (for example, the BSP layer for Raspberry Pi is meta-raspberrypi)
- any additional Yocto layers required by the board BSP (check the Yocto BSP layer of the respective board for instructions on how to build the BSP and what are the Yocto dependencies of that particular BSP layer)
In addition to the above git submodules, the layers
directory requires a meta-balena-<board-family>
directory (please note this directory is not a git submodule). This directory contains the required customization for making a board balena.io enabled. For example, the balena-raspberrypi repository contains the directory layers/meta-balena-raspberrypi
to supplement the BSP from layers/meta-raspberrypi
git submodule, with any changes that might be required by balenaOS.
This directory contains optional and mandatory directories:
Mandatory | Optional (as needed) |
---|---|
conf |
recipes-containers/docker-disk |
recipes-core/images |
|
recipes-kernel/linux directory |
|
recipes-support/resin-init |
layer.conf
, see the layer.conf frommeta-balena-raspberrypi
for an example, and see Yocto documentationsamples/bblayers.conf.sample
file in which all the required Yocto layers are listed, see this bblayers.conf.sample frommeta-balena-raspberrypi
for an example, and see the Yocto documentationsamples/local.conf.sample
file which defines part of the build configuration (see the meta-balena README.md for an overview of some of the variables use in thelocal.conf.sample
file). An existing file can be used (e.g. local.conf.sample) but making sure the "Supported machines" area lists the appropriate machines this repository is used for. See also the Yocto documentation.
Which contains at least a resin-image.bbappend
file. Depending on the type of board you are adding support for, you should have your device support either just resin-image
or both resin-image-flasher
and resin-image
. Generally, resin-image
is for boards that boot directly from external storage (these boards do not have internal storage to install balena.io on). resin-image-flasher
is used when the targeted board has internal storage so this flasher image is burned onto an SD card or USB stick that is used for the initial boot. When booted, this flasher image will automatically install balena.io on internal storage.
The resin-image.bbappend
file shall define the following variables:
-
IMAGE_FSTYPES_<yocto-machine-name>
: this variable is used to declare the type of the produced image. It can be ext3, ext4, resinos-img etc. The usual type for a board that can boot from SD card, USB, is "resinos-img". -
RESIN_BOOT_PARTITION_FILES_<yocto-machine-name>
: this allows adding files from the build's deploy directory into the vfat formatted resin-boot partition (can be used to add bootloader config files, first stage bootloader, initramfs or anything else needed for the booting process to take place for your particular board). If the board uses different bootloader configuration files when booting from either external media (USB thumb drive, SD card etc.) or from internal media (mSATA, eMMC etc) then you would want to make use of this variable to make sure the different bootloader configuration files get copied over and further manipulated as needed (seeINTERNAL_DEVICE_BOOTLOADER_CONFIG_<yocto-machine-name>
andINTERNAL_DEVICE_BOOTLOADER_CONFIG_PATH_<yocto-machine-name>
below). Please note that you only reference these files here, it is the responsibility of a.bb
or.bbappend
to provide and deploy them (for bootloader config files this is done with an append typically inrecipes-bsp/<your board's bootloader>/<your board's bootloader>.bbappend
, see balena-intel grub bbappend for an example).
It is a space separated list of items with the following format: FilenameRelativeToDeployDir:FilenameOnTheTarget. If FilenameOnTheTarget is omitted then the FilenameRelativeToDeployDir will be used.
For example to have the Intel NUC bzImage-intel-corei7-64.bin
copied from deploy directory over to the boot partition, renamed to vmlinuz
:
```sh RESIN_BOOT_PARTITION_FILES_nuc = "bzImage-intel-corei7-64.bin:vmlinuz" ```
The resin-image-flasher.bbappend
file shall define the following variables:
IMAGE_FSTYPES_<yocto-machine-name>
(see above)RESIN_BOOT_PARTITION_FILES_<yocto-machine-name>
(see above). For example, if the board uses different bootloader configuration files for booting from SD/USB and internal storage (see below the use ofINTERNAL_DEVICE_BOOTLOADER_CONFIG
variable), then make sure these files end up in the boot partition (i.e. they should be listed in thisRESIN_BOOT_PARTITION_FILES_<yocto-machine-name>
variable)
Shall contain a .bbappend
to the kernel recipe used by the respective board. This kernel .bbappend
must "inherit kernel-resin" in order to add the necessary kernel configs for using with balena.io
Shall contain a resin-init-flasher.bbappend
file if you intend to install balena.io to internal storage and hence use the flasher image.
resin-init-flasher.bbappend
should define the following variables:
-
INTERNAL_DEVICE_KERNEL_<yocto-machine-name>
: used to identify the internal storage where balena.io will be written to. -
INTERNAL_DEVICE_BOOTLOADER_CONFIG_<yocto-machine-name>
: used to specify the filename of the bootloader configuration file used by your board when booting from internal media. Must be the same as the FilenameOnTheTarget parameter of the bootloader internal config file used in theRESIN_BOOT_PARTITION_FILES_<yocto-machine-name>
variable fromrecipes-core/images/resin-image-flasher.bbappend
. -
INTERNAL_DEVICE_BOOTLOADER_CONFIG_PATH_<yocto-machine-name>
: used to specify the relative path, including filename, to the resin-boot partition whereINTERNAL_DEVICE_BOOTLOADER_CONFIG_<yocto-machine-name>
will be copied to.For example, setting
sh INTERNAL_DEVICE_BOOTLOADER_CONFIG_intel-corei7-64 = "grub.cfg_internal" ```` and
sh INTERNAL_DEVICE_BOOTLOADER_CONFIG_PATH_intel-corei7-64 = "/EFI/BOOT/grub.cfg" ``` will result that after flashing the filegrub.cfg
_internal is copied with the name `grub.cfg` to the /EFI/BOOT/ directory on the resin-boot partition. -
BOOTLOADER_FLASH_DEVICE
: used to identify the internal storage where the bootloader needs to be flashed to. This is only the case usually when the bootloader needs to be in a SPI flash like memory where the bootrom code expect it to read it from raw disk instead from a partition. Note that ifBOOTLOADER_FLASH_DEVICE
is set, then alsoBOOTLOADER_IMAGE
,BOOTLOADER_BLOCK_SIZE_OFFSET
andBOOTLOADER_SKIP_OUTPUT_BLOCKS
need to be set. -
BOOTLOADER_IMAGE
: used to specify the name of the bootloader binary, from the resin-boot partition, that is to be written toBOOTLOADER_FLASH_DEVICE
. -
BOOTLOADER_BLOCK_SIZE_OFFSET
: used to specify the block size with whichBOOTLOADER_IMAGE
is to be written toBOOTLOADER_FLASH_DEVICE
. -
BOOTLOADER_SKIP_OUTPUT_BLOCKS
: used to specify how many blocks of sizeBOOTLOADER_BLOCK_SIZE_OFFSET
need to be skipped fromBOOTLOADER_FLASH_DEVICE
when writingBOOTLOADER_IMAGE
to it.Note: Some hardware requires the use of a MLO (a.k.a. SPL - secondary program loader) that is to be copied in static RAM and executed from there (static RAM is small in size) and this first stage bootloader is responsible for initializing the regular RAM and then copying the regular bootloader to this regular RAM and passing execution to it. For this purpose a second set of variables called BOOTLOADER_FLASH_DEVICE_1, BOOTLOADER_IMAGE_1, BOOTLOADER_BLOCK_SIZE_OFFSET_1 and BOOTLOADER_SKIP_OUTPUT_BLOCKS_1 can be used to accomodate this use case.
For example, setting
sh BOOTLOADER_FLASH_DEVICE = "mtdblock0"
sh BOOTLOADER_IMAGE = "u-boot.imx"
sh BOOTLOADER_BLOCK_SIZE_OFFSET = "1024"
andsh BOOTLOADER_SKIP_OUTPUT_BLOCKS = "3"
will result that the file u-boot.imx from the resin-boot partition is written to /dev/mtdblock0 with a block size of 1024 bytes and after the first 3 * 1024 bytes of /dev/mtdblock0.
and the optional ones are:
Which contains docker-resin-supervisor-disk.bbappend
that can define the following variable(s):
LED_FILE_<yocto-machine-name>
: this variable should point to the Linux sysfs path of an unused LED if available for that particular board. This allows the unused LED to be flashed for quick visual device identification purposes. If no such unused LED exists, this variable shall not be used.
The directory structure then looks similar to this:
├── conf
│ ├── layer.conf
│ └── samples
│ ├── bblayers.conf.sample
│ └── local.conf.sample
├── recipes-bsp
│ └── bootfiles
├── recipes-containers
│ └── docker-disk
│ └── docker-resin-supervisor-disk.bbappend
├── recipes-core
│ ├── images
│ │ └── resin-image.bbappend
├── recipes-kernel
│ └── linux
│ ├── linux-<board-family>-<version>
│ │ └── <patch files>
│ ├── linux-<board-family>_%.bbappend
│ └── linux-<board>_<version>.bbappend
└── recipes-support
└── resin-init
├── files
│ └── resin-init-board
└── resin-init-board.bbappend
See the meta-balena Readme on how to build the new resinOS image after setting up the new board package as defined above.
For specific examples on how board support is provided for existing devices, see the repositories below.
- Beaglebone: balena-beaglebone
- Raspberry Pi: balena-raspberrypi
- Freescale/NXP: balena-fsl-arm
- ODROID: balena-odroid
- Parallella: balena-parallella
- Technologic Systems: balena-ts
- Toradex: balena-toradex
- VIA: balena-via-arm
- Zynq: balena-zc702
- Samsung Artik: balena-artik
The versions before v2.0-beta.3 didn't support kernel sources that were not git repositories. Starting with this version aufs patches will get applied on kernel recipes which use tar achives for example as well. For the older version this is considered a limitation.