Installing Gentoo on a Raspberry PI

Install ARM Toolchain

$ emerge -av crossdev
$ crossdev -S -v -t armv6j-hardfloat-linux-gnueabi

Get Raspberry Kernel Sources

$ git clone --depth=1 https://github.com/raspberrypi/linux.git
$ wget http://xecdesign.com/downloads/linux-qemu/linux-arm.patch
$ patch -p1 -d linux/ < linux-arm.patch

Configure the Kernel for QEMU

$ cd linux
$ make ARCH=arm menuconfig
$ make ARCH=arm
$ make ARCH=arm INSTALL_MOD_PATH=../modules modules_install
$ cp arch/arm/boot/zImage ../raspi-kernel

This is my .config
and the corresponding zImage and Modules: kernel_raspi_qemu.tar

Prepare “SD Card”

Create a sparse Image (this will be the SD Card)
$ dd if=/dev/null of=gentoo-raspi.img bs=1G seek=8 # 8GiB Image Partition Image
$ cfdisk gentoo-raspi.img
#first partition: boot, vfat ~80MiB (Partition Type: 0x0C)
#second: Gentoo Root (Partition Type: 0x83)

Mount Image as NBD

$ modprobe nbd max_part=4
$ qemu-nbd --connect=/dev/nbd0 -n /path/to/gentoo-raspi.img

$ emerge -av dosfstools
$ mkfs.vfat -n boot /dev/nbd0p1
$ mkfs.ext4 -j -L Gentoo -E lazy_itable_init=0,lazy_journal_init=0 /dev/nbd0p2
$ mount /dev/nbd0p2 /mnt/raspi
$ cd /mnt/raspi
$ curl http://distfiles.gentoo.org/releases/arm/autobuilds/current-stage3-armv6j_hardfp/stage3-armv6j_hardfp-20130207.tar.bz2 | tar -xvjp

Prepare Base System


$ dd if=/dev/zero of=/mnt/raspi/var/swap bs=1M count=512
$ chmod 0600 /mnt/raspi/var/swap
$ mkswap /mnt/raspi/var/swap

$ cd /mnt/raspi/etc
$ vi fstab


Insert the following lines:
LABEL=Gentoo / ext4 noatime 0 1
LABEL=BOOT /boot vfat noatime,defaults 0 0
/var/swap swap swap defaults 0 0

Set Root Password
$ openssl passwd -1 raspi
$ vi shadow

first line: root:$1$pDGeoXQj$0zq3sa5b9o9rJ8CpcIpPR/:10770:0:::::

Set Hostname & Keymap & timezone
$ vi conf.d/hostname
$ vi conf.d/keymaps
$ ln -sf ../usr/share/zoneinfo/Europe/Berlin localtime

Configure locale.gen
$ vi /etc/locale.gen

Copy Kernel Modules
$ cp -av /path/to/modules/lib /mnt/raspi

Install Portage
$ curl http://distfiles.gentoo.org/snapshots/portage-latest.tar.bz2 | tar -xvjp -C /mnt/raspi/usr

Set correct make.profile
$ cd /mnt/raspi/etc/portage rm make.profile
$ ln -sf ../../usr/portage/profiles/default/linux/arm/13.0 make.profile

Disconnect NBD
$ umount /mnt/raspi
$ qemu-nbd --disconnect /dev/nbd0

Boot your Raspberry on QEMU

$ qemu-system-arm -kernel zImage -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 console=ttyAMA0" -hda gentoo-raspi.img
Login: root:raspi
Set Date (Raspi has no hardware Clock πŸ™ )
$ date --set="20130808 14:00"
$ rc-update del hwclock default

Configure Network
$ ifconfig eth0 10.0.2.15 #USE THIS IP!
$ route add default gw 10.0.2.2
$ echo nameserver 8.8.8.8 > /etc/resolv.conf #just use google's dns

Get dhcp Client and configure network
$ emerge dhcpcd
$ dhcpcd

Configure eth0 persistently
$ cd /etc/init.d
$ ln -s net.lo net.eth0
$ rc-update add net.eth0 boot

$ cd /etc/conf.d/
$ nano net

add the line: config_eth0="dhcp"

You WANT distcc.
emerge -av distcc #Run on both, host and guest

Edit make.conf
$ echo FEATURES="distcc" >> /etc/portage/make.conf
$ echo MAKEOPTS="-j6" >> /etc/portage/make.conf

Set DistCC Hosts
$ cd /etc/distcc
$ nano hosts

Now compile everything you want

Emerge boot stuff and kernel
$ mkdir /etc/portage/package.keywords
$ cd /etc/portage/package.keywords
$ echo sys-boot/raspberrypi-firmware ** ~arm >> raspi
$ echo sys-kernel/raspberrypi-sources ** ~arm >> raspi
$ echo media-libs/raspberrypi-userland ** ~arm >> raspi

