#!/bin/sh

# Copyright (C) 2006  Joey Hess  <joeyh@debian.org>
# Copyright (C) 2006, 2007, 2008, 2009  Martin Michlmayr <tbm@cyrius.com>
# Copyright (C) 2009, 2010 Canonical Ltd

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
# USA.

set -e

error() {
	echo "$@" >&2
	exit 1
}

check_mtd() {
	if [ ! -e /proc/mtd ]; then
		error "/proc/mtd doesn't exist"
	fi
}

mtdblock() {
	grep "\"$1\"" /proc/mtd | cut -d: -f 1 | sed 's/mtd/\/dev\/mtdblock/'
}

check_dev_mtdblock() {
	if [ ! -b "$1" ]; then
		error "$1 is not a block device"
	fi
}

mtdsize() {
	size=$(grep "\"$1\"" /proc/mtd | cut -d " " -f 2)
	printf "%d" 0x$size
}

check_subarch() {
	if [ -n "$subarch" ] && [ "$subarch" != "$1" ]; then
		echo "Kernel $kfile does not match your subarchitecture" >&2
		echo "$1, therefore not writing it to flash." >&2
		exit 0
	fi
}

check_size() {
	if [ $2 -gt $3 ]; then
		error "The $1 doesn't fit in flash."
	fi
}

check_fis() {
	if ! fis -d "$1" -o "$2" -s "$3" list >/dev/null; then
		error "fis list failed on device $1 at offset $2 with size $3"
	fi
}

# returns addr, size, and entry in hex, space separated; e.g. for the kernel
# partition, when fis list would return:
#          kernel: addr = 0x00060000, size = 0x00400000, entry = 0x00100000, \
#          length = 0x002144c0, cksum = 0xe9909335
# this function outputs:
# 00060000 00400000 00100000
fis_info() {
	LC_ALL=C fis -d "$1" -o "$2" -s "$3" list | sed -rn "s/^[[:space:]]*$4: addr = 0x([0-9a-f]{8}), size = 0x([0-9a-f]{8}), entry = 0x([0-9a-f]{8}), length = 0x[0-9a-f]{8}, cksum = 0x[0-9a-f]{8}\$/\1 \2 \3/p"
}

# pass fis_info output in args and outputs the decimal offset
fis_offset() {
	printf %d 0x$1
}

# pass fis_info output in args and outputs the decimal size
fis_size() {
	printf %d 0x$2
}

# pass fis_info output in args and outputs the decimal entry point
fis_entry() {
	printf %d 0x$3
}


# See http://www.nslu2-linux.org/wiki/Info/BootFlash -- the NSLU2 uses a
# 16 byte MTD header, the first four bytes (big endian) give the length of
# the remainder of the image, and the remaining bytes are zero.  Generate
# this header.
sercomm_header() {
	perl -e 'print pack("N4", shift)' "$1"
}

nslu2_swap() {
	if [ "$little_endian" ]; then
		devio "<<$1" "xp $,4"
	else
		cat "$1"
	fi
}

# list of functions to call on cleanup
cleanup_funcs=""
cleanup() {
	for f in $cleanup_funcs; do
		$f
	done
}

# generic flash-kernel routines for specific subarchs

omap_flash_kernel_and_initrd() {
	printf "Creating backups of boot files ... " >&2
	if [ -e $TMPMOUNT/uImage ]; then
		cp $TMPMOUNT/uImage $TMPMOUNT/uImage.bak
	fi
	if [ -e $TMPMOUNT/uInitrd ]; then
		cp $TMPMOUNT/uInitrd $TMPMOUNT/uInitrd.bak
	fi
	if [ -e $TMPMOUNT/boot.scr ]; then
		cp $TMPMOUNT/boot.scr $TMPMOUNT/boot.scr.bak
	fi

	echo "done." >&2
	printf "Generating kernel u-boot image... " >&2
	mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
		-e 0x80008000 -n "Ubuntu Kernel" -d $kfile $TMPMOUNT/uImage >&2 1>/dev/null
	echo "done." >&2
	printf "Generating Initramfs u-boot image... " >&2
	mkimage -A arm -O linux -T ramdisk -C none -a 0x0 -e 0x0 \
		-n "Ubuntu Initrd" -d $ifile $TMPMOUNT/uInitrd >&2 1>/dev/null
		echo "done." >&2
	if [ -e /boot/boot.script ];then
		printf "Generating u-boot configuration from /boot/boot.script... " >&2
		mkimage -A arm -T script -C none -n "Ubuntu boot script" -d /boot/boot.script \
			$TMPMOUNT/boot.scr >&2 1>/dev/null
		echo "done." >&2
	fi
}

