Step08 – Linux Kernel Development

It may seem like a bit of a leap from the other articles, but kernel development is part and parcel of embedded linux deployment and development. We’re interested in getting a working system, and sometimes the kernel needs to be tweaked in order to work in a particular fashion on our hardware.

Normally the Linux device drivers do a satisfactory job, but sometimes (especially with legacy hardware or protocols) we’re stuck without a function in the low level driver that we need for our system to function properly.

Generate a standard system

The first thing we must do in order to develop the kernel is to build a system in the standard way, described by the Angstrom site:

So let’s do that first:

I suggest doing this on Ubuntu, and as we’re cross-compiling, don’t bother trying to do it on a system you have already, just start from a fresh Ubuntu 12.10 install in a VM. That’s what I’m doing here.

From a virgin Ubuntu install, get it up-to-date first:

sudo apt-get update
sudo apt-get upgrade

From a fresh Ubuntu install, get the required packages:

sudo apt-get install git gawk u-boot-tools lzop gcc-arm-linux-gnueabihf quilt build-essential texinfo chrpath

Now we can get on with building Angstrom. It’s as simple as following the instructions from the Angstrom site, but a simple script is worth doing. I generally run this script on a new install:


export MACHINE=beaglebone

rm -rf ./ang-dev
mkdir ./ang-dev
cd ./ang-dev

git clone git://

cd ./setup-scripts

./ config beaglebone
./ update
#./ bitbake virtual/kernel
./ bitbake systemd-image

You can download the script above here. Saves some typing and mis-spelling!

Be prepared, it takes a while for the above to complete. Once it does though, you’ll find a complete Angstro, system build and ready to deploy in:


Next, we need to get the system onto an SD card so that we can boot into it:

Understanding the boot process

(1) There are several stages to booting a OMAP SoC like the BeagleBone. First, on the boot partition x-loader ( ) is loaded, this file is simply a file called MLO. It performs the external DRAM configuration. No need to edit or change this!

(2) x-loader loads u-boot ( ). The default filename for u-boot is u-boot.img

(3) u-boot is resposible for executing the default environment commands. The default filename for the commands is uEnv.txt on the boot partition

(4) Commands from u-boot load the kernel. The default filename for the kernel is uImage.

(5) Finally the kernel ( uImage ) reads the root filesystem.

x-loaderer and u-boot are pre-built. We have no reason to modify them. The kernel we’re interested in developing, and so we will be using the one we’ve just compiled, or in future the one that we modify and rebuild. The root filesystem that we’ve already built will do us for now. If we get the need to deploy a different root filesystem we’ll have to make a new bitbake target in the future. For now we’re on kernel development…

Creating the card

You can follow the Working with SD cards page if you’re looking to start from a fresh card. It’s easier to start with a card that’s already been paritioned though, so I suggest for this step we start with a standard Angstrom distribution card.

Insert the SD card into a card reader. Make sure you know what the card is known as (Run dmesg if you need to in order to ensure you’re about to modify the right card!). If I run dmesg after putting a card in, I get the following output:

[code][ 1281.285129] sd 3:0:0:0: >[sdb] 7626752 512-byte logical blocks: (3.90 GB/3.63 GiB)
[ 1281.313540] sd 3:0:0:0: >[sdb] No Caching mode page present
[ 1281.313547] sd 3:0:0:0: >[sdb] Assuming drive cache: write through
[ 1281.371589] sd 3:0:0:0: >[sdb] No Caching mode page present
[ 1281.371595] sd 3:0:0:0: >[sdb] Assuming drive cache: write through
[ 1281.380757] sdb: sdb1 sdb2
[ 1284.951631] EXT4-fs (sdb2): mounted filesystem with ordered data mode. Opts: (null)

So sdb is the card I want to modify.

Now we need to mount the file systems onto our box so that we can write to them. Make sure there are directories in your mount root directory to mount eh partitions onto.

