Search:  
Gentoo Wiki

Technologic_Systems_TS-72xx

This article is still a Stub. You can help Gentoo-Wiki by expanding it.

This article is part of the Hardware series.
Laptops TV Tuner Cards Wireless Servers Storage Other Hardware Motherboards Related
Warning: THIS PAGE IS UNDER CONSTRUCTION

Image:EmbeddedARM.jpg

Contents

Introduction

Jump here if you just want to download the binaries.

The purpose of this HowTo is to port Embedded Gentoo [1] to the TS72xx series of ARM (Wikipedia:ARM Architecture) single board computers (SBC) [2] from Technologic Systems.The procedure loosely follows the 'from scratch' method of Mike Frysinger (vapier) [3] but with conserably more detail. The 'Linux From Scratch' [4] documentation was loosely referenced as well. Although this document concentrates on installation specifically for the TS72xx series boards with maverick-crunch (Wikipedia:MaverickCrunch) and the GNU-EABI (Wikipedia:EABI), it could potentially also be generalized to any other new architecture if the arm/maverick/eabi-specific parts are omitted.

If you are unfamiliar with the ARM EABI, then you might want to read the following first - [5], [6].Also, for detail about the TS72xx hardware itself, and the relevent ARM / Cirrus documentation, see [7], [8], [9].

Overview

What this HowTo Covers

This how-to will address the following topics:

What this HowTo Does Not Cover

Here are some things that this article does not cover

Each of the above (aside from the GCC business) will be part of my project for the next couple of weeks. I probably will not have this system finely tuned for slightly longer, but I expect to have a proof of concept done by then. Aside from the maverick and ts72xx ebuild overlays, I have not made any significant code / patch changes except to make it 'just work'. All patches can be viewed if you download the ebuilds in the overlays that are mentioned below.

What Needs Touching-Up

The 'full distro' in this case is basically equivalent to the Debian-256 distribution from Technologic Systems. This filesystem is ~ 400MB and is therefore not suitable for on-board flash. If this filesystem is to be used, then it should be installed on a USB storage device or SD-card, as the case may be. Note that this filesystem is only so large because it includes all headers, man pages, a full native toolchain, and so on. I will address stripping this filesystem at a later date.

Typically, 'full distros' do not attempt to reduce filesystem size. Therefore, a full GNU userland is created. Common system applications are not replaced by the BusyBox (Wikipedia:BusyBox) counterparts. Similarly, uClibc (Wikipedia:uClibc) is not used to decrease the size of the system C library, but rather the full Glibc. Furthermore, packages installed to this root filesystem will contain includes, man pages, and other such clutter, whereby a 'tiny distro' will usually attempt to install only the shared libraries, binaries, and minimal configuration files for a runnable system.

Assumptions

This how-to assumes that you have

Creating the Cross-Toolchain

Code: Export necessary environment variables
export MYHOST=armv4tl-maverick-linux-gnueabi
export SRVR="http://vaiprime.visibleassets.com/~cfriedt"

Below we will emerge our cross-toolchain. It is absolutely imperative that you do not forget the -D__MAVERICK__ CFLAG when creating the cross-glibc. Due to the way the patch is set-up, if this is not defined for glibc, then none of the glibc maverick-crunch features will be used! Unfortunately, portage does not as of yet have a built-in method of organizing per-package environment variables (i.e. CFLAGS) for automated installation. That means every time you re-build glibc you must remember to define __MAVERICK__! Otherwise your glibc will provide a completely incorrect float/double math library with unexpected results (well... any float op will return 0). I believe Ned Ludd had devised a separate env.d subsystem for automating environment variables (i.e. CFLAGS,CXXFLAGS,etc) for portage, but it is not yet integrated into the main portage package.

I modified portage to recognize the GCC_EXTRA_ECONF environment variable. Why? Well, if you set --with-cpu as an option, expecting GCC to target a specific processor by default, then glibc infers that it should optimize the code for that CPU as well. If you are creating a cross-toolchain, then that is obviously impossible, because GCC would optimize code for, say, arm920t, while glibc (which has i686 compatible objects) would refuse and say 'that target is not supported in this architecture', or something of that sort.

Code: Crossdev
CROSSDEV_OVERLAY="/usr/local/portage/crossdev_overlay"
MAVERICK_OVERLAY="/usr/local/portage/maverick_overlay"
OVERLAY_SRC="${SRVR}/overlays"

rm -Rf ${MAVERICK_OVERLAY} &&
mkdir -p ${MAVERICK_OVERLAY} &&
wget -O - ${OVERLAY_SRC}/maverick.tar.bz2 | \
tar xpjf - -C ${MAVERICK_OVERLAY}

unset PKGDIR

# this is necessary for recognizing GCC_EXTRA_ECONF
PORTDIR_OVERLAY="${MAVERICK_OVERLAY}" \
emerge -v1 =sys-devel/crossdev-0.9.18-r7

# emerge the cross-toolchain
PORTDIR_OVERLAY="${CROSSDEV_OVERLAY} ${MAVERICK_OVERLAY}" \
CFLAGS="-O2 -pipe -D__MAVERICK__" \
GCC_EXTRA_ECONF="--with-cpu=arm920t --with-tune=arm920t \
--with-fpu=maverick --with-float-abi=softfp \
--enable-__cxa_atexit --with-system-zlib \
--without-included-gettext --enable-threads=posix \
--enable-clocale=gnu" \
USE="-gcj -gtk -fortran -mudflap" \
FEATURES="buildpkg" \
crossdev -S --ex-gdb \
--l 2.5-r4 --g 4.1.2 --b 2.17-r1 \
${MYHOST}

