Jump Start your BSP using DistroKit and PTXdist Layers

A BSP (Board Support Package) in Embedded Software is the layer of software that lets you run your application on a specific hardware. For Pengutronix a BSP usually contains a bootloader, Linux Kernel and a userspace. DistroKit is our Demo-BSP that supports a variety of common evaluation boards. DistroKit gives you a head start if you want to develop an application on top of such an evaluation board with most of the hard problems already solved.

Some years ago Robert wrote about how you can use DistroKit as an example of PTXdist and it's features. Generally his blog post is still valid – but I want to introduce a new way to use DistroKit.

Don't be shocked by all the code snippets in here: This blog post is written as a step-by-step walkthrough on how to create a DistroKit based layered BSP and how to migrate it to a new DistroKit revision.

Layers everywhere

In modern times things must have layers: Ogres, Onions, and also PTXdist.

In short: PTXdist layers give you the possibility to stack multiple PTXdist configurations on top of each other, each representing a diff to the previous one.

The classical way to use DistroKit was to take the upstream BSP and stack your changes on top of that in the same git. PTXdist keeps its configuration inside a Kconfig file. An update to a new DistroKit version now means to rebase your changes on top of the upstream, or merge the upstream. You easily end up with in a rebase hell or a merge hell. For an inexperienced user it is hard to make a reproducible merge.

My suggestion is to use DistroKit as a base layer for your own BSP. Using layers you gain more separation between DistroKit and your own changes, but you are still able to gain the comfort of a preconfigured BSP.

A working environment

Before we can go any deeper I assume that you have a working environment where you can compile a bare DistroKit.

Robert has done a good job describing the necessary steps in his blog post. The original PTXdist documentation provides some further reading on how to get a working environment.

Create a layer

For our new BSP let's start with an empty git:

chris@dauntless:~/Projekte$ mkdir my-fancy-layer-bsp
chris@dauntless:~/Projekte$ cd my-fancy-layer-bsp
chris@dauntless:~/Projekte/my-fancy-layer-bsp$ git init
Initialized empty Git repository in /home/chris/Projekte/my-fancy-layer-bsp/.git/

Let's now add DistroKit as the underlying layer. This layer is called base in PTXdist. base can be symlink to a DistroKit checkout. But in this case you would not be able to store the state of your underlying layer alongside with your BSP. Thus I suggest to add base as a git submodule:

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ git submodule init
chris@dauntless:~/Projekte/my-fancy-layer-bsp$ git submodule add https://git.pengutronix.de/git/DistroKit base
Cloning into '/home/chris/Projekte/my-fancy-layer-bsp/base'...
remote: Counting objects: 3163, done.
remote: Compressing objects: 100% (2209/2209), done.
remote: Total 3163 (delta 2203), reused 1268 (delta 814)
Receiving objects: 100% (3163/3163), 10.88 MiB | 5.35 MiB/s, done.
Resolving deltas: 100% (2203/2203), done.

Let's assume we want to build a BSP for the v7a platform. This means that we will end up with images for the BeagleBone, the Raspberry Pi 2 and the RIoTboard.

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ ptxdist-2019.06.0 platform base/configs/platform-v7a/platformconfig
info: selected platformconfig:
      'base/configs/platform-v7a/platformconfig'

found and using toolchain:
'/opt/OSELAS.Toolchain-2018.12.0/arm-v7a-linux-gnueabihf/gcc-8.2.1-glibc-2.28-binutils-2.31.1-kernel-4.19-sanitized/bin'

(Note: Due to a bug in the auto-version detection in PTXdist 2019.06.0, we have to call ptxdist-2019.06.0 explicitely here. In other versions, you can just use ptxdist instead as usual.)

After this step you can – in general – build your BSP. You would end up with an unaltered DistroKit.

Customising your layer

At this point you can use PTXdist to configure your BSP to your needs. One of the easiest steps is to set the name of your project. Run:

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ ptxdist menuconfig

This command opens the PTXdist menuconfig interface. Navigate to Project Name & Version and change the entries for Vendor Name and Project Name. Quit menuconfig saving your settings.

PTXdist will now write your new configuration into your layer. To store your configuration PTXdist will create a new folder config:

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ ptxdist menuconfig
#
# configuration written to .config
#
configuration written to .config

*** End of the configuration.
*** Execute 'ptxdist go' to build the project or try 'ptxdist help'.

Saving 'my-fancy-layer-bsp/configs/ptxconfig'.
Saving 'my-fancy-layer-bsp/configs/ptxconfig.diff'.

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ ls
base  configs  platform-v7a  selected_platformconfig  selected_toolchain

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ tree configs/
configs/
├── ptxconfig
├── ptxconfig.diff
├── ptxconfig.diff.old
└── ptxconfig.old

