Raspberry Pi Gentoo

Raspberry Pi Gentoo
linux, gentoo, raspberry pi
A Gentoo distribution for the Raspberry Pi $25 computer.
Last Update:


This project is an attempt to build and prepare a minimal Gentoo Linux distribution for the Raspberry Pi computer board.

Because we are installing a new system, permissions will be important to preserve. For that reason, it is assumed that all of these steps are followed while we have root priviledges. The reason for this is that the system image being created will have many files created with UID 0 (root) and we will not be able to modify them as a standard user.

This setup will assume you have an existing computer with Gentoo installed on it. Since the Raspberry Pi runs off of an SD card and a 700mhz processor, we will be reducing the space and processing requirements by cross-building all of our packages on the host computer.

Initial setup

In this section we'll cover the various utilities you're going to need on the host system before you can begin building for Raspberry Pi.

Working directory

First we need to make a base working directory. We'll call it ${RASPIGEN}.

# make the working directory
mkdir -p "${RASPIGEN}"
# change to that directory
cd "${RASPIGEN}"
# make some other directories
mkdir ./root
mkdir ./mnt

QEmu emulator

In order to build Gentoo for Raspberry Pi, we will be using the QEmu emulator to run ARM-compiled libraries. First we need to download and compile QEmu for ARM:

# move to our working directory
# clone qemu-1.0
git clone git://git.qemu.org/qemu.git -b stable-1.0
# move to qemu directory
cd qemu
# configure for static arm-linux-user target with most features disabled
./configure --target-list=arm-linux-user --static --disable-{sdl,vnc,xen,curses,curl,bluez,kvm,vde,attr,smartcard,guest-agent,libiscsi,spice,docs,attr,linux-aio,blobs}
# compile
# copy output to root directory
mkdir -p ../root/opt/rpi-build/
cp arm-linux-user/qemu-arm ../root/opt/rpi-build/

Now create the following file under ${RASPIGEN}/qemu:

