
This document explains how to use
deboostrap --foreign
to build from scratch and install a minimal Debian system on the
Sheevaplug (but it is equally applicable to many other embedded systems).
The only piece missing to be able to install from bare metal is a working kernel and initramfs pair, so this document assumes that you already have a kernel which can mount the root file system from a USB key. For the Sheevaplug, the factory kernel in the internal NAND flash will work fine.
The Debian kernel package puts us in a chicken and egg situation: it cannot mount the root without an initramfs (because all drivers are modular), but we cannot build one until we can boot the system. I suppose that, as an exercise of style, somebody could create a minimal initramfs with busybox and the kernel modules needed to mount the root and then mount it manually, but if you really lack a working kernel then it's probably faster to boot the file system image for the first time using
qemu and the "versatile" debian-installer target.
The first step is to run the first stage of
debootstrap
on another system (which does not need to be ARM), to build a temporary root file system. I use the
--variant
and
--include
options to build the smallest possible system with network support, but they can be omitted.
debootstrap \
--foreign --arch=armel \
--variant=minbase \
--include=linux-image-2.6-kirkwood,module-init-tools,udev,netbase,
net-tools,ifupdown,iproute,whiptail,vim-tiny \
sid ./target/ http://ftp.it.debian.org/debian/
As usual when using debootstrap, some manual configuration is needed:
cd target/
echo bokassa.mi.bofh.it > etc/hostname
vi etc/network/interfaces
vi etc/resolv.conf
echo LANG=C > etc/default/locale
echo '127.0.0.1 localhost' > etc/hosts
cat <<END > etc/fstab
/dev/root / ext3 noatime 0 1
tmpfs /tmp tmpfs defaults 0 0
#/tmp /var/tmp none bind 0 0
END
I took some hints from
http://wiki.debian.org/ReadonlyRoot to reduce writes to the flash file system:
# the blkid cache is evil anyway
ln -s /dev/null etc/blkid.tab
# this link will be created anyway by the package
ln -s /var/lib/initscripts/nologin etc/nologin
# it's better to not use a static mtab with modern kernels
ln -s /proc/mounts etc/mtab
# unless you plan to use multiple removable network interfaces, persistent
# interface names are not needed
: > etc/udev/rules.d/75-persistent-net-generator.rules
Two small workarounds are needed:
# if this is not set then the preinst of linux-image-* will die trying
# to ask a debconf question in the debootstrap second stage
echo 'do_initrd = yes' > etc/kernel-img.conf
# a workaround for bug #520742
: > etc/udev/disabled
Now you can format a USB pen drive and copy the root file system on it:
mke2fs /dev/sdb1
tune2fs -i 0 -c 0 /dev/sdb1
mount /dev/sdb1 /mnt/
rsync -aH target/ /mnt/
umount /mnt/
After powering the plug press a key to get to the
U-Boot prompt and use the factory kernel to boot from USB:
setenv bootargs console=ttyS0,115200 root=/dev/sda1 rootdelay=10 panic=10 init=/bin/bash
run bootcmd
Then you can run the second stage of debootstrap, finish the bare minimal configuration and start init:
./debootstrap/debootstrap --second-stage
# disable the gettys for /dev/tty[1-6], which do not exist
vi /etc/inittab
# and add one for the serial console
echo 'T0:2345:respawn:/sbin/getty -L ttyS0 115200 linux' >> /etc/inittab
# do not forget to set the root password or you will not be able to login...
vi /etc/shadow
rm /etc/udev/disabled
exec /bin/bash
mount / -o ro,remount
exec /sbin/init
Congratulations, now you can login on the system and start to install the packages you like:
echo 'deb http://ftp.it.debian.org/debian/ unstable main' > /etc/apt/sources.list
echo 'APT Install-Recommends "false"; ;' > /etc/apt/apt.conf.d/no-recommends
apt-get update
# dash is much faster
apt-get install dash
dpkg-divert --add /bin/sh
ln -sf dash /bin/sh
# I do not like these, YMMV
rm /vmlinuz /initrd.img
rmdir /selinux /srv
# the kernel is able to read the time from the RTC by itself, and this
# will allow using a read only root
echo HWCLOCKACCESS=no >> /etc/default/rcS
# faster boot
echo CONCURRENCY=shell >> /etc/default/rcS
# useless on this platform
mv /etc/rcS.d/S01glibc.sh /etc/rcS.d/K01glibc.sh
dpkg-reconfigure tzdata
apt-get install openssh-server screen iptables wget less
U-Boot requires that the kernel and initramfs have a special header:
apt-get uboot-mkimage
cd /boot/
mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 \
-n Linux-2.6.29-2 -d vmlinuz-2.6.29-2-kirkwood uImage
mkimage -A arm -O linux -T ramdisk -C gzip -a 0x00000000 -e 0x00000000 \
-n initramfs -d initrd.img-2.6.29-2-kirkwood uInitrd
Now you can reboot and configure u-boot to boot from the USB device. This is the variables scheme I like and it is not mandatory in any way, so I recommend that you read and understand the existing configuration before modifying it (some lines have been broken for readability):
setenv bootargs_nand $(bootargs)
setenv bootcmd_nand $(bootcmd)
setenv bootargs_root root=/dev/sda1
setenv bootargs_misc 'ro panic=10
mtdparts=nand_mtd:0x400000@0x100000(uImage),0x1fb00000@0x500000(rootfs)'
setenv bootcmd_usb 'usb start; ext2load usb 0:1 0x00200000 /boot/uImage;
ext2load usb 0:1 0x01100000 /boot/uInitrd'
setenv bootcmd 'setenv bootargs $(console) $(bootargs_root) $(bootargs_misc)
$(bootargs_more); run bootcmd_usb; bootm 0x00200000 0x01100000'
Since now you are not using anymore the Marvell kernel tree it is mandatory to set these two variables and reboot:
setenv mainlineLinux yes
setenv arcNumber 2097
saveenv
reset
Installation to SD is identical, but requires an updated version of U-Boot with SD support. Due to a kernel bug which prevents autoloading the driver you will need to add
mvsdio and
mmc_block to
/etc/initramfs-tools/modules and rebuild the initramfs.
(Yes, the naming theme I use at home is "
african dictators"...)