Recently, I started to dig into the topic of Linux kernel, especially from the embedded point of view. I got a chance to explore the operating system, its configuration and build process at Nokia, where I currently work. I decided to shift this exploration to a different kind of hardware. Since I’ve got two Raspberry Pi at home, I decided to make a mini project, where I would prepare the operating system myself.

At first, I thought about using Yocto, but since I don’t need the out-of-the box package management provided by this build system, I ended up using Buildroot. What is more, it turned out that Buildroot prepares the image much faster than Yocto. The first one builds it in less than an hour, the second one uses more than 4 hours.

In the following sections, I will describe the steps needed to prepare a minimal image, which can be booted on the RPi. I will also show, how to access the freshly booted system without any network connection or external LCD.

I will not go into Buildroot details yet. The goal is to get the system up fast.

At the moment of writing this post, the latest stable buildroot version is 2016.02.

Getting buildroot

It’s easy as a pie:

$ wget https://buildroot.org/downloads/buildroot-2016.02.tar.bz2
$ tar xvjf buildroot-2016.02.tar.bz2
$ cd buildroot-2016.02
Building

Buildroot is now ready for initial configuration. There are few commands that can help:

$ make help
$ make list-defconfigs

The first one will show all of the make commands that are available. After executing the second one, two interesting configurations can be found:

raspberrypi2_defconfig - Build for raspberrypi2
raspberrypi_defconfig - Build for raspberrypi

Since I’m using Raspberry Pi B, the choice is obvious:

$ make raspberrypi_defconfig

Which does not last too long:

real	0m1.252s
user	0m0.868s
sys	0m0.124s

Now, with a little bit of patience:

$ make all

Which takes (on a i5-3320M):

real	42m22.210s
user	101m33.384s
sys	7m20.732s

NOTE!
The first time I ran make all, there was a problem with downloading the mpfr library. www.mpfr.org was unavailable, causing wget to hang and retry connection. The solution was to switch source address in package/mpfr/mpfr.mk

#MPFR_SITE = http://www.mpfr.org/mpfr-$(MPFR_VERSION)
MPFR_SITE = https://ftp.gnu.org/gnu/mpfr

Buildroot places the output files in:

output/images

And the most interesting at the moment is the sdcard.img

$ ls -al output/images/sdcard.img -h
-rw-r--r-- 1 tekieli tekieli 84M 04-03 18:11 output/images/sdcard.img

The default image is only 84 megabytes, which is much less than a Raspbian. The image can be copied straight to the SD Card:

$ dd if=sdcard.img of=/dev/mmcblk0
Booting up

Unfortunately, placing the SD card in the RPi is not enough. Since the default configuration does not set up any network, it is good to have some kind of control over the system. Serial console is the perfect answer.

Here is my setup:
Raspberry Pi - serial console connection

RPi Wire Serial adapter
GND BROWN GND
TX GREEN RX
RX YELLOW TX

To access serial connection:

$ minicom -b 115200 -D /dev/ttyUSB0

After connecting the serial adapter and powering up Pi, minicom shows:

"Uncompressing Linux... done, booting the kernel."

Great! Serial connections works, but nothing more, no logs, no login prompt. It turns out that the default arguments supplied to the kernel are:

root=/dev/mmcblk0p2 rootwait

Serial output needs to be enabled. To do this, cmdline.txt file needs to be modified. It is located on the first partition of the SD card.

console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootwait

This will enable the log output during kernel startup. To enable the login prompt, so that we are able access the newly built system, a minor change needs to be done in the Buildroot configuration. To access the configuration, in the Buildroot top directory run:

$ make nconfig

Go to “System configuration” -> “Run a getty after boot” and set the “TTY port” to ttyAMA0 , “Baudrate” to 115200 and “TERM environment variable” to vt100.

After exiting, run make all to rebuild the change. This time the build execution should take seconds, as all of the results of previous run are reused.

The change can be checked in:

$ cat output/target/etc/inittab
...
ttyAMA0::respawn:/sbin/getty -L ttyAMA0 115200 vt100 # GENERIC_SERIAL
...

After copying the new image to the SD card, login through serial console will be enabled:

Welcome to Buildroot
buildroot login:

Default login is root and password is not set.

# ls -al /
total 31
drwxr-xr-x 18 root root 1024 Apr 3 2016 .
drwxr-xr-x 18 root root 1024 Apr 3 2016 ..
drwxr-xr-x 2 root root 3072 Apr 3 2016 bin
drwxr-xr-x 7 root root 2580 Jan 1 00:00 dev
drwxr-xr-x 5 root root 1024 Jan 1 00:00 etc
drwxr-xr-x 4 root root 1024 Apr 3 2016 lib
lrwxrwxrwx 1 root root 3 Apr 3 2016 lib32 -> lib
lrwxrwxrwx 1 root root 11 Apr 3 2016 linuxrc -> bin/busybox
drwx------ 2 root root 16384 Apr 3 2016 lost+found
drwxr-xr-x 2 root root 1024 Mar 1 2016 media
drwxr-xr-x 3 root root 1024 Jan 1 1970 mnt
drwxr-xr-x 2 root root 1024 Mar 1 2016 opt
dr-xr-xr-x 52 root root 0 Jan 1 00:00 proc
drwx------ 2 root root 1024 Jan 1 00:00 root
drwxr-xr-x 3 root root 140 Jan 1 00:00 run
drwxr-xr-x 2 root root 1024 Apr 3 2016 sbin
dr-xr-xr-x 11 root root 0 Jan 1 00:00 sys
drwxrwxrwt 2 root root 60 Jan 1 00:00 tmp
drwxr-xr-x 6 root root 1024 Apr 3 2016 usr
drwxr-xr-x 4 root root 1024 Apr 3 2016 var

The system is now functional and ready for further customizations.