Novena/Embedian Build

From Studio Kousagi Wiki
Jump to: navigation, search

NOTE: these instructions are in flux

How to use the embedian cross-compilation toolchain to generate binaries that will run on armhf hardware using a debian-based x86/amd64 build host.

These directions require a physical micro SD card; partitioning happens "in place" instead of using loop-mounted .img files.

These directions assume you basically know what you are doing; eg, be careful dd'ing directly to the micro SD card and that you don't accidentally dd to an important disk, resulting in a loss of all data.

Prepare Cross-Compile Toolchain on Build Host

You need to add the embedian repositories to your sources.list.

There aren't toolchain packages in (emdebian) wheezy yet, so if your build host is wheezy add (emdebian) squeeze to your /etc/apt/sources.list (don't replace any wheezy lines, just copy the wheezy deb line and replace "wheezy" with "squeeze"), then apt-get update. This shouldn't clobber your system too bad as the wheezy packages will almost always be prefered to squeeze packages. My sources.list on my (wheezy) build machine looked like this in January 2013:

# primary
deb     http://http.debian.net/debian/  wheezy  main  contrib
deb-src http://http.debian.net/debian/  wheezy  main  contrib

# security
deb     http://security.debian.org/  wheezy/updates  main contrib  
deb-src http://security.debian.org/  wheezy/updates  main contrib

# emdebian  
deb http://www.emdebian.org/debian/ wheezy main  
deb http://www.emdebian.org/debian/ sid main  
deb http://http.debian.net/debian/  squeeze main contrib 

IIRC the main toolchain package is gcc-4.7-arm-linux-gnueabi.

Also install (at least) these debian packages:

build-essential multistrap qemu-user-static gparted device-tree-compiler u-boot-tools bc

Note that 'gparted' is a GUI and will pull in X dependancies; if you build on a remote server you could do the partitioning steps on a different machine.

Check out these repositories from github:

The linux-stable git checkout could take ages (and is huge), so you might want to just grab a tarball of 3.7.4.

Build u-boot

Checkout the custom u-boot-imx6: https://github.com/sutajiokousagi/u-boot-imx6

As of Jan 2013, use ddrsetup branch (else *-staging?).

Enter top directory and build:

export CROSS_COMPILE=arm-linux-gnueabi-
make novena_config
make

Grab the resulting 'u-boot.imx' for later.


Compile the u-boot boot script

You need u-boot-tools for the next bit.

Grab boot.script from the meta-kosagi repo:

wget https://raw.github.com/sutajiokousagi/meta-kosagi/novena/recipes-bsp/u-boot/u-boot-imx/boot.script

Compile the boot script (careful, confusing file names!):

mkimage -A arm -O linux -a 0 -e 0 -T script -C none -n "Boot script" -d boot.script boot.scr

Grab the resulting boot.src file for later.

Build Kernel

Install whatever general build tools. Might in particular need 'lzop' for building uImages.

Grab linux-stable upstream: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

As of Jan 2013, testing with 3.8-rc (not linux-stable).

Copy in meta-kosagi/recipes-kernel/linux/linux-novena/defconfig as .config

Create this script as cross_build.sh; note the UIMAGE_LOADADDR=10008000 on penultimate line (i.mx6-specific?), and change "custom1" to whatever you want:

#!/usr/bin/env bash
export ARCH=arm
export DEB_HOST_ARCH=armhf
export CONCURRENCY_LEVEL=`grep -m1 cpu\ cores /proc/cpuinfo | cut -d : -f 2`
fakeroot make-kpkg --arch arm --cross-compile arm-linux-gnueabi- --initrd --append-to-version=-custom1 kernel_image kernel_headers
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- EXTRAVERSION=-custom1 UIMAGE_LOADADDR=10008000 uImage
cp arch/arm/boot/uImage uImage

If you are using a newer -stable kernel than the one use to generate the .config, the first compile will prompt you to select a whole boatload of NEW configuration options (new optional features in the kernel sources). If you run in to this, keep hitting enter to accept all the defaults.

Run the cross_build.sh script to build.

Grab the resulting uImage file and rename it uImage-novena.bin.

Build device tree file

You need the device-tree-compiler package for the next bit.

Grab novena.dts and imx6q.dtsi from the meta-kosagi repo:

meta-kosagi/recipes-kernel/linux/linux-novena/novena.dts
meta-kosagi/recipes-kernel/linux/linux-novena/imx6q.dtsi

Grab skelton.dtsi from the linux-stable sources (checked out previously):

linux-stable/arch/arm/boot/dts/skeleton.dtsi

Compile the device tree file:

dtc -I dts -O dtb -R 8 -p 0x3000 -o uImage-novena.dtb novena.dts

Grab the resulting uImage-novena.dtb file for later.

Build a Basic Debian armhf wheezy rootfs with multistrap and qemu

These are crude, manual, slow directions, included for completeness. Pretty much nobody should do things this way, any targeted application of the novena board would have images generated by a script or better build process. Perhaps even the Debian installer will be sufficient.

You might also be able to use a generic debian wheezy armhf rootfs tarball if you have one sitting around.

We'll use multistrap, configure the packages with qemu, then edit the configuration by hand. This follows http://wiki.debian.org/Multistrap#Steps_for_Squeeze_and_later.