Because of the 'buildpkg' feature, binary packages for the cross-toolchain will have already been made and stored in ${PKGDIR}/cross/${MYHOST}. There you will find a binary package for gcc, glibc, linux-headers, binutils, and gdb. These binary packages form a portable cross-toolchain.

Xmerge: The Emerge Wrapper

Create /usr/sbin/xmerge [10]

File: /usr/sbin/xmerge
#!/bin/sh
export CBUILD=$(portageq envvar CHOST)
export PORTAGE_CONFIGROOT=${SYSROOT}
if [ "$1" = "--root" ] ; then
	export ROOT=$2
	shift 2
else
	export ROOT=${SYSROOT}
fi
exec emerge "$@" 

chmod +x /usr/sbin/xmerge

Populating the ${SYSROOT}

Portage Configuration

Export Environment Variables

Code: Environment Variables Used by Xmerge / Emerge
export SYSROOT=/usr/${MYHOST}
export PKGDIR=${SYSROOT}/var/tmp/binpkgs

For each ofthe packages installed below, you will find a precompiled binary tbz2 package in ${PKGDIR}. These binary packages will form your binary package repository.

Set Up the PORTDIR_OVERLAY

Code: Prepare the PORTDIR_OVERLAY
PORTDIR_OLAY=${SYSROOT}/usr/local/portage

export PORTDIR_OVERLAY="${PORTDIR_OLAY}/ts72xx_overlay \
${PORTDIR_OLAY}/maverick_overlay"

mkdir -p ${PORTDIR_OVERLAY}

wget -O - ${SRVR}/overlays/ts72xx.tar.bz2 | \
tar xpjf - -C ${PORTDIR_OLAY}/ts72xx_overlay

wget -O - ${SRVR}/overlays/maverick.tar.bz2 | \
tar xpjf - -C ${PORTDIR_OLAY}/maverick_overlay

Create ${SYSROOT}/etc/make.conf

Note: I guess I found a 'bug' in gcc. The problem is that in the INSTALL documentation, it says that if you configure gcc with --with-cpu=x,--with-fpu=y,--with-float-abi=z, then it will produce binaries using that combination by default. This is not the case as I discovered. After running the same lame mp3 encoding test that Martin Guy used, the time taken was equivalent to that of soft-float. If i recompiled lame with the -m options that I thought were set by default, then gcc produced the expected maverick-enabled code. Any idea why that would be the case, gcc people?

Maybe this is actually a bug in binutils. Who knows, but until its fixed, you need to apply CFLAGS as shown below.

mkdir -p ${SYSROOT}/etc/portage

File: Edit ${SYSROOT}/etc/make.conf
ACCEPT_KEYWORDS="arm"
ARCH=arm
CHOST="armv4tl-maverick-linux-gnueabi"
# for some reason we need to include the -m options that GCC was supposed to have enabled by default
# -D__MAVERICK__ is required for compiling glibc, no others, but it's easier to have here
CFLAGS="-O2 -pipe -mcpu=arm920t -mtune=arm920t -mfpu=maverick -mfoat-abi=softfp -D__MAVERICK__"
CXXFLAGS="${CFLAGS}"
MAKEOPTS="-j2"
EMERGE_DEFAULT_OPTS="-k"
VIDEO_CARDS="none"
LCD_DEVICES=""
ALSA_PCM_PLUGINS=""
FEATURES="buildpkg -ccache -confcache"
PORTDIR_OVERLAY="/usr/local/portage/ts72xx_overlay /usr/local/portage/maverick_overlay"
PKGDIR=/var/tmp/binpkgs
# Note! If internationalization is required, set nls and unicode below
USE="-acl berkdb -bitmap-fonts bzip2 -cli -cracklib crypt -cups fortran gcj gmp -iconv -ipv6 \
-isdnlog -midi mpfr -mudflap ncurses -nls nptl nptlonly -openmp -pam pcre perl -ppds -pppd \
python readline -reflection -session slang -spl ssl tcpd -truetype-fonts -type1-fonts -unicode \
-xorg zlib"

Edit Locale Information (Optional)

If you need to generate certain locale data, then add locale codes to the file below.

File: Edit ${SYSROOT}/etc/locale.gen
en_US ISO-8859-1
en_US.UTF-8 UTF-8
en_CA ISO-8859-1
en_CA.UTF-8 UTF-8
de_DE ISO-8859-1
de_DE@euro ISO-8859-15
fr_FR ISO-8859-1
fr_FR@euro ISO-8859-15
fr_CA ISO-8859-1
fr_CA UTF-8

Edit Package-Specific Use Flags / Keywords

I have marked several of the core system applications to be made static. This prevents important programs from bailing out in case a shared library is accidentally deleted. The static variable should not be overly used since the size of statically compiled binaries are much larger.

