Build a Linux Real-Time kernel using docker

Introduction

Ubuntu 20.04 x86_64 docker container is used to cross-compile a new kernel. There is a Dockerfile which can be used for that purpose. If you want to build it using gitpod you need to run https://gitpod.io/#https://github.com/ros-realtime/rt-kernel-docker-builder. It will spawn a docker container automatically for you.

Build and run docker container

For the local build:

$ git clone https://github.com/ros-realtime/rt-kernel-docker-builder
$ cd rt-kernel-docker-builder
$ docker build -t rtwg-image .
$ docker run -t -i rtwg-image bash

Setup a build environment

Container comes with cross-compilation tools installed, and a ready-to-build RT kernel:

  • ARMv8 cross-compilation tools

  • Linux source build dependencies

  • Linux source buildinfo, i.e. from where config is copied

  • Ubuntu RPI4 linux source installed under ~/linux_build

  • RT kernel patch downloaded and applied - the nearest to the recent RPI4 Ubuntu kernel

Kernel configuration

Additionally RT kernel configured as

$ ./scripts/config -d CONFIG_PREEMPT \
$ ./scripts/config -e CONFIG_PREEMPT_RT \
$ ./scripts/config -d CONFIG_NO_HZ_IDLE \
$ ./scripts/config -e CONFIG_NO_HZ_FULL \
$ ./scripts/config -d CONFIG_HZ_250 \
$ ./scripts/config -e CONFIG_HZ_1000 \
$ ./scripts/config -d CONFIG_AUFS_FS \

which corresponds to the following

# Enable CONFIG_PREEMPT_RT
 -> General Setup
  -> Preemption Model (Fully Preemptible Kernel (Real-Time))
   (X) Fully Preemptible Kernel (Real-Time)

# Enable CONFIG_HIGH_RES_TIMERS
 -> General setup
  -> Timers subsystem
   [*] High Resolution Timer Support

# Enable CONFIG_NO_HZ_FULL
 -> General setup
  -> Timers subsystem
   -> Timer tick handling (Full dynticks system (tickless))
    (X) Full dynticks system (tickless)

# Set CONFIG_HZ_1000
 -> Kernel Features
  -> Timer frequency (1000 HZ)
   (X) 1000 HZ

# Set CPU_FREQ_DEFAULT_GOV_PERFORMANCE [=y]
 -> CPU Power Management
  -> CPU Frequency scaling
   -> CPU Frequency scaling (CPU_FREQ [=y])
    -> Default CPUFreq governor (<choice> [=y])
     (X) performance

# Disable CONFIG_AUFS_FS, otherwise RT kernel build breaks
 x     -> File systems                                                                                                                          x
  x (1)   -> Miscellaneous filesystems (MISC_FILESYSTEMS [=y])

If you need to reconfigure it, run

$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

Kernel build

$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j `nproc` deb-pkg

You need 32GB free disk space to build it, it takes a while, and the results are located:

gitpod ~/linux_build/linux-raspi-5.4.0 $ ls -la ../*.deb
-rw-r--r-- 1 gitpod gitpod  11278252 Nov 29 14:01 ../linux-headers-5.4.86-rt48_5.4.86-rt48-1_arm64.deb
-rw-r--r-- 1 gitpod gitpod 486149956 Nov 29 14:04 ../linux-image-5.4.86-rt48-dbg_5.4.86-rt48-1_arm64.deb
-rw-r--r-- 1 gitpod gitpod  38504756 Nov 29 14:01 ../linux-image-5.4.86-rt48_5.4.86-rt48-1_arm64.deb
-rw-r--r-- 1 gitpod gitpod   1054624 Nov 29 14:01 ../linux-libc-dev_5.4.86-rt48-1_arm64.deb

Deploy

Download and install Ubuntu 20.04 image

Follow these links to download and install Ubuntu 20.04. In the case of the Raspberry PI:

  • https://ubuntu.com/download/raspberry-pi

  • https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04&architecture=arm64+raspi

  • https://ubuntu.com/tutorials/create-an-ubuntu-image-for-a-raspberry-pi-on-ubuntu#2-on-your-ubuntu-machine

# initial username and password
ubuntu/ubuntu

Update your system

After that you need to connect to the Internet and update your system

$ sudo apt-get update && apt-get upgrade

Copy a new kernel to your system and install it

Assumed you have already copied all *.deb packages to your $HOME/ubuntu directory

$ cd $HOME/ubuntu
$ sudo dpkg -i *.deb

Now it is necessary to adjust vmlinuz and initrd.img links. There is an extra step in compare to the x86_64 install (why is that?)

$ cd /boot
$ sudo ln -s -f vmlinuz-5.4.86-rt48 vmlinuz
$ sudo ln -s -f vmlinuz-5.4.0-1029-raspi vmlinuz.old
$ sudo ln -s -f initrd.img-5.4.86-rt48 initrd.img
$ sudo ln -s -f initrd.img-5.4.0-1029-raspi initrd.img.old
$ sudo cp vmlinuz firmware/vmlinuz
$ sudo cp vmlinuz firmware/vmlinuz.bak
$ sudo cp initrd.img firmware/initrd.img
$ sudo cp initrd.img firmware/initrd.img.bak

$ sudo reboot

Verify kernel version

After reboot you should see a new RT kernel installed

ubuntu@ubuntu:~$ uname -a
Linux ubuntu 5.4.86-rt48 #1 SMP PREEMPT_RT Sun Nov 15 22:44:33 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux