Novena/Embedian Build
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.
Contents
- 1 Prepare Cross-Compile Toolchain on Build Host
- 2 Build u-boot
- 3 Compile the u-boot boot script
- 4 Build Kernel
- 5 Build device tree file
- 6 Build a Basic Debian armhf wheezy rootfs with multistrap and qemu
- 7 rootfs Tweaks (even for recycled images)
- 8 Partition a blank SD card
- 9 Assemble Everything
- 10 Result!
- 11 Hacks
- 12 TODO
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:
- meta-kosagi from github/sutajiokousagi (novena branch): https://github.com/sutajiokousagi/meta-kosagi
- u-boot-imx6 from github/sutajiokousagi (ddrsetup branch): https://github.com/sutajiokousagi/u-boot-imx6
- linux-stable from kernel.org (eg, 3.7.4 tag): https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
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"