File: Edit ${SYSROOT}/etc/portage/package.use
net-wireless/wireless-tools multicall
net-misc/iputils static
sys-devel/patch static
sys-apps/grep static
sys-apps/net-tools static
sys-apps/baselayout static unicode
sys-apps/debianutils static
app-arch/tar static
app-arch/bzip2 static
app-arch/gzip static
net-misc/rsync static
net-misc/wget static
sys-apps/coreutils static
sys-devel/make static
sys-apps/diffutils static
sys-fs/e2fsprogs static
sys-apps/texinfo static
sys-apps/findutils static
sys-apps/sed static
sys-apps/sysvinit static
net-firewall/iptables static
net-misc/openvpn ssl threads
sys-apps/busybox savedconfig static -debug -make-symlinks -pam
net-misc/dhcp static
app-admin/eselect bash-completion
### the packages below require a portage overlay & patches
# note: psmisc needs to be patched for cross-compiling (rpl_malloc)
=sys-process/psmisc-22.5-r2 gnu-malloc
=net-libs/libnfsidmap-0.19 gnu-malloc
# gcc needs the arm/sysv.S patch for @progbits
# also added externalize-jar patch
sys-devel/gcc fortran gcj -gtk -mudflap
File: Edit ${SYSROOT}/etc/portage/package.keywords
=sys-apps/busybox-1.8.2
=app-arch/fastjar-0.95
=net-wireless/wpa_supplicant-0.5.8
=net-misc/openvpn-2.1_rc7

Busybox Savedconfig

Code: Make a BusyBox Savedconfig File
mkdir -p ${SYSROOT}/etc/portage/savedconfig/sys-apps
wget -O ${SYSROOT}/etc/portage/savedconfig/sys-apps/busybox-1.8.2 \
${SRVR}/configs/busybox-1.8.2.config

Create make.profile and make.globals

Code: Make the make.profile Symlink and make.globals File
cd ${SYSROOT}/etc
cp /etc/make.globals .
ln -sf /usr/portage/profiles/default-linux/arm/2007.0 make.profile

Emerge System Packages

The following list of packages is not simply the 'system' group (omitting the compiler, libc, os-headers,and binutils). It is also a carefully tested list of packages that are known to cross-compile, which may on occasion require extra patching, as apparent in the ts72xx overlay.

On one hand that spares you, the builder, the time it takes to organize this ordering from scratch. On the other hand, it also means there are other 'system' packages that will not properly cross compile, such as perl. Those packages must go through the extremely slow process of native compilation later on.

I've taken the liberty to add a few extra programs that are not part of the 'system' group but useful nonetheless.

Code: Emerge the System Packages
PKGS="sys-libs/ncurses sys-libs/zlib sys-libs/db sys-apps/tcp-wrappers dev-libs/gmp sys-libs/com_err sys-devel/m4 sys-devel/gnuconfig sys-apps/sysvinit sys-devel/autoconf-wrapper sys-devel/automake-wrapper sys-apps/shadow sys-apps/sed dev-libs/popt sys-libs/timezone-data sys-apps/sandbox dev-libs/expat dev-libs/libevent =net-libs/libnfsidmap-0.19 sys-libs/ss sys-fs/e2fsprogs =net-fs/nfs-utils-1.1.0-r1 sys-apps/findutils virtual/libiconv dev-libs/libpcre sys-apps/grep sys-apps/net-tools sys-apps/kbd net-misc/iputils =sys-apps/busybox-1.8.2 sys-devel/patch sys-devel/flex sys-apps/gawk sys-apps/file sys-apps/which app-arch/fastjar net-misc/dhcpcd app-arch/gzip app-arch/bzip2 app-arch/cpio =app-arch/tar-1.18-r2 app-portage/portage-utils net-firewall/iptables sys-libs/readline sys-apps/texinfo app-shells/bash sys-apps/coreutils app-editors/nano virtual/init net-misc/rsync net-nds/portmap sys-process/procps =sys-process/psmisc-22.5-r2 sys-devel/bison sys-apps/less dev-libs/mpfr sys-apps/groff virtual/editor net-wireless/wireless-tools sys-apps/man sys-apps/util-linux sys-apps/man-pages sys-apps/diffutils =dev-lang/python-2.4.4-r6 dev-libs/openssl net-misc/openssh net-misc/wget net-wireless/wpa_supplicant dev-python/python-fchksum dev-python/pycrypto app-admin/python-updater sys-apps/portage dev-libs/libxml2 sys-devel/autoconf sys-devel/automake sys-devel/libtool sys-apps/debianutils sys-apps/mktemp sys-apps/baselayout sys-apps/module-init-tools sys-fs/udev =app-arch/fastjar-0.95 sys-devel/gcc-config sys-devel/binutils-config dev-libs/lzo net-misc/openvpn net-misc/ntp app-misc/screen app-editors/hexedit app-admin/eselect"

CFLAGS="-O2 -pipe" xmerge -av1 --nodeps $PKGS

xmerge -av1 --nodeps media-sound/lame

# for some reason make will not compile -O2 with maverick/eabi
CFLAGS="-pipe" xmerge -av1 --nodeps sys-devel/make

Package the Native Toolchain

It is VERY important that these packages should be emerged with the -B option. This option instructs emerge to create binary packages only and not to install anything to ${SYSROOT}. If the -B option is not passed then portions of the cross-toolchain could be overwritten, rendering it useless (namely the libc and os-headers).

