Debian on Kirkwood, fra USB-stick, SD-card, SATA-disk, FLASH, og NFS

Nu hvor vi har u-Boot bootloaderen på plads, er det på tide at vi får bootet noget. Der er nok at vælge imellem:

  • Debian Linux
  • Arch Linux
  • Openwrt Linux
  • NetBSD UNIX
  • FreeBSD UNIX

Jeg vælger Debian, mest fordi det er det jeg er vandt til, og fordi der er masser af andre der gør det, og dermed er der stortset altid et svar at finde på nettet når man løber ind i et problem. Jeg kørte Arch Linux en overgang, men det var “anderledes” så jeg er endnu engang kommet tilbage til Debian.

Og hvilket medium skal der bootes fra

  • USB stick
  • sd-card
  • SATA harddisk
  • intern FLASH formateret som JFFS2
  • intern FLASH formateret som UBIFS
  • NFS Network File System

u-Boot kan programmeres i et sprog meget lig Bourne shell (HuSH), så vi kan forholdsvis enkelt lave et system der kan boote fra alle de ovenstående muligheder, i prioriteret rækkefølge, således at man f.ex normalt booter fra den interne FLASH, men hvis man forbinder en USB-stick så vil den boote derfra.

Den nye u-Boot har support for Flattened Device Tree (FDT) så vi kan bruge den samme kernel til mange forskellige systemer, For ikke alt for længe siden skulle de hver have haft en lidt forskellig Linux-kernel, disse kernels kaldes “uImage” og bootes med “bootm” kommandoen. F.ex u-Boot som Pogoplug-en blev leveret med havde kun “bootm”.

En FDT kerne benævnes “zImage” og bootes med “bootz” kommandoen.   Bootloaderen tilføjer så en FDT beskrivelse af maskinen.  I stedet for at lægge FDT-beskrivelse fast i bootloaderen (som er normalt) kan vi loade beskrivelsen når vi booter, “/boot/dts/kirkwood-pogoplug_v4.dtb” indeholder information om hvordan denne box er skruet sammen.  Med dette lille trick kan vi bruge vores USB-stick til at boote mange forskellige Kirkwood maskiner. Og vi behøver ikke at installere en ny u-Boot når vi ændrer maskinen (eller beskrivelsen af maskinen)

u-Boot har en hel del kommandoer og et “environment” der består af variable lige som i Bourne Shell, Environment variable bliver så brugt og/eller sat af de forskellige kommandoer. Man kan selve sætte disse variable, og køre små programmer gemt i disse variable.  Når systemet starter udfører den disse to komandoer “run preboot; run bootcmd” hvorefter den kommer med interaktiv prompt.  Man kan ikke overføre parametre på samme måde som i shellen, men kan nå langt alligevel, f.ex:

setenv usb_load 'setenv ext2load usb 0:1 $addr /boot/$file'
setenv nfs_load 'nfs $addr $rootpath/boot/$file'
setenv load_uimage 'addr=0x800000; file=uImage; run ${dev}_load'

dev=usb if run load_uimage; then echo USB-boot; else dev=nfs; run load_uimage; echo NFS-boot; fi

Den sidste linie vil forsøge at loade uImage fra ext2-filsystem på den første USB device (0) første partition (1 = sda1) nærmere bestemt bliver nedenstående udført:

ext2load usb 0:1 0x800000 /boot/$file

hvis dette går godt skrives der “USB-boot” på konsollen, hvis det fejler loader vi uImage via nettet fra $serverip, der bliver her udført:

nfs 0x800000 $rootpath/boot/uImage; echo NFS-boot

Jeg har altid lavet shell-scripts der laver shell-scripts, det giver mulighed for at se hvad der skal ske inden man udfører det og evt. splitter maskine ad.  Derfor producerer nedenstående shell-script et shell-script som sætter u-Boot environment variable.

#!/bin/sh
# cleanup and setup u-Boot env
# This script generates a script to setup the u-Boot env
#
# $ sudo ./fw_setup.sh
# examine if this is realy what you want to do, then run
# $ sudo .fw_setup.sh | sudo sh -x
#
#USE_NET_CONSOLE=YES
KEEP="arcNumber baudrate bootdelay console ethact ethaddr led_error led_exit led_init machid mainlineLinux mtdids mtdparts stderr stdin stdout"

usage()
{
	echo $*
	echo setup uboot env, be sure to be ROOT
	exit
}