#include <string.h>
#include <unistd.h>
int main(int argc, char **argv, char **envp) {
	char *newargv[argc + 3];
	newargv[0] = argv[0];
	newargv[1] = "-cpu";
	newargv[2] = "arm1176";
	memcpy(&newargv[3], &argv[1], sizeof(*argv) * (argc - 1));
	newargv[argc + 2] = NULL;
	return execve("/opt/rpi-build/qemu-arm", newargv, envp);

Then statically build our wrapper and copy it to our root directory:

# build
gcc -static qemu-wrapper.c -o qemu-wrapper
# move
cp qemu-wrapper ../root/opt/rpi-build/
This wrapper will be used to run our ARM binaries. It is necessary to create a wrapper so that we can specify the proper CPU to emulate (in our case arm1176). We must also build a static binary to remove any dependencies to the host system since within our chroot all binaries except qemu-arm and qemu-wrapper will be ARM binaries.


For those of you who aren't aware, there is a magical module for the Linux kernel known as binfmt_misc. What it does is essentially scan any binaries attempting to be ran for a magic string at a specific offset, and if found pass them off to another program to be read.

We will be using this to allow us to run ARM-compiled binaries on our x86 system! Through the magic of binfmt_misc we can have our kernel look for ARM binaries and pass them to qemu-arm for emulation.

You MUST have a kernel with binfmt_misc support. This can be done by either compiling your kernel with CONFIG_BINFMT_MISC=m if building as a module or CONFIG_BINFMT_MISC=y to build it in.

Once you have binfmt_misc, you need to insert the module and mount the proper proc directory. The following commands will do this for you as necessary:

[ -d /proc/sys/fs/binfmt_misc ] || modprobe binfmt_misc
[ -f /proc/sys/fs/binfmt_misc/register ] || mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

Lastly we need to register our binary format. The following string is interpreted as :name:type:offset:magic:mask:interpreter:flags. So given the following registration string, we will be registering a magic string interpreter by the name of arm_rpi, and assigning it to pass any ARM binaries it detects to /opt/rpi-build/qemu-wrapper.

We set binfmt_misc to point to /opt/rpi-build/qemu-wrapper instead of ${RASPIGEN}/root/opt/rpi-build/qemu-wrapper because we will eventually be changing our root to ${RASPIGEN}/root and thus with the new root, we need to chop that portion of the path off for the binary to still be found.
echo ':arm_rpi:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/opt/rpi-build/qemu-wrapper:' > /proc/sys/fs/binfmt_misc/register

Stage 3 Installation

Now that we have QEmu installed on the host system, it's time to start setting up the base stage that will be ran on our system.

Download the stage

The first step is to download the stage tarball as well as a copy of portage. Go to the Mirror Network and pick mirror.

Download the latest stage3 tarball for armv6j_hardfp under releases/arm/autobuilds/current-stage3-armv6j_hardfp to ${RASPIGEN}.

Also download the latest portage snapshot from under snapshots.

Install the stage

Once we are done downloading these files, extract them:

cd ${RASPIGEN}/root
tar -xvjpf ../stage3-armv6j_hardfp-*.tar.bz2
tar -xvjf ../portage-latest.tar.bz2 -C usr/

CHROOT into the stage

At this point we have a base stage installed to ${RASPIGEN}/root. Now it's time to chroot into it:

# mount some needed filesystems into our new root
mount -t proc proc ${RASPIGEN}/root/proc/
mount -t sysfs sysfs ${RASPIGEN}/root/sys/
mount -o bind /dev ${RASPIGEN}/root/dev/
# copy resolve information for networking
cp -L /etc/resolv.conf ${RASPIGEN}/root/etc/
# perform the chroot
chroot ${RASPIGEN}/root /bin/bash
# update our environment
source /etc/profile
export PS1="(chroot) $PS1"

Perpare the Stage

In order to start using the stage, we will need to prepare it.

First we need to select a valid profile for our build:

eselect profile set default/linux/arm/10.0

Next edit /etc/fstab to contain the following:

/dev/mmcblk0p1  /boot   vfat    noauto,noatime  1 2
/dev/mmcblk0p2  /       ext4    noatime         0 1

Also overwrite the existing /etc/make.conf file to look like this:

CFLAGS="-Os -pipe -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard"

Rebuild for new CHOST

Since we changed our CHOST value (from armv6j-hardfloat-linux-gnueabi to armv6zk-hardfloat-linux-gnueabi) in make.conf to match the Raspberry Pi, we need to rebuild our system to handle that.

We start by rebuilding our core libraries in order to obtain a working arm6zk toolchain:

First rebuild binutils:

emerge -v1 binutils

Next we build GCC, our compiler. GCC is a bit of a memory hog to build, so in order for it to succeed we need to increase the amount of address space given to Qemu using the QEMU_RESERVED_VA environment variable.

QEMU_RESERVED_VA="0xf7000000" \
emerge -v1 gcc
This may produce a broken system with errors about not finding libgcc_s.so.1. If that happens run the following commands (where ${GCC_VER} is the version of gcc we just installed)
# specify LD_LIBRARY_PATH to point to our recently built GCC
LD_LIBRARY_PATH=/usr/lib/gcc/armv6zk-hardfloat-linux-gnueabi/${GCC_VER} \
gcc-config armv6zk-hardfloat-linux-gnueabi
# resource our profile
. /etc/profile
# re-setup our chroot prompt (gets wiped out by sourcing profile
export PS1="(chroot) $PS1"

To be safe, it is generally a good idea to remerge GCC to make sure the toolchain is sound following this change.

Finally build our C library, glibc:

emerge -v1 glibc

At this point we have a new toolchain, so we need to do some sanity checks:

# check gcc-config
gcc-config -l
# set compiler to the armv6zk one, mine was 4.5.3
gcc-config armv6zk-hardfloat-linux-gnueabi-4.5.3
# check binutils
binutils-config -l
# set binutils to the armv6zk one, mine was 2.21.1
binutils-config armv6zk-hardfloat-linux-gnueabi-2.21.1
# source and reset
source /etc/profile
export PS1="(chroot) $PS1"

Now we need to remove references to our old CHOST:

# look for files with references to the old CHOST
# this should produce some files
grep -R armv6j /etc/env.d
# double-check to makes sure we have references to the new ones
# before deleting the old
grep -R armv6zk /etc/env.d
# if all looks good, delete the old files
rm -i $(grep -R -l armv6j /etc/env.d)
# regen environment and reset
source /etc/profile
export PS1="(chroot) $PS1"

Now we need to rebuild libtool and fix some of its archives:

emerge -v1 libtool
# the GCC version I merged was 4.5.3, be sure to use the right one
/usr/share/gcc-data/armv6zk-hardfloat-linux-gnueabi/4.5.3/fix_libtool_files.sh 4.5.3 --oldarch armv6j-hardfloat-linux-gnueabi

The final step in the process is to recompile the world using the new build toolchain.

QEMU_RESERVED_VA="0xf7000000" \
emerge -ev world
This could take awhile, go grab some coffee.

When this is done, we have a functional system completely rebuilt specifically for the Raspberry Pi's hardware. The next step is to start installing the tools and utilities specific to the Raspberry Pi.

System Setup

Now that we have a working stage 3, it is time to start installing the parts of the system specific to the Raspberry Pi.

Install the overlay

I have set up an overlay that includes the R-Pi kernel patches to make things easier. First install layman:

# set up a use flag for GIT (if not in the global make.conf)
mkdir -p /etc/portage/package.use
echo "app-portage/layman git" >> /etc/portage/package.use/layman
# install
emerge -v layman

Next we need to edit the layman configuration file to include my overlay. Edit the overlays line of the /etc/layman/layman.cfg file to include the cvpcs repo:

overlays  : http://www.gentoo.org/proj/en/overlays/repositories.xml

Then we need to install layman into our make.conf file:

# sync the layman tree
layman -L
# add the cvpcs overlay
layman -a cvpcs
# hook layman into portage
echo "source /var/lib/layman/make.conf" >> /etc/make.conf

The Kernel

In order to boot the Raspberry Pi system, we need to have a kernel. The cvpcs overlay contains a copy of the Raspberry Pi patchset as rpi-sources. In this section we will install, configure, and cross-compile those sources.

Install the Sources

Install the sources onto your stage root from the cvpcs overlay.

emerge -v rpi-sources

Configure the Sources

The sources contain a default configuration specifically tailored to the Raspberry Pi device.

# change to the kernel source directory
cd /usr/src/linux
# set the default configuration for rpi
make bcmrpi_cutdown_defconfig

Next open .config and search for the line starting with CONFIG_CMDLINE, change the end of the line from rootfstype=ext3 to rootfstype=ext4 and save the file.

Compile the Kernel

Finally it is time to compile the kernel and modules:

# compile the kernel and modules
# install the modules into the appropriate location
make modules_install

FIXME stuff needs to be fixed here

SD Card Setup

The next step is to plug in the SD card you plan to use and prepare it for your Raspberry Pi.

Be sure to check out the Raspberry Pi Verified Peripherals page to ensure that your SD card is supported!

I will assume your SD card was recognized as /dev/mmcblk0. This may not be the case depending on your kernel setup. If you connected your SD card via a USB SD card reader it may appear as /dev/sdX (where X is some letter).


The first step is setting the geometry of our SD card.

Make sure you are sure about what you are doing or you may accidentally destroy data that you didn't want to lose! The following commands will wipe all data from the device you are dealing with!

Open fdisk:

fdisk /dev/mmcblk0

Wipe the contents by typeing o, ENTER.

Command (m for help): o
Building a new DOS disklabel with disk identifier 0x82af8ca7.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Print the card info by pressing p, ENTER.

Command (m for help): p

Disk /dev/mmcblk0: 15.9 GB, 15931539456 bytes
256 heads, 63 sectors/track, 1929 cylinders, total 31116288 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: 0x82af8ca7

   Device Boot      Start         End      Blocks   Id  System
Note the card size in bytes (in my case, 15931539456). This will be used next to calculate the disk cylinder count.

Next we enter expert mode by typing x, ENTER. And then set the geometry to 255 heads and 63 sectors by typing h, ENTER, 255, ENTER and s, ENTER, 63, ENTER, respectively.

Command (m for help): x

Expert command (m for help): h
Number of heads (1-256, default 256): 255

Expert command (m for help): s
Number of sectors (1-63, default 63): 63

Now we need to calculate the number of cylinders. The calculation is done based on the following formula:

$$ \text{cylinders} = \left \lfloor \frac{\text{total_size_in_bytes}}{\text{heads} \cdot \text{sectors} \cdot 512} \right \rfloor $$

Hence in our calculation looks as such:

$$ \text{cylinders} = \left \lfloor \frac{15931539456}{255 \cdot 63 \cdot 512} \right \rfloor = \lfloor 1936.899346405 \rfloor = 1936 $$

Enter this number as the cylinder count by typing c, 1936 (or whatever number you came up with), ENTER. Then leave expert mode by typing r, ENTER.

Expert command (m for help): c
Number of cylinders (1-1048576, default 1929): 1936

Expert command (m for help): r


Now we have to partition the SD card. At this point you should be in the basic command prompt for fdisk. We will be creating two partitions: a boot and root partition.

First make the boot partition. This must be a FAT32 partition and bootable. Type the following to create a 64MB boot partition: c, ENTER, ENTER, ENTER, ENTER, +64M, ENTER, t, ENTER, c, ENTER, a, ENTER, 1, ENTER.

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 
Using default value 1
First sector (2048-31116287, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-31116287, default 31116287): +64M

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))

