====== Raspberry Pi Gentoo ====== ---- dataentry project ---- Name_ : Raspberry Pi Gentoo Tags_tags : linux, gentoo, raspberry pi Description_ : A Gentoo distribution for the Raspberry Pi $25 computer. Last Update_dt : 2012-02-04 ---- ===== Description ===== This project is an attempt to build and prepare a minimal [[http://gentoo.org|Gentoo Linux]] distribution for the [[http://raspberrypi.org|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 cd ${RASPIGEN} # 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 make # 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 #include 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. ==== binfmt_misc ==== 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 [[http://www.gentoo.org/main/en/mirrors2.xml|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 env-update 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" CXXFLAGS="${CFLAGS}" CHOST="armv6zk-hardfloat-linux-gnueabi" ==== 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 env-update 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 https://raw.github.com/cvpcs/gentoo-overlay/master/profiles/repo.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 make # 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 [[http://elinux.org/RPi_VerifiedPeripherals#SD_cards|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). === Geometry === 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 === Partitions === 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 information. 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. === Filesystems === 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 \ "${RASPIGEN}"/root/boot/kernel.img 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 $6$wwRnB8p6$5a1hOb.b75EwAnv2TbQBKLcjzxA15gcF53Ul2RYOVySZodvgjR0AAiIfp1VUE.gbQXEYo56O4vFkFJ8Ownb6A0 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 ===== References ===== * [[http://www.cnx-software.com/2012/01/22/linux-kernel-3-1-9-for-raspberry-pi-released/|Linux Kernel 3.1.9 for Raspberry Pi Released & Build Instructions]] - Kernel 3.1.9 compilation * [[http://www.gentoo.org/proj/en/base/embedded/cross-development.xml|Gentoo Cross-development]] * [[http://www.gentoo.org/doc/en/change-chost.xml|Gentoo Changing CHOST]] * [[http://dev.gentoo.org/~armin76/arm/chost.xml|Gento ARM CHOST values]] * [[http://www.gentoo.org/doc/en/handbook/handbook-arm.xml|Gentoo Handbook for ARM]] * [[http://elinux.org/RPi_Advanced_Setup|RPi Advanced Setup]] * [[http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html|GCC ARM options]] * [[http://www.kernel.org/doc/Documentation/binfmt_misc.txt|binfmt_misc]]