#!/bin/sh # Copyright (C) 2006 Joey Hess # Copyright (C) 2006, 2007, 2008 Martin Michlmayr # This code is covered by the GNU General Public License (GPLv2 or higher) 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/' } 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 fi } check_size() { if [ $2 -gt $3 ]; then error "The $1 doesn't fit in flash." fi } # 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 } if [ -n "$1" ]; then kvers="$1" kfile=/boot/vmlinuz-$kvers ifile=/boot/initrd.img-$kvers desc="Debian kernel $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" 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/.*-//') machine=$(grep "^Hardware" /proc/cpuinfo | sed 's/Hardware\s*:\s*//') case "$machine" in "Linksys NSLU2") check_subarch "ixp4xx" # case "$(dpkg --print-architecture)" in # arm|armel) # little_endian=1 # ;; # armeb) # little_endian=0 # ;; # esac little_endian=1 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 kmtdsize=$(mtdsize "Kernel") check_size "kernel" $(($kfilesize + 16 + 16)) $kmtdsize imtd=$(mtdblock Ramdisk) if [ -z "$imtd" ]; then error "Cannot find mtd partition 'Ramdisk'" fi 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: $kfile\n" >&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: $ifile\n" >&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 ;; "QNAP TS-109/TS-209" | "QNAP TS-409") check_subarch "orion5x" check_mtd imtd=$(mtdblock "RootFS1") if [ -z "$imtd" ]; then error "Cannot find mtd partition 'RootFS1'" fi imtdsize=$(mtdsize "RootFS1") check_size "RootFS1" $ifilesize $imtdsize kmtd=$(mtdblock Kernel) if [ -z "$kmtd" ]; then error "Cannot find mtd partition 'Kernel'" fi 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") devio > $tmp 'wl 0xe3a01c06,4' 'wl 0xe381101d,4' ;; "QNAP TS-409") devio > $tmp 'wl 0xe3a01c06,4' 'wl 0xe3811041,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... \n" >&2 cat $tmp.uboot > $kmtd || error "failed." echo "done." >&2 rm -f $tmp.uboot $tmp printf "Flashing initramfs... \n" >&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 imtdsize=$(mtdsize "ramdisk") check_size "ramdisk" $ifilesize $imtdsize kmtd=$(mtdblock kernel) if [ -z "$kmtd" ]; then error "Cannot find mtd partition 'kernel'" fi kmtdsize=$(mtdsize "kernel") check_size "kernel" $(($kfilesize + 8)) $kmtdsize printf "Flashing kernel... \n" >&2 ( devio 'wl 0xe3a01c04,4' 'wl 0xe381104d,4' cat $kfile ) > $kmtd || error "failed." echo "done." >&2 printf "Flashing initramfs... \n" >&2 pad=$(expr $imtdsize - $ifilesize) ( cat $ifile dd if=/dev/zero bs=$pad count=1 2>/dev/null ) > $imtd || error "failed." echo "done." >&2 ;; *) error "Unsupported platform." ;; esac