omap_flash_bootloader() {
	case "$machine" in
		"IGEP v2 board")
			XLOADERDIR=x-loader/igep0020
			UBOOTDIR=igep0020
		;;
		"OMAP3 Beagle Board")
			XLOADERDIR=u-boot/omap3_beagle
			UBOOTDIR=omap3_beagle
		;;
		"OMAP4430 Panda Board" | "OMAP4 Panda board")
			XLOADERDIR=u-boot/omap4_panda
			UBOOTDIR=omap4_panda
		;;
		*)
			error "Bootloader update not supported on $machine."
		;;
	esac

	XLOADER=/usr/lib/$XLOADERDIR/MLO
	UBOOT=/usr/lib/u-boot/$UBOOTDIR/u-boot.bin

	# Ensure that the input files EXIST
	if [ ! -e "$XLOADER" ]; then
		error "$XLOADER doesn't exist. Make sure proper x-loader package is installed"
	fi
	if [ ! -e "$UBOOT" ]; then
		error "$UBOOT doesn't exist. Make sure proper u-boot package is installed"
	fi
	if [ -z "$BOOTLOADER_FILES" ];then
		BOOTLOADER_FILES="$XLOADER $UBOOT"
	fi

	for f in $BOOTLOADER_FILES;do
		F=$(basename $f)
		#Check whether the file is already written to the boot partition
		S1=$(md5sum $f 2>/dev/null|cut -f1 -d\ )
		S2=$(md5sum $TMPMOUNT/$F 2>/dev/null|cut -f1 -d\ )
		if [ "$S1" != "$S2" ];then
			if [ -e $TMPMOUNT/$F ];then
				mv -f $TMPMOUNT/$F $TMPMOUNT/$F.bak
			fi
			cp $f $TMPMOUNT/
			echo $f copied to the boot partition. >&2
		else
			echo $f is already installed in the boot partition. >&2
		fi
	done
}

omap_flash_kernel() {
	if [ -n "${UBOOT_PART}" ]; then
		echo "Using u-boot partition: ${UBOOT_PART}" >&2
		TMPMOUNT=$(mktemp -d)
		mount $UBOOT_PART $TMPMOUNT

		if [ -n "$UPDATE_BOOTLOADER" ];then
			omap_flash_bootloader
		fi

		omap_flash_kernel_and_initrd

		umount -l $TMPMOUNT
		rm -rf $TMPMOUNT
	else
		initrd_nand_size="16777216"
		check_mtd
		kmtd=$(mtdblock "Kernel")
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'Kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "Kernel")
		check_size "Kernel" $(($kfilesize + 8 + 64)) $kmtdsize

		printf "Generating kernel u-boot image... " >&2
		tmp=$(tempfile)
		cat $kfile >> $tmp
		mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
			-e 0x80008000 -n "Ubuntu Kernel" -d $tmp $tmp.uboot >&2 1>/dev/null
		echo "done." >&2

		printf "Erasing Kernel NAND space... " >&2
		dd if=/dev/zero of=$kmtd bs=$kmtdsize count=1 2>/dev/null
		echo "done." >&2

		printf "Flashing kernel... " >&2
		cat $tmp.uboot > $kmtd || error "failed."
		echo "done." >&2
		rm -f $tmp.uboot $tmp

		imtd=$(mtdblock "File System")
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition for Initramfs"
		fi
		check_dev_mtdblock "$imtd"
		check_size "Initramfs" $ifilesize $initrd_nand_size

		printf "Generating Initramfs u-boot image... " >&2
		tmp=$(tempfile)
		cat $ifile >> $tmp
		mkimage -A arm -O linux -T ramdisk -C none -a 0x0 -e 0x0 \
			-n "Ubuntu Initrd" -d $tmp $tmp.uboot >&2 1>/dev/null
		echo "done." >&2

		printf "Erasing Initramfs NAND space... " >&2
		dd if=/dev/zero of=$imtd bs=$initrd_nand_size count=1 2>/dev/null
			echo "done." >&2

		printf "Flashing Initramfs... " >&2
		cat $tmp.uboot > $imtd || error "failed."
		echo "done." >&2
		rm -f $tmp.uboot $tmp
	fi
}

dove_flash_kernel() {
	tmp=$(tempfile)
	case $subarch in
		"dove")
			uboot_kernel_load_addr=0x00200000
			uboot_initramfs_load_addr=0x01100000
			script_load_addr=0x1000
			;;
		"armadaxp")
			uboot_kernel_load_addr=0x02000000
			uboot_initramfs_load_addr=0x20000000
			script_load_addr=0x1000
			;;
	esac
	printf "Generating kernel u-boot image... " >&2
	cat $kfile >> $tmp
	mkimage -A arm -O linux -T kernel -C none -n "$desc" -a 0x00008000 \
		-e 0x00008000 -d $tmp $tmp.uboot >&2 1>/dev/null
	echo "done." >&2
	if [ -e /boot/uImage ]; then
		echo "Creating backup of /boot/uImage." >&2
		mv /boot/uImage /boot/uImage.bak
	fi
	echo "Creating new /boot/uImage." >&2
	mv $tmp.uboot /boot/uImage
	rm -f $tmp
	printf "Generating initrd u-boot image... " >&2
	mkimage -A arm -O linux -T ramdisk -C gzip -a 0x0 \
		-e 0x0 -n "$idesc" -d "$ifile" "$tmp.uboot" >&2 1>/dev/null
	echo "done." >&2
	if [ -e /boot/uInitrd ]; then
		echo "Creating backup of /boot/uInitrd." >&2
		mv /boot/uInitrd /boot/uInitrd.bak
	fi
	echo "Creating new /boot/uInitrd." >&2
	mv "$tmp.uboot" /boot/uInitrd
	rm -f "$tmp.uboot"
	if [ -z "$script_load_addr" ]; then
		return
	fi
	printf "Generating new u-boot boot script..." >&2
	# The UUID will come from the flash-kernel config file
	cat >"$tmp.boot.script" <<EOF
