Raspberry Pi: Script to (Cross) Compile a new Kernel

Hi,

a my Project Owncloud on a Raspberry Pi I want to use AppArmor to protect the lighttpd webserver. Unfortunately the default kernel is complied without apparmor support.

So I decided to build my own kernel:-)

Here are the steps to (cross) compile the new kernel on a x64 Intel based computer.

First of all update the Rasperries Firmware and therefore the kernel to the latest revision.

1
2
pi@raspi ~$ sudo rpi-update
pi@raspi ~$ sudo reboot

Check Version

1
2
pi@raspi ~$ uname -a
Linux raspi.yourdomain 4.1.13+ #1 PREEMPT Tue Oct 24 13:10:50 CET 2015 armv6l GNU/Linux

Get the kernel config file (.config). The kernel provides this in /proc/config.gz. The raspbian kernel does provide it by default. You must load the configs.ko kernel module

1
2
pi@raspi ~$ sudo modprobe configs
pi@raspi ~$ zcat /proc/config.gz > ~/.config

Or after installing kernel sources you can also use the script “extract-ikconfig” in the scripts folder to extract the config from the kernel image file.

Go to the x86 PC. Make sure you have free at least 5GB of disk space. Define the build directory

1
2
michael@devdeb ~ $ mkdir $HOME/raspbian-kernel
michael@devdeb ~ $ cd $HOME/raspbian-kernel

Get the kernel config file from Raspberry to your home

1
michael@devdeb ~ $ scp pi@IPAddressRaspPI:/home/pi/.config ~/.config.raspberry

Get ARM Compiler

1
michael@devdeb:/home/michael/raspbian-kernel $ git clone https://github.com/raspberrypi/tools

The next step is to determine the git path of the current kernel. These steps are not necessary if you want to compile a version 4.1.x

1
2
3
4
5
6
7
# Determine git pathof current Kernel. Not necessary if you know it, in this example 4.1.x
# cd linux
# git show-ref
#   06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/heads/rpi-4.1.y
#   06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/remotes/origin/HEAD
#   06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/remotes/origin/rpi-4.1.y

Some Environmentvariables with a decision first for which Raspberry you want to compile the kernel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# New Kernelfilename
export KERNEL=kernel-custom
# Kernel sources directory
michael@devdeb ~ $ export KERNEL_SRC=$HOME/raspbian-kernel/rpi-4.1.y
# gcc Compiler Prefix
# michael@devdeb ~ $ export CCPREFIX=$HOME/raspbian-kernel/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
michael@devdeb ~ $ export CCPREFIX=$HOME/raspbian-kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-
# Root for tar Archive for the transfer to Pi
michael@devdeb ~ $ export RASP_FILE_ROOT=$HOME/raspbian-kernel/root
# Folder latest firmware
michael@devdeb ~ $ export FIRMWARE=$HOME/raspbian-kernel/firmware
# Target directory for the new kernel modules
michael@devdeb ~ $ export MODULES_TEMP=$HOME/raspbian-kernel/lib/modules
# Create folders
michael@devdeb ~ $ mkdir -p $KERNEL_SRC
michael@devdeb ~ $ mkdir -p $MODULES_TEMP
michael@devdeb ~ $ mkdir -p $RASP_FILE_ROOT

While it is important in which directory a command is executed and the command lines and prompt are partitialy rather long and therefore uses a lot of space. I insert before each command block a pwd to show the working directory and “hide” the prompt in front of the commands.

Get the latest sources

1
2
3
4
5
6
michael@devdeb ~ $ cd $KERNEL_SRC
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
git init
git fetch https://github.com/raspberrypi/linux.git rpi-4.1.y:refs/remotes/origin/rpi-4.1.y
git checkout refs/remotes/origin/rpi-4.1.y

Clean up

1
2
3
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
make mrproper

Copy the .config file to the kernel build folder

1
2
3
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
cp ~/.config.raspberry .config

It’s time to customize the kernel. I want to enable apparmor. CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 enables AppArmor by default.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
# CONFIG_AUDIT=y
sed -r 's/^((CONFIG\_AUDIT=.*$)|(^# CONFIG\_AUDIT\s.*$))/CONFIG\_AUDIT=y/m' .config -i
# CONFIG_CRYPTO_SHA1=y
sed -r 's/^((CONFIG\_CRYPTO\_SHA1=.*$)|(^# CONFIG\_CRYPTO\_SHA1\s.*$))/CONFIG\_CRYPTO\_SHA1=y/m'  .config -i
# CONFIG_SECURITY=y
sed -r 's/^((CONFIG\_SECURITY=.*$)|(^# CONFIG\_SECURITY\s.*$))/CONFIG\_SECURITY=y/m' .config -i
# CONFIG_SECURITYFS=Y
sed -r 's/^((CONFIG\_SECURITYFS=.*$)|(^# CONFIG\_SECURITYFS\s.*$))/CONFIG\_SECURITYFS=y/m' .config -i
# CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_PATH=y
# CONFIG_SECURITY_APPARMOR=y
# CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
# CONFIG_SECURITY_APPARMOR_HASH=y
# CONFIG_INTEGRITY=y
# CONFIG_INTEGRITY_AUDIT=y
sed '/CONFIG_SECURITYFS=y/a CONFIG_SECURITY_NETWORK=y\nCONFIG_SECURITY_PATH=y\nCONFIG_SECURITY_APPARMOR=y\nCONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1\nCONFIG_SECURITY_APPARMOR_HASH=y\nCONFIG_INTEGRITY=y\nCONFIG_INTEGRITY_AUDIT=y' .config -i
# Version -apparmor
sed -r 's/^CONFIG_LOCALVERSION=.*$/CONFIG_LOCALVERSION="-apparmor"/m' .config -i

