Linux Format LXF0165 Raspberry Pi Tutorial : Supplementary Notes
================================================================

These notes supplement the magazine article.

Commands beginning with '#' require root privileges (either log
in as root or use 'sudo'). Commands beginning with '$' assume
an unprivileged user.

Scripts should be pasted verbatim into a file and chmod +x to
make it executable.

This file is formatted with markdown syntax [viewer](http://showdown.im)  

1. Prep
-------

    # pacman -Syu
    # pacman -S base-devel python2 git parted dosfstools

2. Make root filesystem in a subdirectory
-----------------------------------------

### 2.1 Package Baseline

    $ pacman -Sg base | awk '{print $2}' | grep -v "^\(linux\|kernel\)" | tr '\n' ' ' > base_packages
    $ sed -i -e 's/$/linux-raspberrypi linux-headers-raspberrypi raspberrypi-firmware/' base_packages

### 2.1 Remove unwanted packages

    $ sed -i -e "s/\bxfsprogs\b//" \
         -e "s/\bwpa_supplicant\b//" \
         -e "s/\breiserfsprogs\b//" \
         -e "s/\bjfsutils\b//" \
         -e "s/\blvm2\b//" base_packages 

### 2.2. Make image

    # mkarchroot archroot $(cat base_packages)

#### 2.2.1 Issue with mkarchroot

There is a line in mkarchroot which tries to set up the mirrorlist 
inside the new archroot. It doesn't work on arm due to the arm 
repos having a different directory structure to x86. If you 
encounter this problem then here is a patch to make it work:

    --- /usr/sbin/mkarchroot	2012-07-21 18:08:16.000000000 +0100
    +++ mkarchroot	2012-10-02 11:17:48.496579764 +0100
    @@ -196,7 +196,7 @@
     	cache_dirs=(${cache_dir})
     fi
     
    -host_mirror=$(pacman -Sddp extra/devtools 2>/dev/null | sed -E 's#(.*/)extra/os/.*#\1$repo/os/$arch#')
    +host_mirror=$(pacman -Sddp extra/devtools 2>/dev/null | sed -E -e 's#(.*/)extra/os/.*#\1$repo/os/$arch#' -e 's#(.*/)extra/.*#\1$repo#')
     if echo "${host_mirror}" | grep -q 'file://'; then
     	host_mirror_path=$(echo "${host_mirror}" | sed -E 's#file://(/.*)/\$repo/os/\$arch#\1#g')
     fi
    
Save that as "mkarchroot_mirrorlist.patch", then:

    $ cp /usr/bin/mkarchroot .
    $ patch < mkarchroot_mirrorlist.patch

### 2.3. Mount Image Script

    #!/bin/bash
    mkdir -p $1/{dev/pts,proc}
    mount proc -t proc $1/proc
    mount devpts -t devpts $1/dev/pts
    chroot $1 /usr/bin/env -i TERM="$TERM" /bin/bash --login
    umount $1/{dev/pts,proc}

3. Make Image File
------------------

Convert the archroot directory tree into an image file

    # modprobe loop
    $ truncate -s 2G myimage
    $ device=$(losetup -f) 
    # losetup $device myimage
    # parted -s $device mktable msdos
    # parted -s $device unit s mkpart primary fat32 8192 90111
    # parted $device unit s mkpart primary ext2 90112 3670015
    # parted $device unit s mkpart primary linux-swap 3670016 4194303
    # parted -s $device unit s print
    # losetup -d $device
    $ device=$(losetup -f) 
    # losetup -P $device myimage
    # mkfs.vfat -I -F 16 -n boot -s 16 -v ${device}p1 | grep "FAT size"
    # mkfs.vfat -I -F 16 -n boot -s 16 -R 8128 -v ${device}p1
    # mkfs.ext4 -O ^has_journal -L root  ${device}p2

Now copy archroot onto the image

    # mount ${device}p2 /mnt
    # mkdir /mnt/boot
    # mount ${device}p1 /mnt/boot
    # (cd archroot ; cp -a * /mnt)
    # umount /mnt/boot /mnt

Put image on SD card

    # dd if=myimage of=/dev/mmcblk0 bs=4M

4. Cross Compiler
-----------------

The cross compiler toolchain is arm-linux-gnueabi.

### 4.1 Install

    # pacman -S yaourt
    # yaourt -S arm-linux-gnueabi-gcc

### 4.2 Test

Create file "hello.c"

    #include <stdio.h>
    int main ()
    {
      printf("Hello, World!\n");
      return 0;
    }

Compile for ARM:

    $ arm-linux-gnueabi-gcc -o hello hello.c
    $ file hello
    hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.27, not stripped

5. Kernel Build
---------------

### 5.1 Native (on the Pi) Compiling

    $ git clone --depth 1 git://github.com/raspberrypi/linux.git
    $ cd linux
    $ zcat /proc/config.gz > .config
    $ make menuconfig -k
    $ make -k
    $ make -k modules_install

**Warning:** expect a native compile to take ten hours!

### 5.2 Cross Compiling 

This requires the arm-linux-gnueabi toolchain to be in place.

    $ git clone --depth 1 git://github.com/raspberrypi/linux.git
    $ cd linux
    $ ssh root@alarmpi zcat /proc/config.gz > .config
    $ make -j 8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig -k
    $ make -j 8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -k
    $ mkdir -p modules
    $ make -j 8 -k ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules_install INSTALL_MOD_PATH=modules

6. Emulator
-----------

### 6.1 QEMU Kernel

    $ mkdir kernel-qemu
    $ cd kernel-qemu
    $ git clone --depth 1 git://github.com/raspberrypi/linux.git
    $ wget http://xecdesign.com/downloads/linux-qemu/linux-arm.patch
    $ patch -p1 -d linux/ < linux-arm.patch
    $ cd linux
    $ make ARCH=arm versatile_defconfig
    $ cat >> .config << EOF
    CONFIG_CROSS_COMPILE="$(which arm-linux-gnueabi-gcc | sed "s/-gcc/-/")"
    CONFIG_CPU_V6=y
    CONFIG_ARM_ERRATA_411920=y
    CONFIG_ARM_ERRATA_364296=y
    CONFIG_AEABI=y
    CONFIG_OABI_COMPAT=y
    CONFIG_PCI=y
    CONFIG_SCSI=y
    CONFIG_SCSI_SYM53C8XX_2=y
    CONFIG_BLK_DEV_SD=y
    CONFIG_BLK_DEV_SR=y
    CONFIG_DEVTMPFS=y
    CONFIG_DEVTMPFS_MOUNT=y
    CONFIG_TMPFS=y
    CONFIG_INPUT_EVDEV=y
    CONFIG_EXT4_FS=y
    CONFIG_FONT_8x16=y
    CONFIG_LOGO=y
    EOF
    $ make -j 8 -k ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- menuconfig
    $ make -j 8 -k ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
    $ cd ..
    $ cp linux/arch/arm/boot/zImage kernel-qemu

### 6.2 Running

    $ qemu-system-arm -machine versatilepb -cpu arm1176 -m 256  \
                -no-reboot -serial stdio -kernel kernel-qemu \
                -append "root=/dev/sda2 panic=1" -hda myimage


7. Transparent Emulation (binfmt-misc)
--------------------------------------

### 7.1 Static QEMU

Download the package for QEMU from SVN (or use ABS)

    $ svn export svn://svn.archlinux.org/packages/qemu

Use a modified PKGBUILD to remove dependencies and perform static linking:

    # $Id: PKGBUILD 166385 2012-09-07 12:55:19Z tpowa $
    # Maintainer: Tobias Powalowski <tpowa@archlinux.org>
    pkgname=qemu
    pkgver=1.2.0
    pkgrel=1
    pkgdesc="A generic and open source processor emulator which achieves a good emulation speed by using dynamic translation."
    arch=('i686' 'x86_64')
    license=('GPL2' 'LGPL2.1')
    url="http://wiki.qemu.org/Index.html"
    makedepends=('texi2html' 'perl' 'python2')
    depends=('glib2')
    backup=('etc/qemu/target-x86_64.conf')
    source=(http://wiki.qemu.org/download/${pkgname}-${pkgver}.tar.bz2)
    options=(!strip)
    
    build()
    {
      cd "${srcdir}/${pkgname}-${pkgver}"
      sed -i -e 's/lib64/lib/g' x86_64.ld
      ./configure --prefix=/usr --sysconfdir=/etc \
                  --python=/usr/bin/python2 \
                  --disable-kvm \
                  --target-list=arm-linux-user \
                  --static
                  make
    }
    
    package() {
      cd "${srcdir}/${pkgname}-${pkgver}"
      make DESTDIR="${pkgdir}" libexecdir="/usr/lib/qemu" install
    }
    md5sums=('78eb1e984f4532aa9f2bdd3c127b5b61')
    

Copy the binary out

    $ cp pkg/usr/bin/qemu-arm /usr/bin/qemu-arm-static

### 7.2 Set up binfmt-misc

    # mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
    # echo ':arm: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:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register

### 7.3 Cross makepkg

This allows you to run makepkg on x86 to create a filesystem with arm packages in it.

#### 7.3.1 Patch makepkg

First, copy and patch 'mkarchroot' so it installs the static QEMU in any chroot it creates:

Here is thee patch:

    --- /usr/sbin/mkarchroot	2012-07-20 22:32:33.000000000 +0100
    +++ mkarchroot	2012-10-02 15:17:15.000000000 +0100
    @@ -190,6 +190,10 @@
     
     [[ -z $working_dir ]] && die 'Please specify a working directory.'
     
    +# Put Static QEMU into the chroot
    +mkdir -p "${working_dir}/usr/bin"
    +cp /usr/bin/qemu-arm-static "${working_dir}/usr/bin/qemu-arm-static"
    +
     if [[ -z $cache_dir ]]; then
     	cache_dirs=($(pacman -v $cache_conf 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g'))
     else
    
Save as "mkarchroot_qemu.patch" and then:

    $ cp /usr/sbin/mkarchroot .
    $ patch < mkarchroot_qemu.patch

(you might also want to apply previous patch mkarchroot_mirrorlist.patch described above)

Thereafter, use local mkarchroot.


#### 7.3.2 Set up Pacman

You need to configure the package manager so it downloads ARM packages. There are two files, the
 first is the mirror list for the package manager. Create this file as "arm_mirrorlist":

    ## Geo-IP based mirror selection and load balancing
    Server = http://mirror.archlinuxarm.org/arm/$repo

(or copy one from your running Raspberry Pi)

The second file is pacman.conf. You can download and create a customised
version as follows:

    $ curl https://projects.archlinux.org/svntogit/packages.git/plain/trunk/pacman.conf?h=packages/pacman > arm_pacman.conf
    $ sed -i -e "s/\Architecture = auto/Architecture = "arm"/g" \
             -e "s@/etc/pacman.d/mirrorlist@arm_mirrorlist@g" \
             -e 's/^SigLevel/#SigLevel/' \
             -e '/^#SigLevel = Optional TrustedOnly/a\SigLevel = Never' \
             -e 's/^CheckSpace/#CheckSpace/' arm_pacman.conf
    $ echo -e "[alarm]\nInclude = arm_mirrorlist" >> arm_pacman.conf

#### 7.3.3 Usage

    # ./mkarchroot -C arm_pacman.conf archroot $(cat base_packages)

8. Distributed Compiling
------------------------

See <http://archlinuxarm.org/developers/distributed-compiling>

### 8.1 ARM Setup (client)

    # pacman -S distcc

In /etc/makepkg.conf, change BUILDENV to un-negate the distcc option. Also
set up the host that will be used to compile (your x86 box). Set up the
make flags according to the server's CPUs:

    BUILDENV=(fakeroot distcc color !ccache)
    DISTCC_HOSTS="10.0.200.12"
    MAKEFLAGS="-j8"

### 8.2 X86 Setup (server)

   # pacman -S distcc

Set up etc/conf.d/distccd, change DISTCC_ARGS to reflect the hosts or network you're allowing to connect:

    DISTCC_ARGS="--user nobody --allow 10.0.0.0/8"

Permit access in /etc/hosts.allow:

   # echo "distcc:ALL" >> /etc/hosts.allow

Add "distccd'' to the DAEMONS line in /etc/rc.conf to start distccd on boot.

Or manually start it with 

    # /etc/rc.d/distccd start

Run the below script to set up a arm-linux-gnueabi containing binaries:

    #!/bin/bash
    
    TOOLCHAINS=(arm-linux-gnueabi)
    
    BINDIRS=(/usr/bin)
    
    for tc in ${TOOLCHAINS[@]}
    do
    
        for i in $(find ${BINDIRS[@]} -name "$tc*")
        do
            d=$(dirname $i)/$tc
            f=$(basename $i)
        
            mkdir -p $d
            ln -s $i $d/${f#${tc}-}
        done
    
    done
    
Add a custom path to the rc file so distccd finds that path:

    # sed -i -e '/^PID=/iPATH=/usr/bin/arm-linux-gnueabi:\$PATH' /etc/rc.d/distcc

### 8.3 Usage

Running a makepkg job on the arm box should automatically delegate compiling to the
x86 box.

    # makepkg -s


(end)