echo Starting Ubuntu...
if test -n \${fs} && test -n \${interface} && test -n \${device} && test -n \${prefix}; then
	\${fs}load \${interface} \${device} $uboot_kernel_load_addr \${prefix}uImage
	\${fs}load \${interface} \${device} $uboot_initramfs_load_addr \${prefix}uInitrd
	setenv bootargs $rootfs ro quiet splash
	bootm $uboot_kernel_load_addr $uboot_initramfs_load_addr
fi

echo boot information not recieved from u-boot, scanning for startup device

if test -e \${reinitalize_devices}; then
	usb start;
	ide reset;
fi

for i in usb ide; do
	for j in 0 1; do
		for l in / /boot/; do
			for m in fat ext2; do
				setenv interface \$i;
				setenv device \$j;
				setenv prefix \$l;
				setenv fs \$m;

				echo Scanning \${fs} \${interface} \${device} on prefix \${prefix} ...;

				# This "if" avoids loading an old image but
				# doesn't work in stock u-boot 1.3.4 and is
				# only fixed in Canonical u-boot from October
				# 1st or later

				if \${fs}load \${interface} \${device} $script_load_addr \${prefix}boot.scr; then
					if imi $script_load_addr; then
						echo boot.scr found! Executing ...;
						autoscr $script_load_addr;
					fi;
				fi
			done;
		done;
	done;
done
echo No boot device found.;
EOF
	mkimage -A arm -T script -C none -n "Ubuntu boot script" -d "$tmp.boot.script" \
		"$tmp.boot.scr" >&2 1>/dev/null
	echo "done." >&2
	if [ -e /boot/boot.scr ]; then
		echo "Creating backup of /boot/boot.scr." >&2
		mv /boot/boot.scr /boot/boot.scr.bak
	fi
	echo "Creating new /boot/boot.scr." >&2
	mv "$tmp.boot.scr" /boot/boot.scr
	rm -f "$tmp.boot.script" "$tmp.boot.scr"
}

highbank_setup_dtb() {
	dtbvers=$(echo "$kfile" | sed -e 's/[^-]*-//')
	dtbdest="/boot/highbank.dtb"
	dtbsrc="/boot/highbank.dtb-$dtbvers"

	test -e "$dtbsrc" || return
	if [ -e "$dtbdest" ]; then
		mv "$dtbdest" "$dtbdest.bak"
	fi
	printf "Generating device tree dtb... " >&2
	cp "$dtbsrc" "$dtbdest"
	echo "done." >&2
}

highbank_flash_kernel() {
	if [ -e /boot/boot.script ];then
		cp /boot/boot.scr /boot/boot.scr.bak
		printf "Generating u-boot configuration from /boot/boot.script... " >&2
		mkimage -A arm -T script -C none -n "Ubuntu boot script" -d /boot/boot.script \
			/boot/boot.scr >&2 1>/dev/null
		echo "done." >&2
	else
		cat >"/boot/boot.script" <<EOF
echo Starting Ubuntu...
setenv bootargs console=ttyAMA0 $rootfs nosplash
mw.l 800000 0 10000
scsi scan
ext2load scsi 0 0x800000 vmlinuz
ext2load scsi 0 0x1000000 initrd.img
bootz 0x800000 0x1000000:\${filesize} 0x1000
EOF
	printf "Generating u-boot config for highbank... " >&2
	mkimage -A arm -T script -C none -n "Ubuntu boot script" -d /boot/boot.script \
		/boot/boot.scr >&2 1>/dev/null
	echo "done." >&2
	fi
}

efikamx_flash_kernel() {
	tmp=$(tempfile)
	printf "Generating kernel u-boot image... " >&2
	mkimage -A arm -O linux -T kernel -C none -a 0x90008000 \
		-e 0x90008000 -d $kfile $tmp.uboot >&2 1>/dev/null
	echo "done." >&2

	if [ -e /boot/uImage ]; then
		mv /boot/uImage /boot/uImage.bak
	fi
	mv $tmp.uboot /boot/uImage

	if [ -e /boot/uInitrd ]; then
		printf "Generating initrd u-boot image... " >&2
		mkimage -A arm -O linux -T ramdisk -C gzip -a 0x0 \
			-e 0x0 -n "$idesc" -d "$ifile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		mv /boot/uInitrd /boot/uInitrd.bak
		echo "Creating new /boot/uInitrd." >&2
		mv "$tmp.uboot" /boot/uInitrd
		rm -f "$tmp.uboot"
	fi

	if [ -e /boot/boot.script ];then
		cp /boot/boot.scr /boot/boot.scr.bak
		printf "Generating u-boot configuration from /boot/boot.script... " >&2
		mkimage -A arm -T script -C none -n "Ubuntu boot script" -d /boot/boot.script \
			/boot/boot.scr >&2 1>/dev/null
		echo "done." >&2
	fi
	rm -f "$tmp"
}

