Embedded Linux
References
Why Gentoo?
Windows is obviously out (virus prone, bad reliablity, closed source, bloated, requires a graphical interface, etc).
Gentoo was chosen because of its customizability, and ease of use of is package management system. Ubuntu and other debian based flavors tend to be way to bloated and are typically inappropriate for headless embedded development. The current gentoo environment only takes up 64MB of space (with 52MB of 3rd party libraries, I.E. it could be cut down to 12MB), and boots in under 20 seconds on the alix3c1 board (including 3rd party services).
That being said, lets continue on to how to setup a base Gentoo distribution for use on ALIX3C1 board. This can also be done with crossdev, and while I will not go over that process in detail here, its worth looking into. For setting up the development environment with crossdev, I used
Using Scripts to Install Embedded Gentoo
I've been working on scrips to perform these tasks automatically. Due to packages always changing there might be some minor problems with these scripts, but I'm providing them anyway as I generally find them to be useful. Of particular interest should be the scripts to change to the development environment and install the OS on to a compact flash card. Also included are all of the configuration files necessary to set up any of the devices I have installed linux on (Alix boards, Soekris boards, pico ITX). If you do improve these scripts, I'd appreciate it if you would share your changes.
Installing from Scratch
Set up the Development Environment
Create a working directory
Download the latest stage 1 tarball and untar
tar -xvjpf stage1-x86-uclibc-2006.1.tar.bz2 -C uclibc-gentoo/
Mount the proc and portage directories from the local computer to your development_fs so they are available for use.
Copy over DNS information to the development environment
And now chroot
Build Development Filesystem
Change the portage profile
unlink make.profile
ln -s ../usr/portage/profiles/uclibc/x86 make.profile
Create new environment and load variables into memory.
source /etc/profile
Modify make.conf file to your liking/needs.
This is for an AMD Geode target.
FEATURES="buildpkg"
CFLAGS="-march=i586 -Os -pipe -fomit-frame-pointer -mmmx"
CHOST="i586-gentoo-linux-uclibc"
CXXFLAGS="${CFLAGS}"
UCLIBC_CPU="586MMX"
Bootstrap the system. There were a few problems with this step when I peformed it, and I found that by emerging gcc beforehand I could get around them.
emerge gcc
/usr/portage/scripts/bootstrap.sh
emerge portage
emerge -e system
There were also some problems with util-linux, coreutils and shadow. This is how I got around them.
export gl_cv_func_getcwd_path_max=yes
emerge coreutils
emerge =shadow-4.0.18.2
Remove the old sysvinit.
Unmask all of the necessary packages.
echo "=sys-apps/baselayout-2.0.0 **" >> /etc/portage/package.keywords
echo "=sys-apps/baselayout-2.0.0" >> /etc/portage/package.unmask echo "sys-apps/openrc **" >> /etc/portage/package.keywords
echo "sys-apps/openrc" >> /etc/portage/package.unmask
echo "sys-apps/sysvinit **" >> /etc/portage/package.keywords
echo "sys-apps/sysvinit" >> /etc/portage/package.unmask
Now emerge the remaining necessary utilities.
Build the Embedded Filesystem
Create the embedded_fs directory.
Emerge baselayout-lite busybox into embedded_fs. This gives your system a basic file structure and necessary binaries.
Baselayout doesn't make the necessary devices
mkdir -p /$SYSROOT/dev/pts
mkdir /$SYSROOT/dev/net
mknod -m 600 /$SYSROOT/dev/console c 5 1
mknod -m 644 /$SYSROOT/dev/ttyS0 c 4 64
mknod -m 644 /$SYSROOT/dev/ttyS1 c 4 65
mknod -m 644 /$SYSROOT/dev/ttyS4 c 4 68
mknod -m 644 /$SYSROOT/dev/ttyS5 c 4 69
mknod -m 644 /$SYSROOT/dev/ttyS6 c 4 70
mknod -m 644 /$SYSROOT/dev/ttyS7 c 4 71
mknod -m 666 /$SYSROOT/dev/null c 1 3
mknod -m 666 /$SYSROOT/dev/zero c 1 5
mknod -m 644 /$SYSROOT/dev/random c 1 8
mknod -m 644 /$SYSROOT/dev/urandom c 1 9
mknod /$SYSROOT/dev/hda1 b 3 1
mknod /$SYSROOT/dev/hda2 b 3 2
mknod /$SYSROOT/dev/ptmx c 5 2
mknod /$SYSROOT/dev/tty c 5 0
mknod /$SYSROOT/dev/ttyUSB0 c 188 0
Edit the init script
chmod +x /embedded_fs/init
nano -w /embedded_fs/init
echo
echo
echo " Welcome to Embedded Gentoo."
echo
echo
echo " * Setting umask.."
umask 022
echo " * Mounting /proc.."
mount -t proc none /proc
echo " * Starting init.."
exec
exec chroot . /sbin/init
echo " *** Starting init failed! ***"
echo " * Trying to start a shell.."
exec /bin/ash
Inittab needs some changes too
null::sysinit:/bin/mount -a
null::sysinit:/bin/hostname -F /etc/hostname
null::sysinit:/sbin/ifconfig lo 127.0.0.1 up
null::sysinit:/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
# Logging
null::sysinit:/bin/touch /var/log/messages
null::respawn:/sbin/syslogd -n -m 0
null::respawn:/sbin/klogd -n
# Stuff to do before rebooting
::ctrlaltdel:/etc/init.d/rcK
::ctrlaltdel:/bin/killall klogd
::ctrlaltdel:/bin/killall syslogd
::ctrlaltdel:/bin/umount -a -r
Create a mount point for persistent storage.
Edit fstab
none | /dev/pts | devpts | pts gid=5,mode=620 | 0 0 |
none | /tmp/ | tmpfs | defaults | 0 0 |
none | /proc | proc | defaults | 0 0 |
/dev/hda1 | /boot | ext2 | noauto | 0 0 |
/dev/hda2 | /mnt/cf | ext2 | defaults | 0 0 |
Emerge uclibc into the embedded_fs. Use the -K option because we don't get the extra files created by the build/emerge process into our embedded fs which needs to be as small as possible.
Create the symlinks for busybox in the embedded_fs.
mount -o bind /proc/ /embedded_fs/proc/
chroot /embedded_fs /bin/busybox --install -s
umount /embedded_fs/proc
Set time zone in your embedded_fs. See this guide for details. For central standard time in the US, use "CST6CDT".
CST6CDT
*/
Set root password for the embedded_fs
passwd
exit
Clean up the embedded_fs.
rm -R /embedded_fs/var/lib/portage/
Build and Install a Kernel to the Embedded Filesystem
First we will emerge the kernel source into our development filesystem, then configure and build it.
cd /usr/src/
cd linux
make menuconfig
Configure your kernel for your TARGET SBC here. I HIGHLY suggest you configure the kernel to compile everything into the kernel, and nothing as a module. My config for the alix3d2 can be found here
ROOT=/embedded_fs make modules_install
mkdir /embedded_fs/boot
cp /usr/src/linux/arch/i386/boot/bzImage /embedded_fs/boot/kernel-2.6.23.17
cd /embedded_fs
Make a symbolic link for the bootloader.
Build and Install Non-System Programs to the Embedded Filesystem
Emerge other software you need for your embedded target. This is very wildly depending on your needs. Also your proprietary application will be done here.
ROOT=/embedded_fs emerge -K foo*
Here is what I did to install openssh (dropbear doesn't provide all of the functionality I wanted), madwifi-ng, aodv-uu, xerces-c, libpcap, and libtrace.
ROOT=/embedded_fs emerge -K sys-libs/zlib openssl --nodeps
cp -av /embedded_fs/lib/libz.so* /usr/i586-pc-linux-uclibc/lib/
cp -av /embedded_fs/usr/include/zlib.h /usr/i586-pc-linux-uclibc/usr/include/
cp -av /embedded_fs/usr/include/zconf.h /usr/i586-pc-linux-uclibc/usr/include/
cp -av /embedded_fs/usr/lib/libcrypto.* /usr/i586-pc-linux-uclibc/usr/lib/
cp -av /embedded_fs/usr/lib/libssl.* /usr/i586-pc-linux-uclibc/usr/lib/
cp -av /embedded_fs/usr/include/openssl /usr/i586-pc-linux-uclibc/usr/include/
emerge openssh --nodeps
ROOT=/embedded_fs emerge -K openssh --nodeps
echo "sshd:x:22:22:sshd:/dev/null:/bin/false" >> /embedded_fs/etc/passwd
echo "PermitEmptyPasswords yes" >> /embedded_fs/etc/ssh/sshd_config
/usr/bin/ssh-keygen -t rsa1 -b 1024 -f /embedded_fs/etc/ssh/ssh_host_key -N ''
/usr/bin/ssh-keygen -d -f /embedded_fs/etc/ssh/ssh_host_dsa_key -N ''
/usr/bin/ssh-keygen -t rsa -f /embedded_fs/etc/ssh/ssh_host_rsa_key -N ''
emerge madwifi-ng-tools wireless-tools madwifi-ng --nodeps
ROOT=/embedded_fs emerge -K madwifi-ng-tools wireless-tools madwifi-ng --nodeps
cd ~
wget "http://downloads.sourceforge.net/aodvuu/aodv-uu-0.9.5.tar.gz?use_mirror=voxel"
tar xzvf aodv-uu-0.9.5.tar.gz
cd aodv-uu-0.9.5
vim Makefile
KERNEL=2.6.23.17
CC=i586-pc-linux-uclibc-gcc
LD=i586-pc-linux-uclibc-ld
CPP=i586-pc-linux-uclibc-g++
OPTS=-Wall -Os
xkmake
install -s -m 755 aodvd /embedded_fs/sbin/aodvd
mkdir /embedded_fs/lib/modules/2.6.23.17/aodv
install -m 644 lnx/kaodv.ko /embedded_fs/lib/modules/2.6.23.17/aodv/kaodv.ko
mkdir /embedded_fs/var/log
emerge =xerces-c-2.7.0-r1
ROOT=/embedded_fs emerge -K =xerces-c-2.7.0-r1
emerge libpcap
ROOT=/embedded_fs emerge -K libpcap
cd ~
wget "http://research.wand.net.nz/software/libtrace/libtrace-3.0.6.tar.bz2"
tar xvf libtrace-3.0.6.tar.bz2
cd libtrace-3.0.6
./configure --prefix="/embedded_fs/usr" --host i586-pc-linux-uclibc LDFLAGS="-L/usr/i586-pc-linux-uclibc/usr/lib -L/embedded_fs/usr/lib -L/embedded_fs/lib" CFLAGS="-Os -pipe -I/embedded_fs/usr/include" CXXFLAGS="${CFLAGS}"
make && make install
Install Service Scripts
In order to automatically start services, you will need to write your own startup scripts and place them in the /embedded_fs/etc/init.d/ folder with a name that consists of "S#-NAME" where # is a number that orders the services, and NAME is the name of the service. Here is an example for starting the wireless device and sshd:
# File: S91-madwifi_managed
# Author: Jack Elston
DEV=ath0
ADDRESS="20.0.0.5"
ESSID=""
modprobe ath_pci > /dev/null 2>&1
iwconfig $DEV essid $ESSID
ifconfig $DEV $ADDRESS netmask 255.255.255.0 up
# File: S96-sshd
# Author: Jack Elston
if [[ ! -d /var/empty ]] ; then
mkdir -p /var/empty || return 1
fi
if [[ ! -e /etc/ssh/sshd_config ]] ; then
echo "You need an /etc/ssh/sshd_config file to run sshd"
echo "There is a sample file in /usr/share/doc/openssh"
return 1
fi
if [[ ! -e /etc/ssh/ssh_host_key ]] ; then
echo "Generating Hostkey..."
/usr/bin/ssh-keygen -t rsa1 -b 1024 -f /etc/ssh/ssh_host_key -N '' || return 1
fi
if [[ ! -e /etc/ssh/ssh_host_dsa_key ]] ; then
echo "Generating DSA-Hostkey..."
/usr/bin/ssh-keygen -d -f /etc/ssh/ssh_host_dsa_key -N '' || return 1
fi
if [[ ! -e /etc/ssh/ssh_host_rsa_key ]] ; then
echo "Generating RSA-Hostkey..."
/usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' || return 1
fi
/usr/sbin/sshd -t || return 1
/usr/sbin/sshd -o PidFile=/var/run/sshd.pid
Installing on Compact Flash
To allow the embedded target to run our version of embedded linux, we create a compact flash card that contains the kernel and zipped filesystem. This allows for everything to be run from memory and not use up cycles on the compact flash card. The first step is to partition the compact flash card using fdisk into the following partitions.
/dev/sdb1 | * | 1 | 66 | 66496+ | 83 | Linux | (64MB) |
/dev/sdb2 | 67 | 983 | 924336 | 83 | Linux | (REST) |
Then format each as ext2, and set the partitions not to be checked for errors on mount.
tune2fs -c 0 /dev/sdb1
mke2fs /dev/sdb2
tune2fs -c 0 /dev/sdb2
Now install the bootloader. I use syslinux as it is much smaller and simpler than Grub.
extlinux -i /mnt/usb nano -w /mnt/usb/extlinux.conf
DEFAULT Lite
PROMPT 0
IMPLICIT 0
TIMEOUT 0
CONSOLE 0
LABEL Lite
KERNEL vmlinuz
# APPEND console=ttyS0,115200n8 initrd=initramfs-embedded_fs.igz
APPEND initrd=initramfs-embedded_fs.igz
Now copy over the system files and kernel and unmount the disk.
cd uclibc-gentoo/embedded_fs && find . | cpio -H newc -o | gzip -9 > /mnt/usb/initramfs-embedded_fs.igz
cp uclibc-gentoo/embedded_fs/vmlinuz /mnt/usb/
umount /mnt/usb
You now have embedded gentoo installed on the compact flash card.