You can make your own changes by opening the kernels config menu. Prior to this you have to install the ncurses-dev paket.

1
2
3
4
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
apt-get install libncurses5-dev
ARCH=arm CROSS_COMPILE=${CCPREFIX} make menuconfig

Start compiling and get a coup of coffee or two. This takes a while.

1
2
3
4
5
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
ARCH=arm CROSS_COMPILE=${CCPREFIX} make olddefconfig
ARCH=arm CROSS_COMPILE=${CCPREFIX} make zImage modules dtbs
ARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=${MODULES_TEMP} make modules_install

Move the lib folder which contains the new kernel modules to the root of the to created tar archive

1
2
3
4
cd ${MODULES_TEMP}
pwd
# /home/michael/raspbian-kernel/lib/modules
mv lib $RASP_FILE_ROOT

Copy the new kernel, the device tree binaries and the overlays to tar archive

1
2
3
4
5
6
7
pwd
# /home/michael/raspbian-kernel/rpi-4.1.y
mkdir -p $RASP_FILE_ROOT/boot/overlays
./scripts/mkknlimg ${KERNEL_SRC}/arch/arm/boot/zImage $RASP_FILE_ROOT/boot/${KERNEL}.img
cp ${KERNEL_SRC}/arch/arm/boot/dts/*.dtb $RASP_FILE_ROOT/boot/
cp ${KERNEL_SRC}/arch/arm/boot/dts/overlays/*.dtb* $RASP_FILE_ROOT/boot/overlays
cp ${KERNEL_SRC}/arch/arm/boot/dts/overlays/README $RASP_FILE_ROOT/boot/overlays

Get the latest firmware.Use showref to get the path for git checkout

1
2
3
4
5
6
7
cd $HOME/raspbian-kernel
pwd
# /home/michael/raspbian-kernel
git clone --depth=1 https://github.com/raspberrypi/firmware.git
cd firmware
# git show-ref
git checkout refs/remotes/origin/master

And also copy the firmware to the tar root

1
2
3
4
5
6
cp $HOME/raspbian-kernel/firmware/boot/bootcode.bin $RASP_FILE_ROOT/boot
cp $HOME/raspbian-kernel/firmware/boot/fixup*.dat $RASP_FILE_ROOT/boot
cp $HOME/raspbian-kernel/firmware/boot/start*.elf $RASP_FILE_ROOT/boot
mkdir -p $RASP_FILE_ROOT/opt
cd $HOME/raspbian-kernel/firmware/hardfp/opt
cp -r . $RASP_FILE_ROOT/opt

Create the tar archive to transfer the new kernel to the Raspberry

1
2
3
4
5
cd $RASP_FILE_ROOT
pwd
# /home/michael/raspbian-kernel/root
tar -cvf $HOME/raspbian-kernel/kernel.tar .
gzip $HOME/raspbian-kernel/kernel.tar

Copy the complete kernel archive to the Raspberry

1
scp /home/michael/raspbian-kernel/kernel.tar.gz pi@IPAddressRaspPI:/home/pi

And install the new kernel. Note: This overwrites the already installed kernel.img.

1
2
3
4
5
pi@raspi ~$ sudo su -
root@raspi:/home/pi # tar --no-same-owner -xvzf kernel.tar.gz -C /
# Edit config.txt
root@raspi:/home/pi # cp /boot/config.txt /boot/config.txt-`date +%Y%m%k-%I%M%S`
root@raspi:/home/pi # grep -q '^kernel=.*' /boot/config.txt && sed -i 's/^kernel=.*/kernel=kernel-custom.img/m' /boot/config.txt || echo 'kernel=kernel-custom.img' >> /boot/config.txt

Reboot the raspberry an check the new kernel version

1
2
pi@raspi ~$ uname -a
Linux raspi.yourdomain 4.1.13-apparmor+ #1 PREEMPT Tue Oct 25 23:10:50 CET 2015 armv6l GNU/Linux

The script (currently works only an Raspberry Models 1 and it requieres sshpass to run) attached does all things to create the tar archive at once, adjust the IP_RASPBERRY= with the IP Address of your Pi, the SSHPASS= variable with the password of user “pi”, you can also give the password as parameter to the script and then start the script with

1
2
apt-get install sshpass
bash BuildKernelRaspberryPi.sh PiPassword

and wait…… 🙂

Michael

References: eLinux.org
Raspberry.org

Script to (cross) compile the linux kernel for Raspberry Pi
Script to (cross) compile the linux kernel for Raspberry Pi
BuildKernelRaspberryPi.sh
Version: 1.1.1
6.8 KiB
1375 Downloads
Details...

2 thoughts on “Raspberry Pi: Script to (Cross) Compile a new Kernel”

Leave a Reply