setup()
{
	echo "#### $i ####"
	case $1 in
	usb)
		INIT="'usb start; setenv options root=/dev/sda1 rootdelay=10'"
		LOAD="'ext2load \${dev} 0:1  \$addr /boot/\$file'"
		;;
	ide)
		INIT="'ide reset; setenv options root=/dev/sda1 rootdelay=10'"
		LOAD="'run usb_load'"
		;;
	mmc)
		INIT="'mmc rescan; setenv options root=/dev/mmcblk0p1 rootdelay=10'"
		LOAD="'run usb_load'"
		;;
	jffs2) # http://wiki.openwrt.org/doc/howto/dockstar_sandbox,
		INIT="'setenv options root=/dev/mtdblock3 rootfstype=jffs2'"
		LOAD="'fsload \$addr /boot/\$file'"
		;;
	nfs)
		INIT="'setenv autoload no; dhcp; setenv options root=/dev/nfs rootfstype=nfs rootwait nfsroot=\$rootpath ip=\$ipaddr:\$serverip:\$gatewayip:\$netmask:\$hostname:eth0:off'"
		LOAD="'nfs \$addr \$rootpath/boot/\$file'"
		;;
	ubi) # http://www.blaicher.com/2012/07/installing-debian-on-a-sheevaplug-into-flash/
		INIT="'ubi part nand0,2; ubifsmount rootfs; setenv options root=ubi0:rootfs rootfstype=ubifs ubi.mtd=2'"
		LOAD="'ubifsload \$addr /boot/\$file'"
		;;
	esac
	echo "fw_setenv $1_init $INIT"
	echo "fw_setenv $1_load $LOAD"
	KEEP="$KEEP $1_init $1_load"
}

# Netconsole
setup_nc()
{
	echo "#### Net Console ####"
	echo "fw_setenv nc_init 'setenv autoload no; dhcp'"
	echo "fw_setenv if_nc 'ping \$serverip'"
	echo "fw_setenv nc_start 'setenv ncip \$serverip; setenv bootdelay 10; setenv stdin nc; setenv stdout nc; setenv stderr nc; version;'"
	echo "fw_setenv nc_preboot 'run nc_init; if_nc nc_start'"
	KEEP="$KEEP nc_init if_nc nc_start nc_preboot"
	if [ xYES = x$USE_NET_CONSOLE ]; then
		echo "fw_setenv preboot 'run nc_preboot'"
		KEEP="$KEEP preboot"
	fi
}

######## Main starts here

fw_printenv >/dev/null
if [ $? != 0 ]; then
	usage
fi
eval "`fw_printenv arcNumber`"
case $arcNumber in
2998)
	echo "fw_setenv arcName dockstar"
	INTERFACES="usb nfs jffs2 ubi"
	;;
3542)
	echo "fw_setenv arcName pogo_e02"
	INTERFACES="usb nfs jffs2 ubi"
	;;
3960)
	echo "fw_setenv arcName pogoplug_v4"
	INTERFACES="ide usb mmc nfs jffs2 ubi"
	;;
*)
	usage  "#### Unkown arcNumber=$arcNumber - please FIX"
	;;
esac
echo "#         arcNumber $arcNumber"
KEEP="$KEEP arcName"

setup_nc

for i in $INTERFACES;do
	setup $i
done

echo "#### load ####"
echo "fw_setenv load_fdt 'addr=0x700000; file=dts/kirkwood-\${arcName}.dtb; if run \${dev}_load; then fdt_addr=0x700000; fdt addr \${fdt_addr}; fi'"
echo "fw_setenv load_uimage 'addr=0x800000; file=uImage; if run \${dev}_load; then uimage_addr=0x800000; fi'"
echo "fw_setenv load_zimage 'addr=0x800000; file=zImage; if run \${dev}_load; then zimage_addr=0x800000; fi'"
echo "fw_setenv load_uinitrd 'addr=0x1100000; file=uInitrd; if run \${dev}_load; then uinitrd_addr=0x1100000; else uinitrd_addr=-; fi'"
echo "fw_setenv set_bootargs 'setenv bootargs console=\$console \$nc_options \$options \$mtdparts'"
KEEP="$KEEP load_fdt load_uimage load_zimage load_uinitrd set_bootargs"

echo "#### boot ####"
echo "fw_setenv bootdelay '3'"

echo "fw_setenv mboot 'run \${dev}_init; run set_bootargs; echo ** mboot \${dev} -- \$bootargs; mw 0x800000 0 1; if run load_uimage; then run load_uinitrd; bootm \$uimage_addr \$uinitrd_addr; fi'"

echo "fw_setenv zboot 'run \${dev}_init; run set_bootargs; echo ** zboot \${dev} -- \$bootargs; mw 0x800000 0 1; if run load_fdt; then if run load_zimage; then run load_uinitrd; bootz \$zimage_addr \$uinitrd_addr \$fdt_addr; fi; fi'"

echo "fw_setenv bootcmd 'for dev in \$default $INTERFACES; do if run zboot; then echo zboot success; else run mboot; fi; done; reset'"

KEEP="$KEEP bootdelay mboot zboot bootcmd default"

echo "#### remove unwanted variables ####"
#echo "# KEEP = $KEEP"
for i in `fw_printenv | cut -f1 -d=`;do
	for j in $KEEP; do
		if [ $i = $j ]; then
			break
		fi
	done
	if [ $i != $j ]; then
		echo fw_setenv $i
	fi