If internationalization support is necessary, you should have added "nls" to USE in ${SYSROOT}/etc/make.conf, edited ${SYSROOT}/etc/locale.gen, and you should remove the LANG variable below.

Code: Package the Native Toolchain
USE="-gcj -fortran" \
EXTRA_ECONF="--enable-shared \
--with-system-zlib --without-included-gettext \
--enable-threads=posix --enable-clocale=gnu \
--with-tune=arm920t --enable-__cxa_atexit \
--with-fpu=maverick --with-float-abi=softfp \
--with-cpu=arm920t" \
xmerge --nodeps -avB1 =sys-devel/gcc-4.1.2

LANG="C" xmerge -avB1 --nodeps =sys-libs/glibc-2.5-r4

xmerge -avB1 =sys-devel/binutils-2.17-r1 \
sys-kernel/linux-headers sys-devel/gdb

Now, it's safe to say ROOT=${SYSROOT} etc-update

Preparing the System Configuration Files

Clock & Timezone Options

File: Edit ${SYSROOT}/etc/conf.d/clock
...
CLOCK="local"
...
TIMEZONE="Europe/Berlin" #or wherever you live
...
Code: Make the ${SYSROOT}/etc/localtime Symlink
cd ${SYSROOT}/etc
rm -f localtime 
ln -sf ../usr/share/zoneinfo/Europe/Berlin localtime

Local Filesystem Options

File: Edit ${SYSROOT}/etc/fstab (so that it looks exactly like this)
/dev/sda1       /               ext2            defaults         0 0

# NOTE: The next line is critical for boot!
proc            /proc           proc            defaults        0 0

# NOTE: The next line is critical for glibc/posix shared memory to work
shm             /dev/shm        tmpfs           nodev,nosuid,noexec     0 0

Assuming that you will be using a USB storage device for the root filesystem, then you can keep the ${SYSROOT}/etc/fstab exactly as shown above. However, if you are using a TS7300, then you might prefer an SD card. In that case, change /dev/sda1 to /dev/mmcblk0p1. The TS7300 has a slightly different boot scheme than the TS72xx series of devices, and they might not be 100% covered by this HowTo as of yet.

Add ttyAM0 to Relevent Files

Code: Edit ${SYSROOT}/etc/inittab
...
# TERMINALS
c1:12345:respawn:/sbin/agetty 38400 tty1 linux
#c2:2345:respawn:/sbin/agetty 38400 tty2 linux
#c3:2345:respawn:/sbin/agetty 38400 tty3 linux
#c4:2345:respawn:/sbin/agetty 38400 tty4 linux
#c5:2345:respawn:/sbin/agetty 38400 tty5 linux
#c6:2345:respawn:/sbin/agetty 38400 tty6 linux
...
# SERIAL CONSOLES
s0:12345:respawn:/sbin/agetty 115200 ttyAM0 vt100 # ARM-specific
#s0:12345:respawn:/sbin/agetty 9600 ttyS0 vt100
#s1:12345:respawn:/sbin/agetty 9600 ttyS1 vt100
...

Make the /bin/ash Symlink

Code: Create a ${SYSROOT}/bin/ash -> busybox Symlink
cd ${SYSROOT}/bin
ln -sf busybox ash

If trouble ever arises with the userland and normal login is not possible, pass "console=ttyAM0,115200 root=/dev/sda1 rootdelay=5s init=/bin/ash" as the kernel command line at the Redboot prompt. Since busybox is compiled statically, it should allow you to sort out the issue without having to do a major overhaul of the system.

Add Static Device Nodes

Code: Create Static ${SYSROOT}/dev nodes
cd ${SYSROOT}/dev
mknod -m 600 mem c 1 1
mknod -m 666 null c 1 3
mknod -m 666 zero c 1 5
mknod -m 644 random c 1 8
for i in `seq 0 6`; do mknod -m 600 tty${i} c 4 ${i}; done
for i in `seq 0 2`; do 
  mknod -m 660 ttyAM${i} c 204 $((16+${i})); 
done
mknod -m 666 tty c 5 0
mkdir -p ttys && cd ttys
for i in `seq 0 2`; do ln -sf ${i} ../ttyAM${i}; done
cd ..
mknod -m 600 console c 5 1
ln -sf /proc/self/fd fd
ln -sf fd/0 stdin
ln -sf fd/1 stdout
ln -sf fd/2 stderr
# and a few additional of our own
mknod -m 400 urandom c 1 9
mknod -m 660 sda b 8 0
mknod -m 660 sda1 c 8 1
mknod -m 660 sda2 c 8 2
mkdir misc
ln -sf misc/rtc rtc
# This is specifically for the rtc-m48t86 module
mknod -m 664 misc/rtc c 254 1
mknod -m 660 hpet c 10 228
mknod -m 640 kmem c 1 2
mknod -m 660 kmsg c 1 11

Adjust the Hostname

Code: Edit ${SYSROOT}/etc/conf.d/hostname
echo "HOSTNAME=ts72xx" > ${SYSROOT}/etc/conf.d/hostname

Static nodes are necessary in case the init process does not properly start Udev (or an equivalent device manager). This is the case when Bash is cross-compiled (for the glibc distro)

Edit SSHD Settings