$ mount /boot
$ emerge -av raspberrypi-firmware raspberrypi-sources raspberrypi-userland

Compile the kernel
$ cd /usr/src/linux
$ make menuconfig

$ make CC="distcc armv6j-hardfloat-linux-gnueabi-gcc" modules -j5
$ make modules_install
$ make CC="distcc armv6j-hardfloat-linux-gnueabi-gcc" -j5
$ cp arch/arm/boot/zImage /boot/kernel.img

This is my precompiled Kernel and Modules / Firmware:
.config
kernel-3.6.11-raspi.tar.gz

You also want to use SSH:
$ rc-update add sshd default

And as we do have no RTC:
$ rc-update add ntp-client default

And a syslogger:
$ emerge -av syslog-ng
$ rc-update add syslog-ng boot

Here's my image:
It needs at least 2.8GiB of space (2.3GiB without /var/swap)

As .tar.gz archive:
VFAT Boot Partition: Raspberry-Boot-20130816.tar.gz
Gentoo Installation: Raspberry-Stage4-20130816.tar.gz

As full 6GiB raw image which is bootable out of the box:
Raspberry-Gentoo-6GiB-Image-20130816.img.gz

You can use dd to flash it on a SD Card
$ gunzip Raspberry-Gentoo-6GiB-Image-20130816.img.gz
$ dd if=Raspberry-Gentoo-6GiB-Image-20130816.img of=/dev/yourraspisdcard

Have fun with Gentoo on your Raspi πŸ™‚

Update 2014-06-03:

Here's another nice tutorial without any cross-compilation