imx_update_dtb() {
	model=""
	if [ -e /proc/device-tree/model ]; then
		model=$(cat /proc/device-tree/model)
	fi
	dtbvers=$(echo "$kfile" | sed -e 's/[^-]*-//')
	case "$model" in
		"Freescale i.MX6 Quad SABRE Lite Board")
			dtbfile=/boot/dt-$dtbvers/imx6q-sabrelite.dtb
		;;
		"Freescale i.MX6 Quad Armadillo2 Board")
			dtbfile=/boot/dt-$dtbvers/imx6q-arm2.dtb
		;;
		*)
			dtbfile=""
		;;
	esac
	if [ -e "$dtbfile" ]; then
		if [ -e $TMPMOUNT/board.dtb ]; then 
			mv $TMPMOUNT/board.dtb $TMPMOUNT/board.dtb.bak
		fi
		printf "Generating device tree dtb... " >&2
		cp "$dtbfile" $TMPMOUNT/board.dtb
		echo "done." >&2
	fi
}

imx_flash_kernel() {
	echo "Using u-boot partition: ${UBOOT_PART}" >&2
	TMPMOUNT=$(mktemp -d)
	mount $UBOOT_PART $TMPMOUNT
	tmp=$(tempfile)
	printf "Generating kernel u-boot image... " >&2
	mkimage -A arm -O linux -T kernel -C none -a $IMX_KERNEL_ADDR \
		-e $IMX_KERNEL_ADDR -d $kfile $tmp >&2 1>/dev/null
	echo "done." >&2

	if [ -e $TMPMOUNT/uImage ]; then
		mv $TMPMOUNT/uImage $TMPMOUNT/uImage.bak
	fi
	cp $tmp $TMPMOUNT/uImage
	rm -f $tmp

	tmp=$(tempfile)
	printf "Generating initrd u-boot image... " >&2
	mkimage -A arm -O linux -T ramdisk -C gzip -a 0x0 \
		-e 0x0 -n "$idesc" -d "$ifile" "$tmp" >&2 1>/dev/null
	echo "done." >&2
	if [ -e $TMPMOUNT/uInitrd ]; then
		mv $TMPMOUNT/uInitrd $TMPMOUNT/uInitrd.bak
	fi
	cp "$tmp" $TMPMOUNT/uInitrd
	rm -f "$tmp"

	if [ -e /boot/boot.script ];then
		if [ -e $TMPMOUNT/boot.scr ]; then
			mv $TMPMOUNT/boot.scr $TMPMOUNT/boot.scr.bak
		fi
		printf "Generating u-boot configuration from /boot/boot.script... " >&2
		mkimage -A arm -T script -C none -n "Ubuntu boot script" -d /boot/boot.script \
			$TMPMOUNT/boot.scr >&2 1>/dev/null
		echo "done." >&2
	fi

	imx_update_dtb

	umount -l $TMPMOUNT
	rmdir $TMPMOUNT
}


trap "cleanup" 0 HUP INT QUIT KILL SEGV PIPE TERM

config="/etc/flash-kernel.conf"
if [ -r "$config" ]; then
	. "$config"
fi

if [ "x$1" = "x--machine" ]; then
	machine=$2
	shift 2
else
	machine=$(grep "^Hardware" /proc/cpuinfo | sed 's/Hardware\s*:\s*//')
fi

running_subarch=$(uname -r | sed -e 's/.*-//')

if [ "x$1" = "x--supported" ]; then
	# if FLASH_KERNEL_SKIP is set, its always unsupported
	if [ -n "$FLASH_KERNEL_SKIP" ]; then
		exit 1
	fi

	case "$machine" in
		"ARM-Versatile Express CA9x4")		exit 0 ;;
		"Buffalo Linkstation Pro/Live")		exit 0 ;;
		"Buffalo/Revogear Kurobox Pro")		exit 0 ;;
		"D-Link DNS-323")			exit 0 ;;
		"Freescale MX51 Babbage Board")		exit 0 ;;
		"Freescale MX53 LOCO Board")		exit 0 ;;
		"Freescale i.MX6 Quad (Device Tree)")	exit 0 ;;
		"GLAN Tank")				exit 0 ;;
		"Genesi Efika MX (Smartbook)")		exit 0 ;;
		"Genesi Efika MX (Smarttop)")		exit 0 ;;
		"Highbank")				exit 0 ;;
		"HP Media Vault mv2120")		exit 0 ;;
		"IGEP v2 board")			exit 0 ;;
		"Linksys NSLU2")			exit 0 ;;
		"OMAP3 Beagle Board")			exit 0 ;;
		"OMAP4430 Panda Board" | "OMAP4 Panda board")	exit 0 ;;
		"OMAP4430 4430SDP board")		exit 0 ;;
		"Marvell OpenRD Base Board")		exit 0 ;;
		"Marvell OpenRD Client Board")		exit 0 ;;
		"Marvell SheevaPlug Reference Board")	exit 0 ;;
		"Marvell eSATA SheevaPlug Reference Board")	exit 0 ;;
		"Marvell DB-MV88F6781-BP Development Board") exit 0 ;;
		"Marvell Armada XP Development Board") exit 0 ;;
		"QNAP TS-109/TS-209" | "QNAP TS-409")	exit 0 ;;
		"QNAP TS-119/TS-219")			exit 0 ;;
		"QNAP TS-41x")				exit 0 ;;
		"Thecus N2100")				exit 0 ;;
		"Toshiba AC100 / Dynabook AZ")			exit 0 ;;
		"Lanner EM7210")			exit 0 ;;
		*)
			# we're supported if we have a generic fallback
			case "$running_subarch" in
				"armadaxp" | "dove" | "highbank" | "omap" | "omap4") exit 0 ;;
			esac
		exit 1
		;;
	esac