done

kører vi programmet på en af mine PogoPlug v4 ser vi:

$ sudo ./fw_setup.sh
fw_setenv arcName pogoplug_v4
#         arcNumber 3960
#### Net Console ####
fw_setenv nc_init 'setenv autoload no; dhcp'
fw_setenv if_nc 'ping $serverip'
fw_setenv nc_start 'setenv ncip $serverip; setenv bootdelay 10; setenv stdin nc; setenv stdout nc; setenv stderr nc; version;'
fw_setenv nc_preboot 'run nc_init; if_nc nc_start'
#### ide ####
fw_setenv ide_init 'ide reset; setenv options root=/dev/sda1 rootdelay=10'
fw_setenv ide_load 'run usb_load'
#### usb ####
fw_setenv usb_init 'usb start; setenv options root=/dev/sda1 rootdelay=10'
fw_setenv usb_load 'ext2load ${dev} 0:1  $addr /boot/$file'
#### mmc ####
fw_setenv mmc_init 'mmc rescan; setenv options root=/dev/mmcblk0p1 rootdelay=10'
fw_setenv mmc_load 'run usb_load'
#### nfs ####
fw_setenv nfs_init 'setenv autoload no; dhcp; setenv options root=/dev/nfs rootfstype=nfs rootwait nfsroot=$rootpath ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:eth0:off'
fw_setenv nfs_load 'nfs $addr $rootpath/boot/$file'
#### jffs2 ####
fw_setenv jffs2_init 'setenv options root=/dev/mtdblock3 rootfstype=jffs2'
fw_setenv jffs2_load 'fsload $addr /boot/$file'
#### ubi ####
fw_setenv ubi_init 'ubi part nand0,2; ubifsmount rootfs; setenv options root=ubi0:rootfs rootfstype=ubifs ubi.mtd=2'
fw_setenv ubi_load 'ubifsload $addr /boot/$file'
#### load ####
fw_setenv load_fdt 'addr=0x700000; file=dts/kirkwood-${arcName}.dtb; if run ${dev}_load; then fdt_addr=0x700000; fdt addr ${fdt_addr}; fi'
fw_setenv load_uimage 'addr=0x800000; file=uImage; if run ${dev}_load; then uimage_addr=0x800000; fi'
fw_setenv load_zimage 'addr=0x800000; file=zImage; if run ${dev}_load; then zimage_addr=0x800000; fi'
fw_setenv load_uinitrd 'addr=0x1100000; file=uInitrd; if run ${dev}_load; then uinitrd_addr=0x1100000; else uinitrd_addr=-; fi'
fw_setenv set_bootargs 'setenv bootargs console=$console $nc_options $options $mtdparts'
#### boot ####
fw_setenv bootdelay '3'
fw_setenv mboot 'run ${dev}_init; run set_bootargs; echo ** mboot ${dev} -- $bootargs; mw 0x800000 0 1; if run load_uimage; then run load_uinitrd; bootm $uimage_addr $uinitrd_addr; fi'
fw_setenv zboot 'run ${dev}_init; run set_bootargs; echo ** zboot ${dev} -- $bootargs; mw 0x800000 0 1; if run load_fdt; then if run load_zimage; then run load_uinitrd; bootz $zimage_addr $uinitrd_addr $fdt_addr; fi; fi'
fw_setenv bootcmd 'for dev in $default ide usb mmc nfs jffs2 ubi; do if run zboot; then echo zboot success; else run mboot; fi; done; reset'
#### remove unwanted variables ####
fw_setenv device
fw_setenv partition
fw_setenv root

For at installere disse opdateringer pipes outputtet blot til en ny shell

sudo ./fw_setup.sh | sudo sh

Nu er u-Boot sat op til at boot i prioriteret rækkefølge fra “$default ide usb mmc nfs jffs2  ubi”

Så mangler vi blot at lave og formattere partion 1 på vores USB-stick/SD-card/SATA-disk og kopiere et Debian system derpå, dette kan foregå på en hvilken som helst Linux komputer

# med fdisk lave en partion af passende størrelse på /dev/sdb
# lav et filsystem:
mkfs.ext4 /dev/sdb1
# monter filsystemet:
mount /dev/sdb1 /mnt
# Hent Debian-3.17.0-kirkwood-tld-1-rootfs-bodhi.tar.bz2
# find den her: http://forum.doozan.com/read.php?2,12096
# pak det ud:
tar -C /mnt xvjf Debian-3.17.0-kirkwood-tld-1-rootfs-bodhi.tar.bz2
# /boot/zImage skal pege på den kerne vi vil bruge
ln -s zImage-3.17.0-kirkwood-tld-1 /mnt/boot/zImage
# og afmonter:
umount /mnt

Nu kan USB-sticken sættes i en PogoPlug og Den er klar til service.

Næste gang ser vi på hvordan man booter fra nettet:

This entry was posted in HomeAutomation, Linux. Bookmark the permalink.