15 thoughts on “Installing Gentoo on a Raspberry PI”

  1. I’m trying to follow your procedure using gentoo (kernel 3.10.7 with nbd and kvm_amd support built in). After the first few steps, I’m qemu-nbd connected to the .img, but mkfs of the partitions is a no-go. I note that device nodes are not listed in /dev/ for the partitions. I can see them if I “fdisk /dev/nbd0” … they are called /dev/nbd0p1 and /dev/nbd0p2 just like your procedure shows – but I cannot access them. Is it possible I’ve missed some important USE flag when I merged qemu ? or can you think of something else?

    1. Hi Joe,

      use MUST load the nbd kernel module with the argument max_part=4. That means, that NBD is allowed to have four “subpartitions”. By default and unfortunately NBD is loaded with the argument max_part=0.

      I recommend to use NBD as a kernel module, not compiled in. If NBD support is still compiled in, then I *think* you could use nbd.max_part=4 as kernel commandline argument.

      You can check your max_part using
      cat /sys/module/nbd/parameters/max_part

      Regards

  2. Thanks, Ralf. I rebuilt my host’s kernel with nbd support as a kernel module. qemu-nbd –connect now works fine. I then followed more of your procedure, with one exception. I loop-mounted an image from an SDHC I already configured for my raspberry (using procedure from http://wiki.gentoo.org/wiki/Raspberry_Pi_Quick_Install_Guide) and did “cp -a /mnt/image /mnt/raspi” to load a mature root filesystem. This simplified getting networking and so on, although I did still have to set date before I could start all my services.

    Problem now. Although I am booted with qemu-system-arm, and the root filesystem is up and running, and I can emerge and everything, I cannot mount boot.

    The error I get is:
    mount: wrong fs type, bad option, bad superblock on /dev/sda1, missing codepage or helper program, or other error. In some casees useful info is found… try dmesg | tail.

    In my qemu-system-arm guest, I emerged dosfstools and redid “mkfs.vfat -n boot /dev/sda1” and tried “fsck.vfat -a /dev/sda1” both of which succeed. When I inspect dmesg | tail, I notice that it seems the operative error is “FAT-fs (sda1): IO charset iso8859-1 not found” … I notice also that message is preceded by “nls_iso8859-1: version magic ‘3.6.11+ preempt mod_unload modversion ARMv6 ‘ should be ‘3.6.11+ mod_unload ARMv6 p2v8 ‘

    I confirmed that my /etc/locale.gen contains:
    en_US ISO-8859-1
    en_US.UTF-8 UTF-8

    and I re-ran locale-gen which reports success. However,
    I still cannot mount /boot. I also tried explicitly “mount -t vfat /dev/sda1 /boot” but I get the same result.

    Any suggestions?

    1. Yip,

      go to your Kernel config and setup
      “File Systems -> Native language support” and activate the corresponding codepage.

      Regards

  3. Ok – yes, I see my error there. That worked. I’ve now got /boot mounted, and I’ve emerged raspberrypi-firmware, -userland, and -sources.

    However, when I cd /usr/src/linux and make menuconfig (or oldconfig), I get ld errors about “relocations in generic ELF … could not read symbols … file in wrong format.”

    Is that a result of my use of the root filesystem from my running system? (i.e. somehow different from what the raspi-kernel expects) Do I need to go back and build up the root filesystem (incl toolchain and portage) from scratch? (I was hoping to avoid)

    Also – why do you use just the 13.0 profile in the manually created link? (why not 13.0/armv6j ?)

    1. Yes, you are right, the armv6j could have been used – I didn’t see it at that moment. Which profile do you use? Perhaps this causes your error.

      I never had an error like that, I don’t know what happens there. Do you use DistCC for Compiling? If so, try not to use distcc first.

      Where do you exactly run menuconfig? (I hope on your raspi πŸ˜‰ ). You could also check if your compiler is set correctly using gcc-config.

  4. I previously had set the 13.0/armv6j/desktop profile because I eventually wanted to install an lxde desktop (like raspbian uses), but I changed it according to your instruction. I also tried switching to the 13.0/armv6j profile, but I got the same errors. (It occurs to me I may need to run a world update after changing the profile, since that root filesystem was copied from a more mature system with packages installed under a different profile πŸ™ ).

    I do use distcc, but when I disable it (stop the daemon and comment out the FEATURE in make.conf on the “raspi”), I still get these errors. I do NOT get them when I emerge packages. I only get these errors when trying to “make” in /usr/src/linux.

    I run “make menuconfig” in the qemu-system-arm window on my host’s desktop (i.e. inside the emulation of the raspi-kernel and 8G “card”). gcc-config -l returns only one entry –> [1] armv6j-hardfloat-linux-gnueabi-4.6.3 *

  5. Ralf,
    After a bit of research, I’ve confirmed that (generally speaking) β€œrelocations in generic ELF … could not read symbols … file in wrong format.” error’s result from attempting to link (ld) object files (.o) that were built with a different target architecture than that desired by the current make/compile/link process. From one Q/A blog I looked at, a simpler of saying: “This last line often means the object file is for the wrong architecture so the linker does not know how to handle this.”

    This appears to be a very common mistake made by people working in cross-compile situations. In MY case, I note that the object file the error is complaining about is “scripts/kconfig/mconf.o”

    The complete error string identifies the compiler as gcc/armv6j-hardfloat-linux-gnueabi/4.6.3/… and the linker as …/armv6j-hardfloat-linux-gnueabi/bin/ld. HOWEVER, I also note that “uname -a” returns:
    “Linux Raspberry01 3.6.11+ #2 Sun Aug 25 … 2013 armv6l ARMv6-compatible processor rev 7 (v6l) ARM-Versatile PB GNU/Linux”
    (i.e. armv6l, not armv6j).

    I note that the profile selection could not have done this – there is no armv6l profile. I also verified that “/usr/lib/distcc/bin” appears early in my $PATH — which lots of online commentary indicates is a common cross-compiling problem.

    Meanwhile, I have also created another image file in which I started from scratch with stage3 as you describe above. On that image, I do NOT have this “file in wrong format” problem, and I’ve successfully compiled and installed a kernel based on a .config with very few changes to the one you posted above. I note that here also, uname -a returns armv6l rather than v6j (so that cannot be why I can’t make menuconfig on the other image).

    So, as an update on my present status: I now have two .img files, both of which will boot and run under qemu-system-arm. One won’t make menuconfig (as described above), and I’ve about abandoned that image because having a kernel of my own construction is my main motivation for this entire effort. With the other .img file, I have completed the build process you describe above and ran a couple other steps from the gentoo handbook, but I haven’t finished adding a couple capabilities I need for my target hardware (wpa_supplicant, cryptsetup, lvm2, etc).

    An additional note on another problem I ran into — the image resulting from the use of “dd if=/dev/null of=gentoo-raspi.img bs=1G seek=8” will not fit on my 8G SDHC card. It seems 8 x 1G blocks are bigger than the physical size of the card (which fdisk informs me has 8010MB). So, while these images boot and run under qemu, after I dd them to my card I end up with “partition outside the disk” errors.

    I’m dealing with that now.

  6. UPDATE: I set up a properly sized “SD Card” image with the following procedure.

    Insert card and look at what dmesg picks up

    # dmesg | tail
    ...
    sd 4:0:0:0: [sdc] 15644672 512-byte logical blocks: (8.01 GB/7.45 GiB)
    ...

    # pay attention to block count and size, and use those in creating the image
    dd if=/dev/null of=gentoo-raspi.realsize8G.card.img bs=512 seek=15644672

    Next, create the filesystems on the new image

    # qemu-nbd --connect="/dev/nbd0" gentoo-raspi.realsize8G.card.img
    # mkfs.vfat -n boot /dev/nbd0p1
    # mkfs.ext4 -j -L Gentoo -E lazy_itable_init=0,lazy_journal_init=0 /dev/nbd0p2

    Next, copy content from old (wrongly sized) image to new (properly sized) image:

    # qemu-nbd --connect="/dev/nbd1" gentoo-raspi.img
    # mount /dev/nbd0p1 /mnt/raspi/
    # mount /dev/nbd1p1 /mnt/image/
    # cp -a /mnt/image/* /mnt/raspi/
    # mount /dev/nbd0p2 /mnt/raspi/
    # mount /dev/nbd1p2 /mnt/image/
    # cp -a /mnt/image/* /mnt/raspi/

    Now, un-mount images and disconnect nbd devices

    # umount /mnt/image/
    # umount /mnt/raspi/
    # qemu-nbd --disconnect /dev/nbd0
    # qemu-nbd --disconnect /dev/nbd1

    Lastly, boot this image to verify it runs

    # qemu-system-arm -kernel /path/to/raspi-kernel -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 console=ttyAMA0" -hda /path/to/qemu_image/gentoo-raspi.realsize8G.card.img

    All of the above worked for me, so I’m flashing my SDHC now and will test it on my actual raspberry.

    # dd if=gentoo-raspi.realsize8G.card.img of=/dev/sdc

    1. After further investigation, I was able to conclude that the difficulty I had with “make menuconfig” (file in wrong format errors) was in fact a cross-compiling problem. This surprised me because I was not trying to cross-compile. I discovered that although I had ensured (by commenting it out) that distcc was not available in FEATURES in my make.conf, I needed to do more to ensure make (which seems to invoke distcc anyway) could not distribute jobs to my desktop distcc server. I did this by removing all entries but “127.0.0.1” from /etc/distcc/hosts … then, make uses only the native armv6j-hardfloat-linux-gnueabi-gcc compiler to build its object files, and the linker is happy with this.

      I also noted that the gentoo raspberrypi wiki now recommends using the defconfig that gentoo distributes with raspberrypi-sources now — so I did that.

      Bottom line: I successfully validated your basic method, with some minor modifications, as noted above.

      Here’s a couple other observations:
      (1) the workstation on which I installed qemu has an Athlon 64 3200+ cup, which I’m very happy with considering it is 8 years old, but it does not support hardware virtualization (AMD-V). Your procedure invokes qemu-system-arm with 256M of virtual RAM (which is half of what I have on my actual raspberrypi) — I tried changing that to 512M, but it would not run. Consequently, my qemu-system-arm virtual raspi was actually SLOWER than my actual raspberrypi.

      (2) in parallel, I also configured a gentoo system for my raspberrypi using the updated instructions on the gentoo wiki ( http://wiki.gentoo.org/wiki/Raspberry_Pi ). This method employs the desktop workstation’s cpu directly, to cross-compile the kernel, which you then copy to the boot partition of the SDHC card. Running in parallel, the kernel compilation took 1/3 the time that the qemu-system-arm system took to compile its kernel.

      (3) out of all of this, the piece most valuable to me has been learning from you about qemu-nbd, which I can now use to mount the filesystems in the partitions that are otherwise hidden to me inside image files.

      (4) I’ve found that once I’ve formatted an SDHC card properly, it’s often quicker/easier to use (3) above and copy files to the SDHC than to completely re-flash it. This way, I can also use one image (say 4G or 8G) as a baseline for a much larger card (say 32G).

      1. Hi Joe,

        to (1):
        For ARM, it doesn’t matter if your CPU supports AMD-V or not. AMD-V or Intel-VT may only be used, when virtualizing the same architecture as the Host system. In case of AMD-V or Intel-VT this is x86 or amd64. ARM is completely virtualized in software. That’s why it is so slow.

        According to this article, versatilepb does not support more than 256MiB of RAM. Do not try to use more than 256 MB of RAM, the value is hard-coded in and QEMU will not work correctly.

        (2):
        Well, that’s true. Cross-Compiling is much faster than compiling on the raspberry or using qemu-arm. But distcc enormously speeds up compiling on raspberry.

        (3):
        qemu-nbd is a very nice tool. But always keep in mind to use the -n flag (no cache). I already had some ugly crashes without using -n. And do not touch the image when it is mounted.

        (4):
        That’s why I provided also a .tar.gz archive πŸ˜‰

        Thank you for your constructive suggestions and have a lot of fun with your Raspberry Pi! If you have further questions, do not hesitate to contact me πŸ™‚

  7. Hello
    I am seeing that all the tutorials of qemu and raspberry pi point to 256MB of RAM. I tried with 512MB but the image doesn’t start, do i need to build a new kernel?

  8. Hello, i dont know if i have to ssh on my rasp.
    I need the login details on the Raspberry-Gentoo-6GiB-Image-20130816.img.gz.
    I have to do $ openssl passwd -1 raspi?
    Thank You!

    1. Best practice is to do openssl passwd -1 on some machine and replace the hash of the root entry of /etc/shadow of the raspi image.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.