fi

if [ -n "$FLASH_KERNEL_SKIP" ]; then
	exit 0
fi

if [ "x$1" = "x--update-bootloader" ]; then
	UPDATE_BOOTLOADER=y
	shift
	BOOTLOADER_FILES=$@
	shift $#
fi

if [ -n "$1" ]; then
	kvers="$1"
	kfile=/boot/vmlinuz-$kvers
	ifile=/boot/initrd.img-$kvers
	desc="Ubuntu kernel $1"
	idesc="Ubuntu ramdisk $1"
else
	if [ -e /vmlinuz ]; then
		kfile=/vmlinuz
		ifile=/initrd.img
	elif [ -e /boot/vmlinuz ]; then
		kfile=/boot/vmlinuz
		ifile=/boot/initrd.img
	else
		error "Cannot find a default kernel in /vmlinuz or /boot/vmlinuz"
	fi
	desc="Debian kernel"
	idesc="Debian ramdisk"
fi

if [ ! -e $kfile ] || [ ! -e $ifile ]; then
	error "Can't find $kfile and $ifile"
fi
kfilesize=$(wc -c "$kfile" | awk '{print $1}')
ifilesize=$(wc -c "$ifile" | awk '{print $1}')

# Extract the subarchitecture from the kernel name
if [ -L "$kfile" ]; then
	kfile=$(readlink -e "$kfile")
fi
subarch=$(echo "$kfile" | sed -e 's/.*-//')