sudo mkdir /mnt/sd-boot
sudo mkdir /mnt/sd-fs
sudo mount -t vfat /dev/sdb1 /mnt/sd-boot
sudo mount /dev/sdb2 /mnt/sd-fs[/code]

Remove the previous boot files from the standard distribution, and remove the standard file system:

cd /mnt/sd-boot
sudo rm ./uImage
sudo rm ./u-boot.img
sudo rm ./MLO
sudo rm ./uEnv.txt
cd /mnt/sd-fs
sudo rm -rf *

Now, back to the build. It’s fairly easy to find, this is where the built image is on my system: brian@brian-VirtualBox:~/ang-dev/setup-scripts/build/tmp-angstrom_v2012_05-eglibc/deploy/images/beaglebone/

Copy the boot files from here to the boot partition. As we outlined above, we need MLO (x-loader), u-boot and uImage. uImage will have a crazy name, so upon copying it we simply rename it to simply uImage. It’s also possible to keep the name and use a symbolic link for uImage.

cd ~/ang-dev/setup-scripts/build/tmp-angstrom_v2012_05-eglibc/deploy/images/beaglebone/
sudo cp MLO /mnt/sd-boot
sudo cp u-boot.img /mnt/sd-boot
sudo cp ./uImage /mnt/sd-boot

Cool, now time to copy the root filesystem over. Remember again, you’ll need to know what your root filesystem’s filename is! You’ll have to copy the kernel modules across too.

cd /mnt/sd-fs
sudo tar -xjf /home/brian/ang-dev/setup-scripts/build/tmp-angstrom_v2012_05-eglibc/deploy/images/beaglebone/Angstrom-systemd-image-eglibc-ipk-v2012.05-beaglebone.rootfs.tar.bz2
sudo tar -xzf /home/brian/ang-dev/setup-scripts/build/tmp-angstrom_v2012_05-eglibc/deploy/images/beaglebone/Angstrom-systemd-image-eglibc-ipk-v2012.05-beaglebone.rootfs.tar.bz2

Unmount the SD card mount points and you can remove the SD card and insert it into the BeagleBone and start it up

[code]cd ~
sudo umount /mnt/sd-boot
sudo umount /mnt/sd-fs[/code]

Now having plugged the BeagleBone, following Step01 Getting Started and get an SSH connection to the BeagleBone in order to log into your new system and check the kernel version:

[code]uname -a[/code]

On the old system I was running I was running:

[code]root@beaglebone:~# uname -a
Linux beaglebone 3.2.18 #1 Thu Jun 14 23:26:20 CEST 2012 armv7l GNU/Linux

Now, booting with the new system I get:

[code]root@beaglebone:~# uname -a
Linux beaglebone 3.2.34 #1 Wed Feb 6 21:53:53 GMT 2013 armv7l GNU/Linux[/code]

Success. Although, we’ve not yet worked on the kernel yet! That’s what we’re onto next:

Now that we have the standard system booting, we can separate out the kernel source code from the OpenEmbedded environment to allow us to work on the linux kernel separately without the overhead/burden of OpenEmbedded (which has just done agood job in creating a system for us to be fair!)

Working on the Kernel

Look at the recipe for the Kernel
Change directory to the kernel recipe directory:

[code]cd setup-scripts/sources/meta-ti/recipes-kernel/linux[/code]

In this directory there are several recipes for building the linux kernel for our target platform. For the beaglebone we use the linux-ti33x-psp-3.2 version (as of writing this page anyway!). some grepping for beaglebone in the this directory will reveal the latest kernel available for your board.

So the recipe for building this kernel is It’s worth opening in a text editor (use nano) to see what the structure of this file is like – we need to extract some information from it anyway.

The first thing we need is the URI of the git repository for the vanilla kernel source before patching. This can be got from the file:

[code]SRC_URI += "git://;protocol=http;branch=${BRANCH}"[/code]

In this case a few lines above we can see that ${BRANCH} is v3.2-staging. So now we can clone the repository using exactly the same line:

