Installing Debian on the Sheevaplug
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 #tmpfs /var/run tmpfs defaults 0 0 #debugfs /sys/kernel/debug/ debugfs defaults 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"...)