case "$machine" in
	"ARM-Versatile Express CA9x4")
		check_subarch "vexpress"
		check_mtd

		kmtd=$(mtdblock "kernel")
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "kernel")
		check_size "kernel" $(($kfilesize + 64)) $kmtdsize
		printf "Generating a u-boot compatible kernel image... " >&2
		mkimage -A arm -O linux -T kernel -C none -a 0x60008000 \
			-e 0x60008000 -n "$desc" -d $kfile $kfile.uboot \
			>&2 1>/dev/null
		printf "Writing kernel to flash... " >&2
		cat $kfile.uboot > $kmtd || error "failed."
		echo "done." >&2
		rm -f $kfile.uboot

		imtd=$(mtdblock "initrd")
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition for initrd"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "initrd")
		check_size "initrd" $ifilesize $imtdsize
		printf "Generating u-boot compatible initrd image... " >&2
		mkimage -A arm -O linux -T ramdisk -C none -a 0x81000000 \
			-e 0x81000000 -n "$idesc" -d $ifile $ifile.uboot \
			>&2 1>/dev/null
		printf "Writing initrd to flash... " >&2
		cat $ifile.uboot > $imtd || error "failed."
		echo "done." >&2
		rm -f $ifile.uboot
	;;
	"Buffalo Linkstation Pro/Live" | "Buffalo/Revogear Kurobox Pro")
		check_subarch "orion5x"
		tmp="$(tempfile)"
		printf "Generating kernel u-boot image... " >&2
		case "$machine" in
			"Buffalo Linkstation Pro/Live")
				# Set machine id 1585 (0x0631)
				devio > "$tmp" 'wl 0xe3a01c06,4' 'wl 0xe3811031,4'
			;;
			"Buffalo/Revogear Kurobox Pro")
				# Set machine id 1509 (0x05e5)
				devio > "$tmp" 'wl 0xe3a01c05,4' 'wl 0xe38110e5,4'
			;;
		esac
		cat "$kfile" >> "$tmp"
		mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
			-e 0x00008000 -n "$desc" -d "$tmp" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		if [ -e /boot/uImage.buffalo ]; then
			echo "Creating backup of /boot/uImage.buffalo." >&2
			mv /boot/uImage.buffalo /boot/uImage.buffalo.bak
		fi
		echo "Creating new /boot/uImage.buffalo." >&2
		mv "$tmp.uboot" /boot/uImage.buffalo
		rm -f "$tmp"
		printf "Generating initrd u-boot image... " >&2
		mkimage -A arm -O linux -T ramdisk -C gzip -a 0x0 \
			-e 0x0 -n "$idesc" -d "$ifile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		if [ -e /boot/initrd.buffalo ]; then
			echo "Creating backup of /boot/initrd.buffalo." >&2
			mv /boot/initrd.buffalo /boot/initrd.buffalo.bak
		fi
		echo "Creating new /boot/initrd.buffalo." >&2
		mv "$tmp.uboot" /boot/initrd.buffalo
	;;
	"D-Link DNS-323")
		check_subarch "orion5x"
		check_mtd
		imtd=$(mtdblock "File System")
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition 'File System'"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "File System")
		check_size "File System" $((ifilesize + 64)) $imtdsize
		kmtd=$(mtdblock "Linux Kernel")
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'Linux Kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "Linux Kernel")
		check_size "Linux Kernel" $(($kfilesize + 8 + 64)) $kmtdsize
		printf "Generating kernel u-boot image... " >&2
		tmp="$(tempfile)"
		# Set machine id 1542 (0x0606)
		devio > "$tmp" 'wl 0xe3a01c06,4' 'wl 0xe3811006,4'
		cat "$kfile" >> "$tmp"
		mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
			-e 0x00008000 -n "$desc" -d "$tmp" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		printf "Flashing kernel... " >&2
		cat "$tmp.uboot" > "$kmtd" || error "failed."
		echo "done." >&2
		rm -f "$tmp.uboot" "$tmp"
		printf "Generating initramfs u-boot image... " >&2
		mkimage -A arm -O linux -T ramdisk -C gzip -a 0x00800000 \
			-e 0x00800000 -n "$idesc" -d "$ifile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		printf "Flashing initramfs... " >&2
		cat "$tmp.uboot" > "$imtd" || error "failed."
		echo "done." >&2
		rm -f "$tmp.uboot"
	;;
	"Freescale MX51 Babbage Board")
		case $subarch in
			"mx5"|"mx51")
				:
				if [ -n "${UBOOT_PART}" ]; then
					UBOOT_PART=/dev/mmcblk0p1
				fi
			;;
			*)
				# Not actually the real expected kfile
				# subarch, but will raise a sensible error
				check_subarch "mx5 or mx51"
			;;
		esac
		IMX_KERNEL_ADDR=0x90008000
		imx_flash_kernel
	;;
	"Freescale MX53 LOCO Board")
		check_subarch "mx5"
		IMX_KERNEL_ADDR=0x70008000
		imx_flash_kernel
	;;
	"Freescale i.MX6 Quad (Device Tree)")
		check_subarch "mx6"
		IMX_KERNEL_ADDR=0x10008000
		imx_flash_kernel
	;;
	"GLAN Tank")
		rm -f /boot/initrd /boot/zImage
		ln -s "$(basename "$ifile")" /boot/initrd
		(
			# Set machine id 1100 (0x044c)
			devio 'wl 0xe3a01c04,4' 'wl 0xe381104c,4'
			cat "$kfile"
		) > /boot/zImage
	;;
	"Highbank")
		highbank_flash_kernel
	;;
	"HP Media Vault mv2120")
		check_subarch "orion5x"
		tmp="$(tempfile)"
		printf "Generating kernel u-boot image... " >&2
		# Set machine id 1693 (0x069d)
		devio > "$tmp" 'wl 0xe3a01c06,4' 'wl 0xe381109d,4'
		cat "$kfile" >> "$tmp"
		mkimage -A arm -O linux -T multi -C none -n "$desc" -a 0x01000000 \
			-e 0x01000000 -d "$tmp:$ifile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		if [ -e /boot/uImage ]; then
			echo "Creating backup of /boot/uImage." >&2
			mv /boot/uImage /boot/uImage.bak
		fi
		echo "Creating new /boot/uImage." >&2
		mv "$tmp.uboot" /boot/uImage
		rm -f "$tmp"
	;;
	"Linksys NSLU2")
		check_subarch "ixp4xx"
		case "$(dpkg --print-architecture)" in
			arm|armel)
				little_endian=1
			;;
			armeb)
				little_endian=0
			;;
		esac
		check_mtd
		fismtd=$(mtdblock "FIS directory")
		if [ -z "$fismtd" ]; then
			error "Cannot find mtd FIS directory"
		fi
		kmtd=$(mtdblock Kernel)
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'Kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "Kernel")
		check_size "kernel" $(($kfilesize + 16 + 16)) $kmtdsize
		imtd=$(mtdblock Ramdisk)
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition 'Ramdisk'"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "Ramdisk")
		check_size "ramdisk" $(($ifilesize + 16)) $imtdsize
		# The following devio magic parses the FIS directory to
		# obtain the size, offset and name of each partition.  This
		# used used to obtain the offset of the Kernel partition.
		offset=$(echo "$(devio "<<$fismtd" '
			<= $ 0x20000 -
			L= 0x1000
			$( 1
				# 0xff byte in name[0] ends the partition table
				$? @ 255 =
				# output size base name
				<= f15+
				.= b 0xfffffff &
				<= f4+
				.= b
				pf "%lu %lu "
				<= f28-
				cp 16
				pn
				<= f240+
				L= L256-
			$) L255>')" |
			while read a b c; do
				if [ "$c" = "Kernel" ]; then
					echo $b
				fi
			done)
		# The Kernel partition, starting at $offset, is divided into
		# two areas at $boundary.  We therefore need to split the
		# kernel into two and write them to flash with two Sercomm
		# headers.
		boundary=1441792 # 0x00160000
		ksize1=$(expr $boundary - $offset - 16)
		tmp="$(tempfile)"
		printf "Flashing kernel: " >&2
		(
			sercomm_header $(expr $kfilesize + 16)
			dd if="$kfile" of="$tmp" bs=$ksize1 count=1 2>/dev/null
			nslu2_swap "$tmp"
			sercomm_header 131072
			dd if="$kfile" of="$tmp" ibs=$ksize1 skip=1 2>/dev/null
			nslu2_swap "$tmp"
			rm -f "$tmp"
		) > "$kmtd" || error "failed."
		echo "done." >&2
		printf "Flashing initramfs: " >&2
		dd if="$ifile" of="$tmp" ibs=$(($imtdsize - 16)) conv=sync 2>/dev/null
		(
			sercomm_header $ifilesize
			nslu2_swap "$tmp"
			rm -f "$tmp"
		) > "$imtd" || error "failed."
		echo "done." >&2
	;;
	"Marvell OpenRD Base Board" | "Marvell OpenRD Client Board" | "Marvell SheevaPlug Reference Board" | "Marvell eSATA SheevaPlug Reference Board")
		check_subarch "kirkwood"
		tmp="$(tempfile)"
		printf "Generating kernel u-boot image... " >&2
		mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
			-e 0x00008000 -n "$desc" -d "$kfile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		if [ -e /boot/uImage ]; then
			echo "Creating backup of /boot/uImage." >&2
			mv /boot/uImage /boot/uImage.bak
		fi
		echo "Creating new /boot/uImage." >&2
		mv "$tmp.uboot" /boot/uImage
		printf "Generating initrd u-boot image... " >&2
		mkimage -A arm -O linux -T ramdisk -C gzip -a 0x0 \
			-e 0x0 -n "$idesc" -d "$ifile" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		if [ -e /boot/uInitrd ]; then
			echo "Creating backup of /boot/uInitrd." >&2
			mv /boot/uInitrd /boot/uInitrd.bak
		fi
		echo "Creating new /boot/uInitrd." >&2
		mv "$tmp.uboot" /boot/uInitrd
		rm -f "$tmp"
	;;
	"Marvell DB-MV88F6781-BP Development Board")
		check_subarch "dove"
		dove_flash_kernel
	;;
	"Marvell Armada XP Development Board")
		check_subarch "armadaxp"
		dove_flash_kernel
	;;
	"IGEP v2 board" | "OMAP3 Beagle Board" | "OMAP4430 4430SDP board" | "OMAP4430 Panda Board" | "OMAP4 Panda board")
		case "$machine" in
			"IGEP v2 board"|"OMAP3 Beagle Board")
				check_subarch "omap"
			;;
			"OMAP4430 Panda Board" | "OMAP4 Panda board")
				# Linaro uses the same omap kernel for OMAP 3 and 4
				if [ `expr "$kfile" : '.*linaro.*-omap$'` -ne 0 ]; then
				        check_subarch "omap"
				else
				        check_subarch "omap4"
				fi
				if [ -z "${UBOOT_PART}" ]; then
					export UBOOT_PART=/dev/mmcblk0p1
				fi
			;;
			"OMAP4430 4430SDP board") 
				# Linaro uses the same omap kernel for OMAP 3 and 4
				if [ `expr "$kfile" : '.*linaro.*-omap$'` -ne 0 ]; then
				        check_subarch "omap"
				else
				        check_subarch "omap4"
				fi
				if [ -z "${UBOOT_PART}" ]; then
					export UBOOT_PART=/dev/mmcblk1p1
				fi
		esac
		omap_flash_kernel
	;;
	"QNAP TS-109/TS-209" | "QNAP TS-119/TS-219" | "QNAP TS-409" | "QNAP TS-41x")
		case "$machine" in
			"QNAP TS-109/TS-209" | "QNAP TS-409")
				check_subarch "orion5x"
			;;
			"QNAP TS-119/TS-219" | "QNAP TS-41x")
				check_subarch "kirkwood"
			;;
		esac
		check_mtd
		imtd=$(mtdblock "RootFS1")
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition 'RootFS1'"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "RootFS1")
		check_size "RootFS1" $ifilesize $imtdsize
		kmtd=$(mtdblock Kernel)
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'Kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "Kernel")
		check_size "Kernel" $(($kfilesize + 8 + 64)) $kmtdsize
		printf "Generating kernel u-boot image... " >&2
		tmp="$(tempfile)"
		case "$machine" in
			"QNAP TS-109/TS-209")
				# Set machine id 1565 (0x061d)
				devio > "$tmp" 'wl 0xe3a01c06,4' 'wl 0xe381101d,4'
			;;
			"QNAP TS-119/TS-219")
				# Set machine id 2139 (0x085b)
				devio > "$tmp" 'wl 0xe3a01c08,4' 'wl 0xe381105b,4'
			;;
			"QNAP TS-409")
				# Set machine id 1601 (0x0641)
				devio > "$tmp" 'wl 0xe3a01c06,4' 'wl 0xe3811041,4'
			;;
			"QNAP TS-41x")
				# Set machine id 2502 (0x09c6)
				devio > "$tmp" 'wl 0xe3a01c09,4' 'wl 0xe38110c6,4'
			;;
		esac
		cat "$kfile" >> "$tmp"
		mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
			-e 0x00008000 -n "$desc" -d "$tmp" "$tmp.uboot" >&2 1>/dev/null
		echo "done." >&2
		printf "Flashing kernel... " >&2
		cat "$tmp.uboot" > "$kmtd" || error "failed."
		echo "done." >&2
		rm -f "$tmp.uboot" "$tmp"
		printf "Flashing initramfs... " >&2
		pad=$(expr $imtdsize - $ifilesize)
		(
			cat "$ifile"
			dd if=/dev/zero bs=$pad count=1 2>/dev/null
		) > "$imtd" || error "failed."
		echo "done." >&2
	;;
	"Thecus N2100")
		check_subarch "iop32x"
		check_mtd
		imtd=$(mtdblock ramdisk)
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition 'ramdisk'"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "ramdisk")
		check_size "ramdisk" $ifilesize $imtdsize
		kmtd=$(mtdblock kernel)
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'kernel'"
		fi
		check_dev_mtdblock "$kmtd"
		kmtdsize=$(mtdsize "kernel")
		check_size "kernel" $(($kfilesize + 8)) $kmtdsize
		printf "Flashing kernel... " >&2
		(
			# Set machine id 1101 (0x044d)
			devio 'wl 0xe3a01c04,4' 'wl 0xe381104d,4'
			cat "$kfile"
		) > "$kmtd" || error "failed."
		echo "done." >&2
		printf "Flashing initramfs... " >&2
		pad=$(expr $imtdsize - $ifilesize)
		(
			cat "$ifile"
			dd if=/dev/zero bs=$pad count=1 2>/dev/null
		) > "$imtd" || error "failed."
		echo "done." >&2
	;;
	"Toshiba AC100 / Dynabook AZ")
		AC_IMG=""
		AC_SIZE=""
		AC_MMC="/dev/mmcblk0"

		TMPIMAGE=$(tempfile)
		CONFIG=""

		find_ac100_bootpart()
		{
			for dev in $(ls ${AC_MMC}?? 2>/dev/null); do
				if abootimg -i $dev >/dev/null 2>&1; then
					size=$(abootimg -i $dev |grep "image size"|cut -d ' ' -f5)
					 if [ $size -gt 5242880 ]; then
						 AC_IMG=$dev
						 AC_SIZE=$size
						 return 0
					 fi
				fi
			done
			return 1
		}

		build_ac100_bootimage()
		{
			if [ -e /boot/bootimg.cfg ]; then
				abootimg --create $TMPIMAGE -f /boot/bootimg.cfg -k $kfile \
					-r $ifile >/dev/null 2>&1 || return 1
				imagesize=$(wc -c "$TMPIMAGE" | awk '{print $1}')
				check_size "Bootimage" $imagesize $AC_SIZE
			else
				printf "Could not find /boot/bootimg.cfg."
				return 1
			fi
		}

		write_ac100_bootimage()
		{
			printf "Writing boot image to $AC_IMG ... "
			dd if=$TMPIMAGE of=$AC_IMG >/dev/null 2>&1 || return 1
			echo "done." >&2
		}

		if ! find_ac100_bootpart; then
			rm -rf $TMPIMAGE
			error "Could not find boot image partition on $AC_MMC."
		fi

		if ! build_ac100_bootimage; then
			rm -rf $TMPIMAGE
			error "Could not create temporary boot image."
		fi

		if ! write_ac100_bootimage; then
			rm -rf $TMPIMAGE
			error "Can not flash to $AC_IMG"
		fi

		rm -rf $TMPIMAGE
	;;
	"Lanner EM7210")
		# Really: Intel SS4000-e and compatibles
		check_subarch "iop32x"
		check_mtd
		imtd=$(mtdblock "ramdisk.gz")
		if [ -z "$imtd" ]; then
			error "Cannot find mtd partition 'ramdisk.gz'"
		fi
		check_dev_mtdblock "$imtd"
		imtdsize=$(mtdsize "ramdisk.gz")
		check_size "ramdisk" $ifilesize $imtdsize
		kmtd=$(mtdblock zImage)
		if [ -z "$kmtd" ]; then
			error "Cannot find mtd partition 'zImage'"
		fi
		kmtdsize=$(mtdsize "zImage")
		check_size "zImage" $(($kfilesize + 8)) $kmtdsize
		printf "Flashing kernel..." >&2
		(
			# Set machine ID 1212 (0x04bc)
			devio 'wl 0xe3a01c04,4' 'wl 0xe38110bc,4'
			cat "$kfile"
		) > "$kmtd" || error "failed."
		echo "done." >&2
		printf "Flashing initramfs... " >&2
		pad=$(expr $imtdsize - $ifilesize)
		(
			cat "$ifile"
			dd if=/dev/zero bs=$pad count=1 2>/dev/null
		) > "$imtd" || error "failed."
		echo "done." >&2
	;;
	"Genesi Efika MX (Smartbook)" | "Genesi Efika MX (Smarttop)")
		efikamx_flash_kernel
	;;
	*)
		case "$running_subarch" in
			"armadaxp" | "dove" | "highbank" | "omap" | "omap4")
				echo "warning: using generic subarchitecture fallback for $running_subarch"
				check_subarch $running_subarch

				case "$subarch" in
					"armadaxp" | "dove")
						dove_flash_kernel
					;;
					"highbank")
						highbank_flash_kernel
					;;
					"omap" | "omap4")
						omap_flash_kernel
					;;
				esac
		;;
		*)
			error "Unsupported platform."
		;;
		esac
	;;
esac