[code]cd ~/ang-dev
mkdir kernel-dev && cd kernel-dev
git clone git://;protocol=http;branch=v3.2-staging[/code]

Now we must checkout the revision specific to the Angstrom build. This revision is the specific checkout from the repository that is used to apply the patches against. As there are around 800 patches, we need the exact revision.

Back to the Open Embedded recipes, we can find out the specific revision. It’s assigned to the variable SRCREV

In my we get:

brian@brian-VirtualBox:~/ang-dev/kernel-dev/co$ gedit ~/ang-dev/setup-scripts/sources/meta-ti/recipes-kernel/linux/

SRCREV = "720e07b4c1f687b61b147b31c698cb6816d72f01"

Check this revsion out of the git kernel clone:

cd ~/ang-dev/kernel-dev/linux-am33x
git checkout 720e07b4c1f687b61b147b31c698cb6816d72f01

Now we take some steps from the BeagleBoneLinuxKernel page to create a set of patches for quilt to run on the kernel to patch it to the Angstrom OMAP distribution source:

cd ~/ang-dev/kernel-dev/linux-am33x
mkdir patches
cp -r ~/ang-dev/setup-scripts/sources/meta-ti/recipes-kernel/linux/linux-ti33x-psp-3.2/* ~/ang-dev/kernel-dev/linux-am33x/patches/
cd patches
grep "^.*file:\/\/" < ~/ang-dev/setup-scripts/sources/meta-ti/recipes-kernel/linux/ |sed "s/^.*file:\/\///" | sed "s/ [\\]//" > ~/ang-dev/kernel-dev/linux-am33x/patches/series

Now, we need to have a look at the series file. It’s not quite right. Let’s have a look at what we need to fix:



The firmware file clearly isn’t a patch, so can’t be run by quilt. Nor can defconfig, or logo_linux… so remove those lines from the series file.

Now we can get quilt to run the patches on the source:

cd ~/ang-dev/kernel-dev/linux-am33x
quilt push -a[/code]

After a while of churning, quilt fails for me with:

Applying patch beaglebone/0095-beaglebone-convert-LCD4-to-16-bit-add-button-support.patch
patching file ‘\’
Hunk #1 FAILED at 188.
Hunk #2 FAILED at 213.
Hunk #3 FAILED at 688.
Hunk #4 FAILED at 1475.
Hunk #5 FAILED at 3249.
5 out of 5 hunks FAILED — rejects in file ‘\’

But the patches that follow this are menial and not really anything I care about, so I carry on regardless rather than trying to hand apply patches!

We need to copy the firmware binary file across (which is hinted at from the lines we removed from the series file:

cd ~/ang-dev/kernel-dev/linux-am33x
cp ./patches/am335x-pm-firmware.bin ./firmware/

Copy the default kernel config across, and compile the kernel:

cp ./patches/beaglebone/defconfig ./.config
ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make -j4 uImage

At the end of compilation of the new kernel, you should end up with something like this being shown:

Image Name: Linux-3.2.34+
Created: Sun Feb 10 16:12:21 2013
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3455944 Bytes = 3374.95 kB = 3.30 MB
Load Address: 80008000
Entry Point: 80008000
Image arch/arm/boot/uImage is ready

If you don’t get the final line, then something went wrong during the build. Sometimes you have to immediately re-run the same build command to get the error message from the kernel build. It sometimes silently stops building. The re-run should show you the error, for example, if you’ve not copied the firmware file across.

Now you can go through the procedure outlined above with the Open Embedded build to place the new kernel (uImage) onto the boot partition (Don’t forget to mount the card first!):

cd /mnt/sd-boot/
rm uImage
cp ~/ang-dev/kernel-dev/linux-am33x/arch/arm/boot/uImage ./

Now you can boot into the kernel again to make sure everything is still working…


Making some changes

Well, now that I’ll leave to you! The first thing most people are going to change when rolling their own distribution/system is to edit /etc/issue!

Good luck!

Leave a Reply