File: Edit ${SYSROOT}/etc/ssh/sshd_config
...
PermitRootLogin yes
...
PasswordAuthentication no
...
UseDNS no
...

Later on, an asymmetric authentication system will be set up for SSH using public keys on a per-device basis.

Remove the Root Password for Local Logins (Optional)

If you are completely opposed to root login on the terminal, then leave the /etc/securetty file with the default entries. The rest of this installation procedure assumes that root can at least log in on ttyAM0.

If you would like to allow root to login on the first terminal device (ttyAM0), then

Code: Add ttyAM0 to ${SYSROOT}/etc/securetty
echo ttyAM0 >> ${SYSROOT}/etc/securetty

If you are feeling bold and would like to allow for password-less root login on the terminal, then

File: Edit ${SYSROOT}/etc/password
root::0:0:root:/root:/bin/bash
...

With any of the settings above, there is still no way for root to login remotely via password authentication.

Add the SSH User/Group and Root's .ssh Folder

Code: So SSH will start
echo 'sshd:x:22:22:added by portage for openssh:/var/empty:/sbin/nologin' >> ${SYSROOT}/etc/passwd
echo 'sshd:*:9797:0:::::' >> ${SYSROOT}/etc/shadow
echo 'sshd:x:22:' >> ${SYSROOT}/etc/group
mkdir -p ${SYSROOT}/root/.ssh
chown -R root:root ${SYSROOT}/root/.ssh
chmod -R u+rw,go-rwx ${SYSROOT}/root/.ssh

Perform rc-updates

Code: Perform RC-Updates
for i in consolefont keymaps; do 
ROOT=${SYSROOT} rc-update del ${i} boot
done

for i in netmount; do 
ROOT=${SYSROOT} rc-update del ${i} default
done

for i in net.eth0; do 
ROOT=${SYSROOT} rc-update add ${i} default
done

Note: I have purposely left out SSHD from the startup because I do not want /etc/init.d/sshd to generate host keys automatically. The reasoning might not be fully apparent right now, but the idea is that several of these embedded devices are going to be deployed from a manufacturing station and all of the keys need to be done at the same time and entered into databases.

Also, for the sake of having a redistributable root filesystem, there should be no ssh keys generated before deployment.

If you would prefer to just have the ssh server running from the start (after 'logging in for the second time'), then add 'sshd' behind 'net.eth0' above.

Add Convenient Ctrl+Left Ctrl+Right Bash Macros

File: Edit ${SYSROOT}/root/.inputrc
"\e[1;5C": forward-word
"\e[1;5D": backward-word
"\e[5C": forward-word
"\e[5D": backward-word
"\e\e[C": forward-word
"\e\e[D": backward-word

Perform an Etc-Update on ${SYSROOT}

Code: Etc-Update
ROOT=${SYSROOT} etc-update

Creating the USB Root Filesystem

Good work so far! Up until now, everything has been isolated on your workstation. At this point, we'll via the basics like formatting the USB device and also build that list of 'system' packages that would not originally cross compile.

After all of the system packages are compiled, we'll copy those from the board back into our BPR, and then create a complete filesystem image. This is the 'full distro' that can be used during development of your embedded system. Some warning should be given, because this must be done before any unique keys are assigned to the filesystem in order ot avoid security risks.

The 'full distro' will come in 2 flavours:

The latter can be used for a 'small' distro based on the full glibc userland (as opposed to a 'tiny' uClibc userland).

Formatting the USB Storage Device

Code: Formatting the Root Filesystem
# the -m option is optional but I would
# rather not sacrifice disk space
mkfs.ext2 -L "Gen2-ts72xx-full" -m 0 /dev/sdd1mkfs.ext2 \
-L "Gen2-ts72xx-full" -m 0 /dev/sdd1
Code: Formatting the Swap Partition
mkswap -L "swap" /dev/sdd2
 

Populating the Root Partition

Copy the ${SYSROOT}

Once again, remove and re-insert the USB storage device. Make a note of where the device was automounted. If the device was not automounted, then do this manually. Assign the variable MNTPNT as the location where the USB storage device was mounted.

To install the 'full' distro, use

Code: Copy the ${SYSROOT} to the Root Partition
xmerge --root ${MNTPNT} -Kav1 \
$PKGS sys-devel/gcc sys-devel/binutils \
sys-kernel/linux-headers sys-libs/glibc sys-devel/gdb
rsync -avr ${SYSROOT}/etc/ ${MNTPNT}/etc
rsync -avr ${SYSROOT}/dev/ ${MNTPNT}/dev
rsync -av ${SYSROOT}/bin/ash ${MNTPNT}/bin
ROOT=${MNTPNT} gcc-config 1
ROOT=${MNTPNT} binutils-config 1
ROOT=${MNTPNT} etc-update
 

Copy Relevant Bash Files

Because of a nasty little bug in bash, where it doesn't properly interpret signalling, it is necessary to build bash natively on the board itself. This is a fairly cumbersome process, but there are a couple of steps we can do to prepare for it.

Code: Copy Relevant Bash Files
mkdir -p ${MNTPNT}/root/bash/distfiles
cp -aR /usr/portage/app-shells/bash/files ${MNTPNT}/root/bash
cp /usr/portage/distfiles/bash32-* ${MNTPNT}/root/bash/distfiles
cp /usr/portage/distfiles/bash-3.2.tar.gz ${MNTPNT}/root/bash/distfiles
wget -O ${MNTPNT}/root/bash/build-bash-3.2_p17-r1.sh \
${SRVR}/scripts/build-bash-3.2_p17-r1.sh
 

