My *nix world

Gentoo on Raspberry Pi

Few weeks ago I received my long awaited Raspberry Pi board. For those that (yet) don't know what a Raspberry-Pi is, "The Raspberry Pi is a credit-card sized computer that plugs into your TV and a keyboard. It's a capable little PC which can be used for many of the things that your desktop PC does, like spreadsheets, word-processing and games. It also plays high-definition video" (source: www.raspberrypi.org).

gentoo on raspberry pi

click to zoom

If someone wonders "what can be done with such a small little toy?" then maybe you should answer this question first: "what is a smart-phone?"
Anyway, to get a grasp of what this might offer, one should check out the board layout:

gentoo on raspberry pi

source: http://elinux.org/RPi_Hardware_Basic_Setup

I'm not going to develop more this subject, additional info can be found at: http://elinux.org/RPi_Hub.

I'm going to tell you how I have installed Gentoo on Raspberry Pi:

Note: make sure you are logged as root so we don't have to 'sudo' all the time.

Create a disk image for your Raspberry Pi

First of all you should know how large is your SDHC card (eg, 2GB, 4GB,..., 32GB). Let's suppose that your SHDC card is 2GB. When you get this info all you have to do is to run the following command (remember: 1GB is 1024*1024*1024 is 1073741824 bytes):

export RPI_IMG=/path-to-image/my-image.img
dd if=/dev/zero of=${RPI_IMG} bs=4096 count=$((2*1000*1000*1000/4096))

This image file is your (r-pi) disk image file, also it will contain your r-pi "hard disk" image. So all we have to do is to mount this disk, to create partitions and the necessary file system.

Create partitions, file-systems, mount the file-systems

The following will setup a loop device linked to your image file:

export RPI_DEV=$(losetup -f --show -P ${RPI_IMG})

Now that we have the disk device, first thing we create the disk partitions with a similar layout like this one (note that our disk device is called /dev/loop1):

Disk /dev/loop1: 2000 MB, 2000000000 bytes
255 heads, 63 sectors/track, 243 cylinders, total 3906250 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x58f30fd1

      Device Boot      Start         End      Blocks   Id  System
/dev/loop1p1   *        2048       69631       33792    c  W95 FAT32
/dev/loop1p2           69632      133119       31744   82  Linux swap
/dev/loop1p3          133120     3906249     1886565   83  Linux

Once your disk is partitioned, make sure that you can see/access all those /dev/loopXpY partitions (where X is your loop device, Y is the number of partition: 1,2,3,..). If they are not visible (they should be, see -P option in losetup utility) then you can force the OS to update its partition table:

partprobe ${RPI_DEV}

Once the partitions are ready we need to format them with a file-system so that we can store files on disk, right?

mkfs.vfat -F 32 -n RpiBoot ${RPI_DEV}p1
mkswap ${RPI_DEV}p2 "" swapon ${RPI_DEV}p2
mkfs.ext4 -L RpiRoot ${RPI_DEV}p3

Note: if you have a 2GB image then those 2000MB of ${RPI_DEV}p3 will be insufficient so I recommend specifying the number of inodes to create:

mkfs.ext4 -T small -L RpiRoot ${RPI_DEV}p3

Now that we have an working disk image we should mount its partitions as local mount points where we are going to deploy Gentoo's files:

export RPI_ROOT=/mnt/rpi
mkdir -p $RPI_ROOT "" mount ${RPI_DEV}p3 $RPI_ROOT
mkdir $RPI_ROOT/boot "" mount ${RPI_DEV}p1 $RPI_ROOT/boot
cd $RPI_ROOT
wget -O - http://distfiles.gentoo.org/releases/arm/autobuilds/current-stage3-armv6j_hardfp/stage3-armv6j_hardfp-YYYYMMDD.tar.bz2|tar xpjf -
wget -O - http://distfiles.gentoo.org/snapshots/portage-latest.tar.bz2| tar xpjf - -C usr/

Gentoo basic setup pre-first-boot

To make sure that you boot with a functional network, you can login with the root, you have an working ssh daemon, etc, we have to make some small adjustments first:

  • edit $RPI_ROOT/etc/shadow and reset root password: root::10770:0:::::
  • edit $RPI_ROOT/etc/conf.d/net and add the following lines:
auto_eth0="true"
config_eth0="dhcp"
  • edit $RPI_ROOT/etc/fstab and adjust the mount points to match the virtual disk (/dev/sda):
