Thursday, November 28, 2013

Cross-compiling Linux Kernel for Raspberry Pi on Ubuntu 12.04


Why recompile the kernel?
Because few drivers might be missing. In my case, the eGalax USB touchscreen driver had to be enabled.

What is this cross compilation thing?
It simply means compiling on a different architecture (eg, Intel processor). You want this as your laptop is most probably 5-10x faster than the Raspberry.

What is your setup?
In this tutorial I assume a separately running Raspberry Pi connected to the network, with the hostname raspberrypi.


Install the compiler (for arm) and the tools necessary:

ubuntu$ sudo apt-get install git-core gcc-arm-linux-gnueabi make ncurses-dev

I also created a symlink for the cross-compiler. This is needed as the CROSS_COMPILE kernel flag takes the prefix "arm-linux-gnueabi-", and appends "gcc" to it, without the version number.

ubuntu$ sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-4.6 /usr/bin/arm-linux-gnueabi-gcc

Obtain and uncompress the kernel source:

ubuntu$ wget --no-check-certificate
ubuntu$ tar xvfz rpi-3.10.y.tar.gz
ubuntu$ cd linux-rpi-3.10.y

Note: 3.10.y is the current stable branch at the time of the writing (November 2013), you might want to change this.


Copy and uncompress the current Raspberry kernel configuration (your scp usage might vary, I assume default hostname and username):

ubuntu$ scp pi@raspberrypi:/proc/config.gz .
ubuntu$ gunzip config
ubuntu$ mv config .config

Now comes the tricky part. Since the kernel we are compiling is (probably) more recent than the one we have on the Raspberry, more configuration choices have been added. The make the kernel ask for the new config options only, issue:

ubuntu$ make oldconfig

Follow the instructions, you should be safe to accept the default answers offered. When done, you can optionally run the shiny menu-based configuration to change your needs -- eg, to enable the touchscreen driver:

ubuntu$ make menuconfig


This can take several hours. If you have multiple CPU cores, to use all of them, make sure to specify -jN, where N is number of cores + 1. Eg, a dual-core machine should use -j3.

ubuntu$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- -j3

When done, we should have the kernel and all the modules built. The module binaries must be installed to separate them from the source files:

ubuntu$ mkdir ../modules
ubuntu$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- INSTALL_MOD_PATH=../modules modules_install

Upgrade the Raspberry Pi Binary Firmware

On the Raspberry Pi, back up the /boot directory containing the boot loader and the current kernel abd the /opt directory containing the VideoCore firmware:

raspberrypi$ sudo cp -R /boot /boot.bak
raspberrypi$ sudo mv /opt /opt.bak

Warning: without these files your Raspberry will not be bootable.

Obtain the most recent Raspberry Pi firmware (takes long, huge repository -- you might choose to clone this to Ubuntu and scp over the required files only):

raspberrypi$ git clone git://

...then copy over the most recent boot loader files:

raspberrypi$ cp firmware/boot/bootcode.bin /boot
raspberrypi$ cp firmware/boot/fixup.dat /boot
raspberrypi$ cp firmware/boot/start.elf /boot

...and the VideoCore firmware (assuming you are using hard float; use command  gcc -v 2>&1 |grep with-float=hard to find out; if it prints a line, you have hard-float configured):

raspberrypi$ cp -R firmware/hardfp/opt /

Note: this "firmware" is different to the module-loaded firmware that is included in the Linux kernel.

Upload the Kernel to the Raspberry

First, let's transfer the necessary files:

ubuntu$ scp arch/arm/boot/zImage raspberrypi:kernel.img
ubuntu$ scp -r ../modules/lib/modules raspberrypi:
ubuntu$ scp -r ../modules/lib/firmware raspberrypi:

Then let's move them to their place:

raspberrypi$ sudo cp kernel.img /boot
raspberrypi$ sudo cp -R modules /lib
raspberrypi$ sudo cp -R firmware /lib

You should be able to reboot now.

Alternative Choices

Kernel source can be obtained through git as well; this takes much longer though:

mkdir linux-rpi-3.10.y
cd linux-rpi-3.10.y
git init
git fetch git:// rpi-3.6.y:refs/remotes/origin/rpi-3.10.y
git checkout rpi-3.10.y

Also, instead of scp'ing to a running Raspberry, you might want to insert the SD card into your Ubuntu machine and copy the files over. (You must obviously do so if the Raspberry does not boot.)


No comments:

Post a Comment