0 directories, 4 files

If you have look into the ptxconfig.diff, you will see that PTXdist uses this file to store the difference to the configuration of the base layer:

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ cat configs/ptxconfig.diff
a002d2d0d014be35adb806a041ab77a4
PTXCONF_PROJECT="Really Cool Project"
PTXCONF_PROJECT_VENDOR="My Fancy Company"

You also see the MD5 checksum at the beginning of the file, which pins down the state of the upstream configuration file, so PTXdist can detect when the config diff is out of date.

The ptxconfig file is still a full PTXdist configuration. But since we are using layers it also has all option of the lower layers enabled/disabled:

chris@dauntless:~/Projekte/my-fancy-layer-bsp$ cat configs/ptxconfig | head
#
# Automatically generated file; DO NOT EDIT.
# PTXdist 2019.06.0
#
PTXCONF_DATAPARTITION=y

#
# ------------------------------------
#

Update DistroKit

Let's assume we have started our BSP using an older version of DistroKit that was based on an older version of PTXdist. I will construct this case by checking out an older revision of DistroKit. In fact the version that I use will be the last commit that was based on ptxdist-2019.05.0:

chris@dauntless:~/Projekte$ mkdir my-fancy-legacy-layer-bsp
chris@dauntless:~/Projekte$ cd my-fancy-legacy-layer-bsp
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ git init
Initialized empty Git repository in /home/chris/Projekte/my-fancy-legacy-layer-bsp/.git/
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ git submodule init
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ git submodule add https://git.pengutronix.de/git/DistroKit base
Cloning into '/home/chris/Projekte/my-fancy-legacy-layer-bsp/base'...
remote: Counting objects: 3163, done.
remote: Compressing objects: 100% (2209/2209), done.
remote: Total 3163 (delta 2202), reused 1268 (delta 814)
Receiving objects: 100% (3163/3163), 10.88 MiB | 5.45 MiB/s, done.
Resolving deltas: 100% (2202/2202), done.
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ cd base/
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp/base$ git checkout b26440afd8a94982bde54a8e801577ff4a7c78e4
Note: checking out 'b26440afd8a94982bde54a8e801577ff4a7c78e4'.
HEAD is now at b26440a platform-v7a, platform-rpi: enable ARM unwinder
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp/base$ cd ..
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ ptxdist-2019.05.0 platform base/configs/platform-v7a/platformconfig
info: selected platformconfig:
      'base/configs/platform-v7a/platformconfig'

found and using toolchain:
'/opt/OSELAS.Toolchain-2018.12.0/arm-v7a-linux-gnueabihf/gcc-8.2.1-glibc-2.28-binutils-2.31.1-kernel-4.19-sanitized/bin'

In the next step we will do some modifications to our layer:

chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ ptxdist menuconfig

chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ grep "2019.05.0" configs/ptxconfig
# PTXdist 2019.05.0
PTXCONF_CONFIGFILE_VERSION="2019.05.0"

Note that PTXdist stores its version inside the config file.

In the next step we will update our base-layer to a newer version. At the time of writing master is based on ptxdist-2019.06.0:

chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ cd base/
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp/base$ git checkout master
Previous HEAD position was b26440a platform-v7a, platform-rpi: enable ARM unwinder
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp/base$ cd ..

Updating our layer to the new DistroKit (that is based on a new PTXdist release!) is now just a matter of calling the correct version of ptxdist migrate:

chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ ptxdist-2019.06.0 migrate
Updating 'my-fancy-legacy-layer-bsp/base/configs/ptxconfig'...
#
# configuration written to .config
#

Updating 'my-fancy-legacy-layer-bsp/configs/ptxconfig'...

Outdated diff, forcing config update...

#
# configuration written to .config
#
Saving 'my-fancy-legacy-layer-bsp/configs/ptxconfig'.
Saving 'my-fancy-legacy-layer-bsp/configs/ptxconfig.diff'.

Updating 'my-fancy-legacy-layer-bsp/base/configs/platform-v7a/platformconfig'...
#
# configuration written to .config
#

Updating 'my-fancy-legacy-layer-bsp/configs/platform-v7a/platformconfig'...
#
# configuration written to .config
#
Empty diff. Skipping 'my-fancy-legacy-layer-bsp/configs/platform-v7a/platformconfig'.

Et voilà, our layer has been automatically migrated to a new DistroKit version and a new PTXdist release:

chris@dauntless:~/Projekte/my-fancy-legacy-layer-bsp$ grep "2019.06.0" configs/ptxconfig
# PTXdist 2019.06.0
PTXCONF_CONFIGFILE_VERSION="2019.06.0"