#                                           <dump/pass>
/dev/sda1               /boot           auto            noauto,noatime  1 2
/dev/sda3               /               ext4            noatime         0 1
/dev/sda2               none            swap            sw              0 0
  • edit $RPI_ROOT/etc/conf.d/hostname and adjust the system name: hostname="rpi-gentoo"
  • edit $RPI_ROOT/etc/conf.d/hwclock and adjust the guest clock according to your host hwclock
  • copy your timezone to $RPI_ROOT/etc/: cp $RPI_ROOT/usr/share/zoneinfo/XXX etc/localtime, where XXX coresponds to your timezone (eg. Europe/Stockholm); edit also /etc/timezone and add the zone name (eg. Europe/Stockholm)
  • if necessary adjust you keymaps at $RPI_ROOT/etc/conf.d/keymaps
  • comment "s0:12345:respawn..." console in $RPI_ROOT/etc/inittab

Note: if you are going to deploy this image on a SDHC card then you should replace the /dev/sda/* (on $RPI_ROOT/etc/fstab) with /dev/mmcblk0/*.

Compile the kernel

So far we have deployed the required Gentoo files. Next step will be to build a qemu kernel for our ARM cpu that will allow us to run this Linux on a qemu emulator. If you plan to compile the kernel for the real thing (BCM2835 hardware) the procedure is quite the same (I will make a note where they differ). For this we need a cross-toolchain that allows us to compile ARM code on a X86 platform.

At first I have tried the sys-devel/crossdev toolchain builder but every time there was something that didn't worked out of the box. I thought that maybe it's something about my system so I've tried to install a a fresh copy of Gentoo (on a virtual machine, of course :o) but nothing helped. If you instead prefer doing the old way (i.e. manually) then try this link first.

Finally I found an working alternative to those one, it's called sys-devel/ct-ng and it works like a charm:

mkdir /tmp/work "amp;"amp; cd /tmp/work
ct-ng list-samples # the list of samples/profiles
ct-ng show-armv6-rpi-linux-gnueabi # pick your sample, I chose Raspberry Pi
ct-ng armv6-rpi-linux-gnueabi # configure the sample we are using
# ct-ng menuconfig
ct-ng build # build a cross toolchain based on our chosen sample
export PATH=${PATH}:${HOME}/x-tools/armv6-rpi-linux-gnueabi/bin
armv6-rpi-linux-gnueabi-gcc -v # test it!

Note: if the toolchain sample you choose is not pre-configured as you wish, then before running "ct-ng build" you can run "ct-ng menuconfig" and tune your toolchain as needed. More here.

Once your cross-toolchain is built we are ready to compile the kernel. But wait! First we have to grab its source from Internet/github.

cd /tmp/
git clone https://github.com/raspberrypi/linux.git
wget -O /tmp/linux-arm.patch http://xecdesign.com/downloads/linux-qemu/linux-arm.patch
patch -p1 -d ./ < /tmp/linux-arm.patch

Now that we have the kernel source code we are ready to compile the kernel (make sure that you check also kernel Device Drivers -> Real Time Clock settings) :

mkdir /tmp/modules "" cd /tmp/linux
make ARCH=arm versatile_defconfig
make ARCH=arm menuconfig
make ARCH=arm -j2
make ARCH=arm INSTALL_MOD_PATH=../modules modules_install
export RPI_KERNEL=arch/arm/boot/zImage

Note: if you are going to compile the kernel for the real thing then you should use bcmrpi_cutdown_defconfig default configuration instead of versatile_defconfig above. See more on your linux/arch/arm/configs/ folder.

Test it inside the QEMU emulator

Once the kernel is built you can use it right away (recommended at least on first boot):

qemu-system-arm -M versatilepb -cpu arm1176 -hda $RPI_DEV -kernel $RPI_KERNEL -append "root=/dev/sda3 panic=1" -m 256 -net nic -net user -redir tcp:2222::22

Note: in the above we have just started a qemu emulator with for a system with an ARM1176 cpu, 256 MB RAM, using our custom kernel, and our disk image, with a fully functional network (read more) where we can connect by ssh from the local host like:

ssh root@localhost -p 2222 # the local 2222 was previously redirected to the qemu port 22

You can even connect the qemu via VNC, usually when it starts is shows you the VNC server:port to use. If instead you want no VNC but all the output redirected to your terminal console then start the qemu like this:

qemu-system-arm -M versatilepb -cpu arm1176 -hda $RPI_DEV -kernel $RPI_KERNEL -append "root=/dev/sda3 panic=1 console=ttyAMA0" -m 256 -net nic -net user -redir tcp:2222::22 -nographic

Moreover, you can even monitor the qemu and communicate with qemu, such as adding a new device, ejecting a device, pausing/resuming the VM, etc:

qemu-system-arm -M versatilepb -cpu arm1176 -hda $RPI_DEV -kernel $RPI_KERNEL -append "root=/dev/sda3 panic=1 console=ttyAMA0" -m 256 -net nic -net user -redir tcp:2222::22 -nographic -monitor telnet:localhost:4444,server,nowait

, then you can access the qemu monitor by:

telnet localhost 4444

Here you can find some extra info regarding using qemu.

Gentoo basic setup post-first-boot

Now that the system just boot-up without problems, connect the guest terminal via VNC, enter the login name root (no password will be required; remember /etc/shadow ?). We have few things to setup so that next boot everything will be in place and working:

  • edit /etc/locale.gen and set your locale then run locale-gen command
  • run the following command: cd /etc/init.d "" ln -s net.lo net.eth0 "" rc-update add net.eth0 default
  • rc-update add sshd default
  • setup the root password by running the following command: passwd
  • run command "eselect profile list" and check out the profile list then "eselect profile set XX" where XX is the identifier for the profile that fits you

Info: If it's happening that at first boot some services like netmount (or those that depends on net) refuse to start, maybe it's a good idea to "emerge -qDuN world" and reboot the system.

For more about possible settings read this.

Transfer the kernel to boot partition

So the kernel it's working and we want to transfer it to the boot partition, on our disk image. The kernel is named Image and can be found on the same path as zImage, i.e. arch/arm/boot/Image. Just copy it to our mount point (remember?) $RPI_ROOT/boot/ with a name like kernel.img.

You should also create a file called /boot/cmdline.txt with the following content:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 kernel=kernel.img root=/dev/mmcblk0p3 rootfstype=ext4 elevator=deadline rootwait

Pay attention to the kernel name, root partition name and file system type. They should match those names/type that you have configured at the previous steps.

You could also have a file called /boot/config.txt where you can define various settings for your real R-Pi machine (doesn't work with qemu emulator, though):

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# for more options see http://elinux.org/RPi_config.txt

We need to transfer the kernel modules too, so just copy the folder ../modules/lib to the root mount point ($RPI_ROOT):

cp -r ../modules/lib/ $RPI_ROOT

We need one more thing: the Raspberry Pi firmware. Once you got it we have to copy these three files {bootcode.bin,fixup.dat,start.elf} in the $RPI_ROOT/boot:

cp firmware/boot/{bootcode.bin,fixup.dat,start.elf} $RPI_ROOT/boot/

Next we have to copy the VC library from the firmware to the /opt folder inside the rpi:

cp -r firmware/hardfp/opt $RPI_ROOT/

Transfer the disk image to your SDHC

Since your disk image is ready, we have to transfer it to your SDHC card. First, make sure that all mount points to that disk image are unmounted then run the following command:

dd if=$RPI_IMG of=/dev/sdX bs=4096 count=$((2*1000*1000*1000/4096)) #where X is your SHDC device

BTW: if you don't have a SD-CARD reader on your system (where you've prepared the R-Pi disk image) like me, you could get an USB2 SD/MMC/RS-MMC SDHC memory card reader (1..16 GB) from eBay for only 1$.

First live test

At this point our Raspberry Pi is ready for a live test! If you want to tune the R-Pi even more then check this link.

If everything went fine then you should be able to get a first impression of your Pi:

rpi-gentoo ~ # cat /proc/cpuinfo 
Processor    : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS    : 697.95
Features    : swp half thumb fastmult vfp edsp java tls 
CPU implementer    : 0x41
CPU architecture: 7
CPU variant    : 0x0
CPU part    : 0xb76
CPU revision    : 7

Hardware    : BCM2708
Revision    : 000f
Serial      : 00000000xxxxxxxx

If 700MHz is not enough for you then you might try to overclock you R-Pi.

Since R-Pi does not have an Real Time Clock (source Wikipedia):

The Raspberry Pi does not come with a real-time clock,[7] so an OS must use a network time server, or ask the user for time information at boot time to get access to time and date for file time and date stamping. However, a real-time clock (such as the DS1307) with battery backup can be added via the I ²C interface.

we have to provide a mean by which Linux will synchronize its date/time every time you boot the R-Pi (unless you wish to enter that manually every time you boot the R-Pi). I am using openntpd at this time and its installation/setup is straightforward:

emerge -q openntpd

After installation make sure to edit /etc/conf.d/ntpd and to uncomment the NTPD_OPTS="-s" option. Moreover, edit the /etc/ntpd.conf file and add some Internet public NTP Pool Servers to it such way that your little daemon can feed itself with the current date/time every time you reboot your system:

server 0.se.pool.ntp.org
server 1.se.pool.ntp.org
server 2.se.pool.ntp.org
server 3.se.pool.ntp.org

Once everything is done, remember to add the ntpd service to the RC-init system such it starts automatically at boot:

rc-update add ntpd default

Make sure you have installed the sudo program, if not then install it right away:

emerge -qDuN sudo

Don't forget to add your user to /etc/sudoers file:

my-user-name ALL=(ALL) ALL

That would be all. Have fun!

Btw: one interesting thing about this Gentoo on R-Pi is that with the following services it eats only 24MB of RAM, while the SDHC card is only 1.3G:

 udev-mount              [  started  ]
 sysfs                   [  started  ]
 devfs                   [  started  ]
 dmesg                   [  started  ]
 udev                    [  started  ]
 hwclock                 [  started  ]
 swap                    [  started  ]
 modules                 [  started  ]
 fsck                    [  started  ]
 root                    [  started  ]
 mtab                    [  started  ]
 localmount              [  started  ]
 sysctl                  [  started  ]
 bootmisc                [  started  ]
 urandom                 [  started  ]
 net.lo                  [  started  ]
 termencoding            [  started  ]
 tmpfiles.setup          [  started  ]
 hostname                [  started  ]
 keymaps                 [  started  ]
 procfs                  [  started  ]
 swapfiles               [  started  ]
 net.eth0                [  started  ]
 netmount                [  started  ]
 sshd                    [  started  ]
 local                   [  started  ]

This sound very promising and it means that I still have ~480M RAM for my projects (games, X11, etc). I made a copy its disk (2G SDHC) image and I shared to the public domain. You can download it from here, it is only 475M (lzma compression; root pwd=rpi) and includes, in addition to the default Gentoo stage3, sudo, screen, gentoolkit, openntpd, distcc, ncdu (which I found them very useful by default).

Next stop...Python!

Now, if you think that this article was interesting don't forget to rate it. It shows me that you care and thus I will continue write about these things.

The following two tabs change content below.
Gentoo on Raspberry Pi

Eugen Mihailescu

Founder/programmer/one-man-show at Cubique Software
Always looking to learn more about *nix world, about the fundamental concepts of math, physics, electronics. I am also passionate about programming, database and systems administration. 16+ yrs experience in software development, designing enterprise systems, IT support and troubleshooting.
Gentoo on Raspberry Pi

Latest posts by Eugen Mihailescu (see all)

Tagged on: , ,

3 thoughts on “Gentoo on Raspberry Pi

  1. Eugen Mihailescu

    Regarding the SDHC disk image I shared on my Google Drive, I've done the both experiments:
    a) I've built myself the kernel to be run within Qemu
    b) I've built the kernel to be run within RaspberryPi.
    The image contains the experiment for b).

    1)
    The provided disk image contains the kernel downloaded from github.com/raspberrypi/linux.git, moreover I applied the patch mentioned grabbed from xecdesign.com/downloads/linux-qemu/linux-arm.patch (but I don't think it is required anymore, as of today).

    2)
    Nonetheless, the disk image contains the Gentoo stage 3+ few others tools (like sudo, screen, distcc, gentoolkit, ncdu and openntpd) that I've considered they should be out of the box.
    Stage 3 contains also gcc, because Gentoo means "compile your system from source" which requires a compiler, right?

    So gcc-v:
    gcc version 4.6.3 (Gentoo 4.6.3 p1.11, pie-0.5.2)
    uname -a:
    Linux rpi-gentoo 3.6.11-cutdown+ #17 PREEMPT Mon Feb 18 14:27:02 CET 2013 armv6l ARMv6-compatible processor rev 7 (v6l) BCM2708 GNU/Linux
    If you need the kernel for Qemu you can follow the procedure I've described in the post or I can compile it for you and I will share it as well on my Google Drive.

Leave a Reply

Your email address will not be published. Required fields are marked *