Friday, June 13, 2014

Here be Dragons! How to cross compile a linux kernel for the RPi

Introduction

It goes without saying that if you aren't a serious geek and you have stumbled upon this blog by mistake then I would leave now. This is about as hard core techie as I get these days.
During my recent spell of relaxing in the Alps and watching the world go by I played with docker on my Raspberry Pi (RPi) since those helpful Resin guys had done all the heavy lifting for me. Great, but the linux distribution they had used was Arch linux which just felt too alien to me since the default Raspbian distribution is based on Debian Wheezy. Wouldn't it be great I thought to install docker on the Raspbian distribution? It can't can't be hard can it since those Resin guys have already done it. Hmmmm!
Anyway, this blog isn't going to explain how to get docker running on Raspbian. I will save that story for another day. This post is about how to cross compile the linux kernel for RPi, so let's get started. Why cross compilation? You can compile and build the linux kernel on the RPi directly. This was my first approach, but it takes a very very long time. The second time I did this I got bored and decided to learn how to cross compile and it was so much faster.
In order to work out how to do this I read some useful blogs, which I will reference at the end.

Prerequisites

I assume you have decent development environment machine such as a Macbook. I used my top-spec mini Air for the job, but I'm sure a Windows machine would do it equally well. The key tool to have as a starting point is vagrant and I used an unbuntu base image for this. I won't explain Vagrant and assume you know how to use this tool.
Vagrant and a fast broadband connection are all you need.
If you want to actually deploy your built kernel to your RPi I would take a copy of it's kernel configuration and scp it to the vagrant directory on your host box first. You can get the configuration on the RPi via the command:
zcat /proc/config.gz > .config

A Step by Step Guide

1. First install all the tools required

sudo apt-get install libncurses5-dev gcc make git bc
sudo apt-get install libc6:i386 libgcc1:i386 gcc-4.6-base:i386 libstdc++5:i386 libstdc++6:i386 lib32z1 lib32ncurses5 lib32bz2-1.0 
The 2nd command insures that you have the 32 bit include files required for the RPi as this is a 32 bit processor.

2. Install the Raspbian Tool Chain for Cross Compiling

sudo su
cd /opt
git clone git://github.com/raspberrypi/tools.git

export CCPREFIX=/opt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-

3. Download the Linux Kernel for the RPi

cd /opt
mkdir raspberrypi
cd raspberrypi
git clone git://github.com/raspberrypi/linux.git
export KERNEL_SRC=/opt/raspberrypi/linux
For this blog I am assuming you will build the most recent kernel.

4. Configure the Kernel

I prefer to ensure I am starting from a clean state first.
ARCH=arm CROSS_COMPILE=${CCPREFIX} make mrproper
Then copy the existing RPI configuration to act as a starting point
cp /vagrant/.config .
ARCH=arm CROSS_COMPILE=${CCPREFIX} make menuconfig
Unless you are feeling brave or need to change the configuration of the kernel you are building, as you would to build docker, then just save the configuration and exit this GUI.

4. Build the Kernel

Since even on a modern machine this will take a while (about 30 minutes on my machine) you might want to use a script and nohup this, but the raw command is:
ARCH=arm CROSS_COMPILE=${CCPREFIX} make &
Assuming all went well you will have a new linux kernel built and now need to make the kernel modules for it.
ARCH=arm CROSS_COMPILE=${CCPREFIX} make modules_install
Now you should have a new linux kernel here:
/opt/raspberrypi/linux/arch/arm/boot/Image
The modules will have been built here: /lib/modules, e.g. at the time I wrote this blog the kernel was at version 3.12.18+
/lib/modules/3.12.18+
Now there is a tool to run to prepare the kernel for the RPi
cd /opt/tools/mkimage
python ./imagetool-uncompressed.py /opt/raspberrypi/linux/arch/arm/boot/Image
Note: This isn't required for the raspberry Pi 2. For that just copy the zImage kernel to image7.img in /boot 
The compressed image will be in your current directory called kernel.img.
You will need to copy this across to /boot directory on the RPi

5. Install The New Kernel on the RPI

IMPORTANT DISCLAIMER: If you follow these instruction it is possible that your RPi may not boot and you will need to enter emergency recovery procedures. You have been warned and I won't be help accountable or responsible.
First backup your old kernel then copy over the kernel modules and new kernel to the new RPI and reboot.
cp /boot/kernel.img /boot/kernel-old.img

cp kernel.img /boot/

- need to install the kernel modules directory built to the RPi in the /lib/modules directory too. I assume you know how to do this using tar & scp.

reboot
That is it!
Hopefully, you will be running ok on a new kernel and uname -a will show that you are running on the correct kernel version

References

1. Ken Cochrane - Getting docker up on a RaspberryPi
2. RPi Kernel Configuration

1 comment:

  1. - need to install the kernel modules directory built to the RPi in the /lib/modules directory too. I assume you know how to do this using tar & scp.

    Let's assume someone does not know how to do this. Can you elaborate?

    ReplyDelete