Command (m for help): a
Partition number (1-4): 1

Next we fill the rest of the disk with our Linux root partition by typing n, ENTER, ENTER, ENTER, ENTER, ENTER.

Command (m for help): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): 
Using default response p
Partition number (1-4, default 2): 
Using default value 2
First sector (133120-31116287, default 133120): 
Using default value 133120
Last sector, +sectors or +size{K,M,G} (133120-31116287, default 31116287): 
Using default value 31116287

Finally, write the changes to the card by typing w, ENTER. This will exit fdisk.

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
Syncing disks.
If your partition devices don't appear (/dev/mmcblk0p1, /dev/mmcblk0p1, etc), then you may need to remove and re-insert your SD card.


Lastly you need to create the filesystems on your new partitions. This can be done using the following steps (taking note to use the proper partition devices):

mkfs.vfat -F 32 /dev/mmcblk0p1 -n RPI_BOOT
mkfs.ext4 /dev/mmcblk0p2 -L RPI_ROOT

Prepare the boot partition

Now we need to prepare the boot partition.

Then we install the boot firmware and utilities package:

# install bootloader and tools
xmerge -v rpi-boot
xmerge -v rpi-tools

Then we package up the kernel we just built and throw it on the boot partition.

# create the kernel bootable image
"${RASPIGEN}"/root/usr/bin/rpi-mkimage \
	"${RASPIGEN}"/root/usr/src/linux/arch/arm/boot/Image \

FIXME need to set the root password in some way, below is a hash that can be thrown in the shadow file to set the password to “root”, but there needs to be a better way than this


FIXME This isn't true, we don't have them copy to the SD card yet

At this point your boot card should be good to go! Unmount it and try it out!

cd "${RASPIGEN}"
umount "${RASPIGEN}"/root/boot
umount "${RASPIGEN}"/root

FIXME Specify common things to do after installation completes such as changing CHOST and setting up SSH+Networking


projects/linux/raspigen.txt · Last modified: 2014/05/13 12:36 (external edit)

Hosted on Microsoft Azure Powered by PHP Driven by DokuWiki RSS Feed

© 2011 Austen Dicken | cvpcs.org