Don't unmount the partition quite yet.

Building the Linux Kernel

The Linux kernel (even as of 2.6.23.1) needs to have several patches applied in order to properly run on the TS72xx boards. I have made a collection of these patches and also provided a script to automatically apply all of the necessary patches to make life easier.

The patches include:

Code: Fetch, Patch, and Build the Linux Kernel
cd ~
KVL=2.6.23.1
KVS=2.6
wget ftp://ftp.kernel.org/pub/linux/kernel/v${KVS}/linux-${KVL}.tar.bz2
wget ${SRVR}/scripts/linux-${KVL}-apply-ts72xx-patches.sh
tar xjf linux-${KVL}.tar.bz2
sh linux-${KVL}-apply-ts72xx-patches.sh linux-${KVL}
wget -O linux-${KVL}/.config ${SRVR}/configs/linux-${KVL}-ts72xx-eabi.config
cd linux-${KVL}
make ARCH=arm CROSS_COMPILE=${MYHOST}- menuconfig
# when you're satisfied with the kernel options
make ARCH=arm CROSS_COMPILE=${MYHOST}-
make ARCH=arm CROSS_COMPILER=${MYHOST}- \
INSTALL_MOD_PATH=${MNTPNT} modules_install
 

Now you may safely unmount the ${MNTPNT}.

Code: Unmount the Root Partition
umount ${MNTPNT}
 

Making the Kernel Image Available to RedBoot

There are a few different options to make the linux kernel image available to RedBoot. Two of them will be addressed here, namely

The preferred method is to set up a TFTP service on the local network. TFTP transfers are fast but require a TFTP server on the local network. Xmodem is the alternative - it requires nothing more than a terminal client supporting the xmodem protocol over a serial cable, but these transfers are much slower. If you plan on uploading the kernel image to boards frequently, the best option is to set up a TFTP server. There are many different terminal clients available, and one of them will be necessary on the build machine.

Creating a TFTP Root (Optional)

Open a completely new terminal window on your workstation and login as root. Emerge the TFTP server

Code: Install a TFTP server
TFTPROOT=/tftproot
emerge -av1 net-ftp/tftp-hpa

echo "INTFTPD_PATH=\"${TFTPROOT}\"" > /etc/conf.d/in.tftpd
echo 'INTFTPD_OPTS="-s ${INTFTPD_PATH}"' >> /etc/conf.d/in.tftpd

mkdir -p ${TFTPROOT}
cp ~/linux-2.6.23.1/arch/arm/boot/zImage /tftproot

/etc/init.d/in.tftpd restart
 

Logging in for the First Time

Loading the Linux Kernel into RAM

Code: Powering-up the TS72xx
>> TS-NANDBOOT, Rev 1.00 - built 14:57:51, Dec 30 2004
>> Copyright (C) 2004, Technologic Systems


>> TS-BOOTROM, Rev 1.06 - built 14:21:24, Dec  5 2005
>> Copyright (C) 2005, Technologic Systems
>> TS-7260: Rev E0 CPU, Rev D PLD, 64MB SDRAM
>> TS-5620: detected, battery OK, time ( 12:20:34, Feb 17 2008 )

+
 

Loading the Kernel via TFTP

Code: Loading the Kernel using the TFTP Protocol
Redboot> ip_address -l <board_ip>/<netmask_len> -h <tftp_ip>
Redboot> load -r -b 0x00218000 zImage-eabi
 

Loading the Kernel via Xmodem

Code: Loading the Kernel using the Xmodem Protocol
Redboot> load -r -b 0x00218000 -m xmodem
 

You now have about 10 seconds to initiate the xmodem file transfer. If using Minicom,

Running the Linux Kernel from RedBoot

Code: Running the Linux Kernel from Redboot
Redboot> exec -c "console=ttyAM0,115200 root=/dev/sda1 rootdelay=5s"
 

The Initial Environment

After the Linux kernel boots up for the first time and enters the environment, the first login will not appear to be fully functional. That is actually very true. None of the familiar Gentoo init.d scripts will run. This is due to a bug in the way that bash deals with signals and foreground processes and some oddity of Python (which? there are so many!). This is a well known bug, and it can only be resolved by compiling bash natively.

First, log in as root. Then,

Code: Some Initialization Steps
mount -o rw,remount,noatime /
mount -t proc none /proc
mount -t sysfs none /sys
ldconfig
 

Next, you should double-check that floating-point is working with this very simple test program.

File: Edit double_test.c
#include <stdio.h>
#include <math.h>
int main()
{
	printf( "x = %f\n", 4.0 * exp(-0.5) / sqrt(2.0) );
	return 0;
}
 

Compile the test program with 'gcc -lm -o double_test double_test.c'. Run it with ./double_test. If the output variable x is 1.715528, then your floating point 'works'. If the output is zero or some other value then your floating point does not work. Did you forget to define __MAVERICK__ when building glibc?

For The Paranoid

paranoia.c still shows some areas for improvement for floating point. There are many many potential reasons that the maverick toolchain does not score 100% and they range from the maverick engine itself, to exception unwinding, etc.