Install the qemu-user-static and multistrap packages.

In a new directory, create a multistrap configuration file like the below, called novena.conf. Add any extra packages you want to the long list:

[General]
arch=armhf
cleanup=true
noauth=false
aptsources=Debian
bootstrap=Debian

[Debian]
packages=file i2c-tools screen build-essential base-files openssh-server wget iproute net-tools hostname udev isc-dhcp-client parted dosfstools apt iputils-ping dialog iptables less traceroute apt-utils dnsutils lsof vim-tiny sudo locales ethtool pciutils git-core ifupdown manpages man-db firmware-linux-free kmod iw wireless-tools wpasupplicant hostapd rfkill  

keyring=debian-archive-keyring
suite=wheezy
source=http://http.debian.net/debian/

To build the first (unconfigured) stage of the rootfs, run:

sudo multistrap -f novena.conf -d armhf

Rename the resulting 'armhf' directory to 'rootfs', and tar it up as a backup copy. Then make the following basic changes *AS ROOT* in the rootfs directory (you don't need to chroot) before configuring the packages. These are just the minimal requirements; package configuration and udev will help, but this won't be a polished OS:

# sudo-s omitted
echo "novena" > etc/hostname
touch etc/fstab
touch etc/resolv.conf
mkdir dev/pts
mknod dev/console c 5 1
mknod dev/random c 1 8
mknod dev/urandom c 1 9
mknod dev/null c 1 3
mknod dev/ptmx c 5 2

Copy the build host's /usr/bin/qemu-arm-static to rootfs/usr/bin/qemu-arm-static.

Create a config.sh script in top level of the rootfs:

# config.sh script
export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
export LC_ALL=C LANGUAGE=C LANG=C
/var/lib/dpkg/info/dash.preinst install
dpkg --configure -a
mount proc -t proc /proc
dpkg --configure -a
umount /proc

Run it:

sudo chroot rootfs /config.sh

Remove unnecessary files:

sudo rm /usr/bin/qemu-arm-static
sudo rm /config.sh

Add a minimal rootfs/etc/hosts:

127.0.0.1       localhost.localdomain localhost novena
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Add a crude rootfs/etc/network/interfaces:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
    hwaddress ether 00:11:22:33:44:55

Edit rootfs/etc/inittab and allow logins on serial console (modify the similar tty1 line):

1:2345:respawn:/sbin/getty 115200 ttymxc1

Edit rootfs/etc/shadow and remove the '*' character after root (to set a null password).

WARNING: only root will be able to login, with blank password!

Ensure that all files in the rootfs are owned by root:root, not a user:

sudo chown -R root:root rootfs/*

Then double check the "tweaks" below.

rootfs Tweaks (even for recycled images)

Set some serial login on ttymxc1 (edit etc/inittab):

1:2345:respawn:/sbin/getty 115200 ttymxc1

(optional) Set MAC address in etc/network/interfaces to:

hwaddress 00:11:22:33:44:55

Partition a blank SD card

Use the gparted GUI.

Delete all existing partitions on the micro SD card.

Create a ~32MB FAT32 partition labeled 'boot' with at least 512KB of padding in front of it (by default there is 1MB of padding), call it 'boot'.

Create a ~500MB ext3 partition.

Commit changes.


Assemble Everything

Copy the u-boot.imx file built above to the padded space at the begining of the card:

$ dd if=u-boot.imx of=/dev/sdb bs=512 conv=notrunc seek=2

Mount the FAT boot partition to /mnt.

Copy boot.src and uImage-novena.dtb over to /mnt, keeping their names. Copy the uImage kernel file to /mnt/uImage-novena.bin.

unmount the FAT boot patition and mount the ext partition to /mnt.

Delete any old rootfs files (if you didn't just re-partition the disk), and copy over the whole rootfs:

$ sudo rsync -arv ./rootfs/ /mnt/

unmount the disk, it's ready to go!

Result!

root@novena:~# uname -a
Linux novena 3.8.0-custom1 #2 SMP Tue Jan 22 04:20:12 UTC 2013 armv7l GNU/Linux
root@novena:~# cat /etc/os-release     
PRETTY_NAME="Debian GNU/Linux 7.0 (wheezy)"
NAME="Debian GNU/Linux"
VERSION_ID="7.0"
VERSION="7.0 (wheezy)"
ID=debian
ANSI_COLOR="1;31"
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support/"
BUG_REPORT_URL="http://bugs.debian.org/"

reboot time: about 13 seconds shutdown time: 3-4 seconds

Hacks

To try and steal a u-boot header from existing disk:

dd if=/dev/sdb of=snag.bin bs=512 skip=2 count=500

and write:

dd if=snag.bin of=/dev/sdb bs=512 seek=2 count=500

If a MAC address isn't assigned for eth0 at boot (eg, if ifupdown package isn't installed), you will get:

root@novena:~# ifconfig eth0 up
SIOCSIFFLAGS: Cannot assign requested address

Workaround:

ifconfig eth0 hw ether 00:11:22:33:44:55
ifconfig eth0 up

TODO

  • add i2c thing to rc.local: "i2cset -f -y 1 0x08 0x66 0x48 || true"