The reason I had to do this was because I needed video4linux to get a webcam working for a forcoming series of posts connecting a telescope to the pi. Although the connection to the telescope wasn’t a problem, the customized webcam I have needed it.
Here I compile the kernel on a more powerful linux box to save time then transfer the kernel over to the PI.
Also this article is mainly my personal notes on compiling a new kernel rather than a tutorial on how to do it. Writing it here makes sense to keep things together & maybe it’s useful for anyone else.
These instructions are based on the RPI Kernel Compilation available at elinux.org.
Terminology
Here were going to cross compile the kernel on one machine for installation on another. Cross compiling is when we compile on a machine of a different architecture to the target machine.
- tabitha – Intel based linux box which will be performing the compilation
- lindesfarne – Raspberry PI which is obviously running on the arm architecture
You’ll also notice that when copying files between the two I’m simply using the cp command. This is because I have setup an NFS share between the two. You’ll need to read the previous article on setting up NFS on how this is setup.
Install the cross compiler
You need the gcc cross compiler for arm, make, git and ncurses:
peter@tabitha:~$ sudo apt-get install gcc-arm-linux-gnueabi make git-core ncurses-dev
Get the sources
Here we’ll download the sources for the kernel & whilst were at it the latest firmware:
First create a directory to install everything, for example:
peter@tabitha:~$ mkdir raspberrypi
Now I used:
peter@tabitha:~$ mkdir -p /srv/public/kernel
as I needed a public location to copy everything to the PI. This is an NFS share which is why I wrote the previous article on setting up NFS.
Next to get the sources. These are fairly large so it will take a while:
peter@tabitha:~$ cd /srv/public/kernel peter@tabitha:/srv/public/kernel$ git clone https://github.com/raspberrypi/firmware peter@tabitha:/srv/public/kernel $ git clone https://github.com/raspberrypi/linux.git peter@tabitha:/srv/public/kernel $ cd linux
Configure the kernel
Here I copied the config from the running kernel on a pi as a baseline:
pi@lindesfarne:~$ sudo zcat /proc/config.gz > .config pi@lindesfarne:~$ cp .config /srv/public/kernel/linux
Next configure the new kernel with the old config:
peter@tabitha:/srv/public/kernel/linux$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- oldconfig
Now the optional bit, run menuconfig to edit the new configuration. I needed to do this to add v4l:
peter@tabitha:/srv/public/kernel/linux$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig
Build the kernel
peter@tabitha:/srv/public/kernel/linux$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- -k
Now go to the pub. Seriously, depending on how powerful your machine is this can take quite some time. If you were building this natively on a pi then it could take all night, on other machines a lot less but it’s still long enough to have a pint!
Update the firmware
You may or may not need to do this but I did on the first time as the firmware has been updated since the original Debian image was created:
First I backed up the existing firmware incase I needed to restore to it:
pi@lindesfarne:~$ mkdir -p /srv/public/raspberry/orig-firmware/ pi@lindesfarne:~$ sudo su - root@lindesfarne:~# cp arm128_start.elf arm192_start.elf arm224_start.elf bootcode.bin loader.bin start.elf /srv/public/raspberry/orig-firmware/
Now copy the new firmware onto the pi:
pi@lindesfarne:~$ sudo su - root@lindesfarne:~# cd /srv/public/kernel/firmware/boot root@lindesfarne:~# cp arm128_start.elf arm192_start.elf arm224_start.elf bootcode.bin loader.bin start.elf /boot
Install the new kernel
pi@lindesfarne:~$ sudo cp /srv/public/kernel/linux/arch/arm/boot/Image /boot/kernel.img
Install the new kernel modules
Now here’s why I used nfs, on the pi we need to run make to install our new modules.
pi@lindesfarne:~$ cd /srv/public/kernel/linux pi@lindesfarne:/srv/public/kernel/linux$ sudo make modules_install
Thats it. Reboot and you should have your new kernel.
Notes
I get a black screen when I reboot
If you get just a black screen and only the red power led lighting up then you probably missed out the step updating the firmware. The older firmware required a special kernel image whilst the newer one only needed the image as built by the build.
If you get this you’ll need to mount the SD card directly to your linux box and install the firmware directly to the boot partition on the card.
How to see what kernel is running
The easiest way is with uname. Here’s the output on a PI with the original Debian image installed:
pi@kell:~$ uname -a Linux kell 3.1.9+ #90 Wed Apr 18 18:23:05 BST 2012 armv6l GNU/Linux
Here’s the output with the new kernel:
pi@lindesfarne:~$ uname -a Linux lindesfarne 3.1.9+ #1 Sat Jul 7 21:18:19 BST 2012 armv6l GNU/Linux
You’ll notice the kernel versions are the same (3.1.9) but the build time is different.
“Now the optional bit, run menuconfig to edit the new configuration. I needed to do this to add v4l:”
What did you modify in there to enable v4l ?
It’s been a while so I can’t remember where the setting was exactly but I do remember going through all the modules & when I found the v4l section I just enabled all of them (as modules).
Doing that ensured they were build so when the time came to test I could just run mod probe to load it.
Hi petermount,
Thanks for your great post. I have few questions
1) You are not using the hf version of compiler (arm-bcm2708hardfp-linux-gnueabi, gcc-linaro-arm-linux-gnueabihf-raspbian) from raspberrypi/tools. Any reasons and is the process similar ?
sudo apt-get install gcc-arm-linux-gnueabi make git-core ncurses-dev
2) Also if we use gcc-arm-linux-gnueabi it does not use hard float ?
2) Also what is the reason for
peter@tabitha:/srv/public/kernel/linux$ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- oldconfig
Is the oldconfig the original config from raspberry pi just renamed to oldconfig ?
Thanks,
Mohsin
Sorry for the late reply.
1: I used the standard compiler rather than the hf one simply because at the time I didn’t know the other existed – I only had the standard examples on cross compiling to go by.
I don’t see any reason for the process to be different other than pointing it to the hf compiler.
2: I don’t know if gcc-arm-linux-gnueabi uses hf or not – see below.
3: oldconfig is the config from the pi. I did that as I wanted the exact same config.
Now at the time I wrote this article I was using the original distribution rather than raspian and that distro didn’t have certain modules, specifically the v4l ones needed to handle a webcam. So I took the exact config from the pi, then added the additional modules I wanted adding to that file. This then meant that when the kernel sources were updated the builds got the required modules rather than the ones defined by the sources.
Now some updates:
Since I wrote this article:
You might also want to take a look at RPi_Kernel_Compilation over on elinux.org as it has a section on cross compiling from Linux & OSX. There they talk about using gnueabi but also using the pre-built bmc2708 compiler from the RPI tools section on GitHub. That one looks like it uses Hard Float.
I hope that helps