Recently Cirrus has abandoned the task of providing a functional gcc for their boards with full floating point support. There is talk of a Savannah.org project to finish the job, so hopefully that will be fruitful. Two other sets of gcc patches are discussed on the Debian wiki and on the linux-cirrus list.

For The Skeptical

For lack of a better test to see whether MaverickCrunch was actually enabled, and I wasn't just being fooled by soft-float, I ran the same test that Martin Guy used. The test was to time the encoding of a 16-bit stereo 44.1 kHz WAV into a 128 kbps MP3. [11]

Code: Output of the Lame MP3 Encoder
ts72xx shm # cd /dev/shm && cp ~/H-lame.wav .
ts72xx shm # lame -b 128 H-lame.wav H-lame.mp3
LAME 3.97 32bits (http://www.mp3dev.org/)
Using polyphase lowpass filter, transition band: 16538 Hz - 17071 Hz
Encoding H-lame.wav to H-lame.mp3
Encoding as 44.1 kHz 128 kbps j-stereo MPEG-1 Layer III (11x) qval=3
    Frame          |  CPU time/estim | REAL time/estim | play/CPU |    ETA 
  1403/1403  (100%)|    2:21/    2:21|    2:21/    2:21|   0.2597x|    0:00 
-------------------------------------------------------------------------------
   kbps        MS  %     long switch short %
  128.0      100.0        92.9   4.5   2.6
Writing LAME Tag...done
ReplayGain: -51.0dB
 

Encoding the audio takes 2 minutes and 21 seconds, which is on par with Martin's tests. Thanks for the reference times Martin ;-)

Actually, when I first performed this test, the encoding time was ~ 6 minutes, which implied that lame was still relying on softfp. This implies that gcc does not actually set the default -m options when configured --with-cpu=arm920t, --with-fpu=maverick, etc, leading me to put the -m options I was expecting in the CFLAGS variable in ${SYSROOT}/etc/make.conf. If I hadn't have done this test, I probably would have gone on quasi-believing that it was actually using the MaverickCrunch fpu. All is fixed now though ;-) }}

Re-Compile Bash

We're almost there. I applaud you for getting this far! Now run the bash build script and take (several) moments to appreciate the beauty of cross-compilation (and how native/embedded compilation can be so much slower!).

Code: Build Bash
cd /root/bash
sh build-bash-3.2_p17-r1.sh
chsh -s /bin/ash
exit
# login again
cp bash/bash-install/bin/bash* /bin
chsh -s /bin/bash
exit
# login again
echo My SHELL is ${SHELL} - Tada'!'
qpkg -P ~ bash
rm -Rf bash
 

The chsh command is needed to change the login shell before overwriting the previous version of bash. This is necessary because bash would otherwise still be in use, resulting in a message like "cp: cannot create regular file `/bin/bash': Text file busy". It's a good thing we installed a static busybox beforehand and had that handy /bin/ash symlink!

Exit from the environment by saying 'umount / && exit', and then power down the board. Remove the USB storage device and insert it back into your workstation. Move the re-compiled bash from the board to your package repository, so that you can skip bash re-compilation next time.

Code: Copy the Re-Compiled Bash into ${PKGDIR}/All
mv ${MNTPNT}/root/bash-3.2_p17-r1.tbz2 \
${SYSROOT}/var/tmp/binpkgs/All
umount ${MNTPNT}
 

Logging in for the Second Time

Re-insert your USB storage device into the board and follow the instructions for booting again. This time you should notice the more familiar init sequence of a Gentoo System! The only thing preventing that in the first place was really just a bash bug. I hope one of these days that bug is fixed.

Compile the Remaining System Packages

The few remaining packages required for the 'system' group are libperl, perl, PodParser, Test-Harness, and perl-cleaner. Aside from those, I would also like to emerge the latest stable versions of tar, python, and pycrypto, since the RM160 hash can only be done with >=Python-2.5. Also, I would like to install a full GCC - with fortran,gcc,g++,and gcj support. This was quite difficult to successfully cross compile, but natively compiling should be functional, if not very time consuming.

TODO - This requires that the portage tree be either mounted via NFS or copied onto the USB device... write some steps

Code: Emerge the Remaining Few
emerge -av1 --nodeps libperl perl PodParser Test-Harness perl-cleaner tar python pycrypto gcc
 

Packaging The 'Full' Distro

After the rest of the 'system' packages have been compiled and installed on the USB device, copy them back to ${PKGDIR}/All.

TODO ... will get to writing it shortly

Give Me the Binaries Already

Please don't forget to read

http://vaiprime.visibleassets.com/~cfriedt/binpkgs/READ and http://vaiprime.visibleassets.com/~cfriedt/toolchains/READ

Toolchain

Here is the gcc-3.4.6/glibc-2.3.2/binutils-2.15 toolchain that I use.

The files are all stored in Gentoo tbz2 format so that they can be installed using qmerge.

Installing the Toolchain

I have working toolchains for

Eventually I would also like to have cross-toolchains for ppc, ppc-mac and intel-mac as well - that should hopefully cover most of the development platforms that people might be using!

Code: Instaling the Toolchain
CHOST=i686-pc-linux-gnu
CTARGET=armv4tl-maverick-linux-gnueabi
SRVR=http://vaiprime.visibleassets.com/~cfriedt
export PORTAGE_BINHOST=${SRVR}/toolchains/${CHOST}/${CTARGET}/All
export QMERGE=1
qmerge -fv \
cross-${CTARGET}/binutils-2.17-r1 \
cross-${CTARGET}/gcc-4.1.2 \
cross-${CTARGET}/linux-headers-2.6.23-r3 \
cross-${CTARGET}/glibc-2.5-r4 \
cross-${CTARGET}/gdb-6.7.1-r2
unset CHOST CTARGET SRVR PORTAGE_BINHOST QMERGE
 

Naturally, you should also have created and exported ${SYSROOT}, as well as ${SYSROOT}/etc/make.conf, ${SYSROOT}/etc/make.profile, ${SYSROOT}/etc/portage/package.use, ${SYSROOT}/etc/portage/package.keywords, ${SYSROOT}/etc/portage/package.unmask, ${SYSROOT}/etc/portage/package.mask, ${SYSROOT}/usr/sbin/xmerge and so on. Templates for all of those files were explained above in detail.

Host Binaries

Here are the host binaries that I've built.

They are also stored in the Gentoo tbz2 format so that they can be installed using qmerge.

Installing the Host Binaries

Assuming that you're using a TS72xx board, create the make.conf below:

File: /etc/make.conf
CHOST=armv4lt-maverick-linux-gnueabi
PKGDIR=/tmp/binpkgs
PORTAGE_TMPDIR=/tmp
INSTALL_MASK="*.a *.la *.h .keep* /usr/share /usr/include /etc"
PORTAGE_BINHOST="http://vaiprime.visibleassets.com/~cfriedt/binpkgs/arm-unknown-linux-gnu/All"
 

Next, do the 1 time setup below:

Code: One-Time Setup
mkdir -p /var
cd /var
rm -Rf db cache
ln -sf ../tmp/db db
ln -sf ../tmp/cache cache
mount -t ramfs none /tmp
cd /tmp

wget http://vaiprime.visibleassets.com/~cfriedt/binpkgs/arm-unknown-linux-gnu/All/portage-utils-0.1.28.tbz2
applets="./usr/bin/qcheck ./usr/bin/qxpak ./usr/bin/qgrep ./usr/bin/q ./usr/bin/qpkg ./usr/bin/qlop \
./usr/bin/qsearch ./usr/bin/qsize ./usr/bin/qglsa ./usr/bin/qatom ./usr/bin/quse ./usr/bin/qlist \
./usr/bin/qcache ./usr/bin/qdepends ./usr/bin/qfile ./usr/bin/qtbz2 ./usr/bin/qmerge"
tar xpvjf portage-utils*tbz2 ${applets} -C /
cd / && umount /tmp
 

Each time you want to install a package, you should

Code: Before Using Qmerge
mount -t ramfs none /tmp
mkdir -p /tmp/binpkgs /tmp/db/pkg /tmp/portage /tmp/cache
export QMERGE=1
 

Note: INSTALL_MASK sometimes needs to be set on a per-package basis. It can be somewhat tricky to manage actually, which is why I've chosen the simple example below.

Code: Example Qmerge Usage
qmerge -KOv lzo
qlist lzo
qmerge -Uv lzo
 
Code: After Using Qmerge
unset QMERGE
cd /
umount /tmp
 

I would also strongly recommend having a read-only root filesystem. This will prevent unforeseeable writes to the flash filesystem which could extend the lifetime of the board. This basically means that before using qmerge, you would need to say remount -o remount,rw /, and then when you're done, say remount -o remount,ro /.

Where to Go From Here

I hope you enjoyed this HowTo.

The next one that I write will be detailed instructions on how to reduce the size of the 'full' filesystem to make it a 'small' filesystem, but not quite a 'tiny' filesystem.

The 'small' filesystem will still have a glibc userland and many bloated binaries (instead of using BusyBox). Although BusyBox is still installed in this distro as it is.

Perhaps before that point, I should get some work done on a 'commissioning' system, with detailed instructions on how to automate the assignment of host keys for SSH and OpenVPN so that these boards can be manufactured en masse for a distributed embedded environment. A slight challenge will be reducing the encryption level in either OpenVPN or the SSH daemon to reduce channel latency - there is definitely such a thing as encryption overkill.

The next part after that will be somehow organizing qmerge as an on-board package manager. The real challenge there is reducing the size of /var/db - at the moment it uses filesystem nodes for the database entries, which is a major waste of space. I should be able to reduce space slightly by using a db format such as sqlite (all in one file) and then applying gzip or bzip2 compression. Theoretically, it should be possible to just gzip or bzip2 compress the filesystem where the package database is located. That option will probably be an initial step since its much easier. Eventually all of this will be tied in with organizing a binary package repository (BPR) for distribution in the embedded environment and automated updates.

Finally, when that's done, I'll do everything with a uClibc userland, busybox, dropbear, etc, in order to minimize the footprint and get everything installed in ~ 4 MB!

Throughout this project I will be maintaining my own BPR. When things have reached some level of stability, then I would be very glad to open up the BPR to all ;-)

Ciao 4 Now

Links


Last modified: Sat, 30 Aug 2008 20:59:00 +0000 Hits: 3,033