#!/bin/sh

#----------------------------------------------------------------------
# (C) Copyright 2000
# Sysgo Real-Time Solutions GmbH.
# Klein-Winternheim, Germany
# All rights reserved.
#----------------------------------------------------------------------

#----------------------------------------------------------------------
# Project:     Elinos -- Embedded Linux OS
# Description: Project and Environment Management Scripts
# This file:   makeboot
# Purpose:     make requisite files for boot
#----------------------------------------------------------------------

#----------------------------------------------------------------------
# CVS info:
#
# $Author: mag $
# $Date: 2002/06/10 13:47:04 $
# $Revision: 1.49 $
# $Id: elinos-makeboot,v 1.49 2002/06/10 13:47:04 mag Exp $
# $Source: /home/elinos/CVS/sysgo/elinos/scripts/elinos-makeboot,v $
#----------------------------------------------------------------------

# warn when using uninitialised variables
set -u

this=$0

ELINOS_PREFIX=/opt/elinos
. $ELINOS_PREFIX/bin/elinos-tools.sh

# set this to add kernel parameters that should always be appended
# (e.g. "kbd-reset" for Jumptec DIMM-PCs)
kernelparm=""
config_file="./project.config"
image_file=""


# usage -- print usage information
usage()
{
    cat >&2 <<EOT
Usage: $this [options] ROOTFS.TGZ

Prepare files for the the current project's boot strategy.
The project configuration is read from \`$config_file'.

Options:

   -h, -?,
   --help                  display this help and exit
   --list                  list all supported boot strategies
   --list-controls=STRAT   list controls for given boot strategy

   ROOTFS                  a compressed tar file containing the root file
                           system.
EOT
}

# bs_echo STRAT LABEL - echo STRAT and label if STRAT is in $LIST_BOOTSTRATS or if
# $LIST_BOOTSTRATS is unset or empty (eg. custom board)
bs_echo()
{
	if [ -z "${LIST_BOOTSTRATS:-}" ]; then
		echo "$1 -- $2"
	else
		for strat in $LIST_BOOTSTRATS; do
			if [ "x$strat" = "x$1" ]; then
				echo "$1 -- $2"
			fi
        	done
	fi
}

# do the commandline
for arg do

    case $arg in
	--*=*)
	    optarg=`echo $arg | sed -e 's/^[^=]*=//'`
	    ;;
	 *) ;;		
    esac

    case $arg in
	-h|-\?|--help)
	    usage
	    exit 1
	    ;;
	# This option lists the available boot strategies. The bs_echo
	# function is used to filter out the allowed strategies according
	# to the setting of ELINOS_BOOT_STRAT.
	--list)
	    bs_echo "floppy"         "Floppy Bootstrap"
	    bs_echo "lilo"           "Hard-Disk Bootstrap"
	    bs_echo "rolo"           "x86 ROM Bootstrap with ROLO"
	    bs_echo "rolo_rawdisk"   "ROLO disk boot image (eg. for CompactFlash)"
	    bs_echo "etherboot"      "Diskless Network Bootstrap"
	    bs_echo "etherboot_multi"  "Diskless Network Bootstrap (one Image for Kernel/Root-Filesystem)"
	    bs_echo "ppcboot"        "ppcboot Bootstrap (separate Images for Kernel/Root-Filesystem)"
	    bs_echo "ppcboot_multi"  "ppcboot Bootstrap (one Image for Kernel/Root-Filesystem)"
	    bs_echo "armboot"        "armboot Bootstrap (separate Images for Kernel/Root-Filesystem)"
	    bs_echo "armboot_multi"  "armboot Bootstrap (one Image for Kernel/Root-Filesystem)"
	    bs_echo "zImage"         "simple zImage"
	    bs_echo "zImage_initrd"  "zImage with embedded ram-disk"
	    bs_echo "szImage"        "simple zImage without ELF Header"
	    bs_echo "szImage_initrd" "zImage without ELF Header with embedded ram-disk"
	    bs_echo "blob"           "two uuencoded files to be uploaded to target"
	    # add custom strategies just like this:
	    # echo "mystrat -- a brief description"
	    exit 0
	    ;;
	# This option lists additional control variables for the various
	# boot strategies. A control is defined by a colon separated list
	# with the variable name, a brief description for UI purposes,
	# a default value and a flag. Current flag values are: 
	# "ask" - always prompt user with that variable
	--list-controls=*)
	    case $optarg in
		ppcboot*)
			echo "MKIMAGE_LOAD_ADDRESS:Boot Image Load Address:00000000"
			echo "MKIMAGE_ENTRY_ADDRESS:Boot Image Entry Address:00000000"
			;;
		armboot*)
			echo "MKIMAGE_LOAD_ADDRESS:Boot Image Load Address:c0020000"
			echo "MKIMAGE_ENTRY_ADDRESS:Boot Image Entry Address:c0021000"
			;;
		zImage*|szImage*)
			echo "ZIMAGENAME:Location of Boot Image in the Kernel:arch/ppc/boot/images/zImage"
			echo "ZIMAGEINITRDNAME:Location of InitRD Boot Image in the Kernel:arch/ppc/boot/images/zImage.initrd"
			;;
		rolo_rawdisk)
			echo "ROLO_RD_DRIVE:DOS Drive to boot from on Target:c:ask"
			;;
		*)
			;;
	    esac
		exit 0
	    ;;
	--*|-*)
	    echo >&2 "$this: Bad Argument '$arg'"
	    echo >&2 "Try \`$this --help' for more information"
		exit 1
	    ;;
	*)
	    if [ -z "$image_file" ]; then
		image_file="$arg"
	    else
	    	echo >&2 "$this: Unknown Option '$arg'"
		echo >&2 "Try \`$this --help' for more information"
		exit 1
	    fi
	    ;;
    esac
done

# set kerneldir here, so that the --list options don't require
# ELINOS_PROJECT to be set (we run with -u flag!)
kerneldir="$ELINOS_PROJECT/linux"

# the image file argument is mandatory
if [ -z "$image_file" ]; then
    echo >&2 "$this: bad arguments."
    echo >&2 "Try \`$this --help' for more information"
    exit 1
fi


# read project configuration
if [ ! -f $config_file ]; then
    echo >&2 "$this: couldn't read project configuration from $config_file"
    exit 1
fi
. $config_file

check_elinos_cmdline kernelparm

# prepare_syslinux -- pepare boot files for syslinux
prepare_syslinux()
{
    add_parm kernelparm "initrd=$image_file"
   
    check_banner

    echo -n "Writing syslinux.cfg ... "
    cat > syslinux.cfg <<-EOF
	append $kernelparm
	display banner
	timeout 0
	EOF
    echo "ok."
}


# prepare_lilo -- pepare boot files for LILO
prepare_lilo()
{
    echo -n "Writing lilo.conf ... "
    if [ -z "$kernelparm" ]; then
	cat > lilo.conf <<-EOF
	    boot=/dev/DISKDEV
	    default=linux
	    image=/boot/vmlinuz
	    root=/dev/DISKROOTPART
	    label=linux
	EOF
    else
	cat > lilo.conf <<-EOF
	    boot=/dev/DISKDEV
	    append="$kernelparm"
	    default=linux
	    image=/boot/vmlinuz
	    root=/dev/DISKROOTPART
	    label=linux
	EOF
    fi
    echo "ok."
}


# prepare_rolo -- pepare boot files for ROLO
prepare_rolo()
{
    check_banner
    echo -n "Writing rolo.cfg ... "
    cat > rolo.cfg <<-EOF
	$kernelparm
EOF
    echo "ok."
    echo
    echo "To create a ROMboot Image, the ROLO command must"
    echo "be used, e.g.:"
    echo 
    echo "   rolo -k boot/vmlinuz -d c: romlinux.img"
    echo
    echo "                             - NOTE -"
    echo
    echo "   The proper options for the ROLO command depend on your"
    echo "   system configuration. Please read the Manual!"
}


# prepare_etherboot -- prepare boot files for etherboot
prepare_etherboot()
{
    echo "Creating network bootable image ... "

    test_result=`echo $kernelparm | grep root=`
    if [ -z "$test_result" ]; then
        # ok, it is not us who assume this but it's mknbi
	echo "	WARNING: No 'root=' option. Root file system is assumed"
	echo "		to be mounted via NFS."
    fi 

    if [ -z "$kernelparm" ]; then
		echo "	mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi boot/vmlinuz"
		do_or_die mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi \
			    boot/vmlinuz
	else
		echo "	mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi --append=\"$kernelparm\" boot/vmlinuz"
		do_or_die mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi \
			    --append=\"$kernelparm\" boot/vmlinuz
	fi
    echo "ok."
}


# prepare_etherboot_multi -- prepare boot files for etherboot with embedded ram-disk
prepare_etherboot_multi()
{
    echo "Creating network bootable image ... "

    # make sure that we mount the root file system from the ram disk!
    test_result=`echo $kernelparm | grep root=ramfs`
    if [ -z "$test_result" ]; then
	echo "	appending mandatory kernel parameter root=ramfs"
	add_parm kernelparm "root=ramfs"
    fi

    echo "	mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi --param=\"$kernelparm\" boot/vmlinuz $image_file"
    do_or_die mkelf-linux --output=boot/${ELINOS_DOSNAME}.nbi \
	    --param=\"$kernelparm\" boot/vmlinuz $image_file
    echo "ok."
}


# prepare_ppcboot -- prepare multiple boot files for ppcboot. The kernel
# has already been done by the Kernel Makefiles. It should be in boot/pImage
# by now. So we'll only wrap up the root fs here.
prepare_ppcboot()
{
    do_or_die ${ELINOS_BIN_PREFIX}-objcopy -O binary $kerneldir/vmlinux \
	    boot/vmlinux.bin
    do_or_die gzip -9f boot/vmlinux.bin
    do_or_die mv boot/vmlinux.bin.gz boot/ezImage
    do_or_die mkimage -O linux -T kernel \
    		-A $ELINOS_CPU -a $MKIMAGE_LOAD_ADDRESS -e $MKIMAGE_ENTRY_ADDRESS \
                -n \'Linux Kernel Image\' \
                -C gzip -d boot/ezImage boot/pImage
    rm boot/ezImage
    do_or_die mkimage -n \'Ramdisk Tar Image\' \
	-A $ELINOS_CPU -O linux -T ramdisk -C gzip \
	-d $image_file ${ELINOS_DOSNAME}.initrd
    if [ -n "$kernelparm" ]; then
	    echo "                             - NOTE -"
	    echo
	    line=`grep '^CONFIG_MENA12=y' $kerneldir/.config`
	    if [ -n "$line" ]; then
		echo "   Remember to set the bootline to serial EEPROM"
		echo "   at the firmware prompt:"	        
		echo "   MenMon> EE-KERPAR $kernelparm"    	    	    
	    else	
		echo "   Remember to set the \"bootargs\" enviroment variable"
		echo "   at the firmware prompt:"	    
		echo "   => setenv bootargs $kernelparm"
	    fi		
	    echo
    fi
}


# prepare_ppcboot_multi -- prepare multi-file image for PowerPC/ppcboot. 
# We'll ignore the boot/pImage.
prepare_ppcboot_multi()
{
    do_or_die ${ELINOS_BIN_PREFIX}-objcopy -O binary $kerneldir/vmlinux \
	    boot/vmlinux.bin
    do_or_die gzip -9f boot/vmlinux.bin
    do_or_die mkimage -n \'Multi-File Image\' -O linux -T multi -C gzip \
	-A $ELINOS_CPU -a $MKIMAGE_LOAD_ADDRESS -e $MKIMAGE_ENTRY_ADDRESS \
	-d boot/vmlinux.bin.gz:$image_file \
	boot/${ELINOS_DOSNAME}.img
    rm boot/vmlinux.bin.gz
    if [ -n "$kernelparm" ]; then
	    echo "                             - NOTE -"
	    echo
	    line=`grep '^CONFIG_MENA12=y' $kerneldir/.config`
	    if [ -n "$line" ]; then
		echo "   Remember to set the bootline to serial EEPROM"
		echo "   at the firmware prompt:"	        
		echo "   MenMon> EE-KERPAR $kernelparm"    	    	    
	    else	
		echo "   Remember to set the \"bootargs\" enviroment variable"
		echo "   at the firmware prompt:"	    
		echo "   => setenv bootargs $kernelparm"
	    fi		
	    echo
    fi
}

# prepare_blob -- prepare a zImage for blob (eg. LART)
prepare_blob()
{
    echo -n "uuencoding Kernel ....."
    if ! (uuencode $kerneldir/arch/arm/boot/zImage LART-Kernel >boot/${ELINOS_DOSNAME}-kernel.uu)
    then
	echo "... failed."
	exit 1
    fi
    echo "... done"
    echo -n "uuencoding Root-Filesystem"
    if ! (uuencode $image_file LART-Rootfs >boot/${ELINOS_DOSNAME}.uu)
    then
	echo "... failed"
	exit 1
    fi
    echo "... done"
}

getbootdir()
{
    # starting with 2.4.16-Elinos we're using the new arch/ppc/boot stuff
    if [ $PATCHLEVEL -eq 4 -a $SUBLEVEL -ge 16 ]; then
    :
    else
	echo -n "Checking PPC bootloader ... "
	bootdir=mbxboot
	if grep >/dev/null '^CONFIG_6xx=y' $kerneldir/.config; then
	    bootdir=boot
	fi
	echo "$bootdir"
    fi
}

# prepare_zImage -- prepare a zImage (eg. MVME, MBX)
prepare_zImage()
{
    getkernelver
    getbootdir
    do_or_die make -C linux zImage
    do_or_die cp $kerneldir/$ZIMAGENAME boot/zImage
}

# prepare_zImage_initrd -- prepare a zImage with embedded initrd 
# (eg. MVME, MBX)
prepare_zImage_initrd()
{
    getkernelver
    getbootdir
    # starting with 2.4.16-Elinos we're using the new arch/ppc/boot stuff
    if [ $PATCHLEVEL -eq 4 -a $SUBLEVEL -ge 16 ]; then
	do_or_die cp $image_file \
		$kerneldir/arch/ppc/boot/images/ramdisk.image.gz
    else
	do_or_die cp $image_file $kerneldir/arch/ppc/mbxboot/ramdisk.image.gz
	do_or_die ln -sf ../mbxboot/ramdisk.image.gz \
		$kerneldir/arch/ppc/coffboot
	do_or_die ln -sf ../mbxboot/ramdisk.image.gz \
		$kerneldir/arch/ppc/chrpboot
	do_or_die ln -sf ../mbxboot/ramdisk.image.gz \
		$kerneldir/arch/ppc/boot
    fi
    do_or_die make -C linux zImage.initrd
    do_or_die cp $kerneldir/$ZIMAGEINITRDNAME boot/zImage.initrd
}

# prepare_szImage -- prepare a szImage (eg. RPX Lite)
prepare_szImage()
{
    getkernelver
    getbootdir
    do_or_die dd if=$kerneldir/$ZIMAGENAME of=boot/szImage bs=64k skip=1
}

# prepare_szImage_initrd -- prepare a szImage with embedded initrd 
# (eg. RPX Lite)
prepare_szImage_initrd()
{
    prepare_zImage_initrd
    do_or_die dd if=boot/zImage.initrd of=boot/szImage.initrd bs=64k skip=1
    rm boot/zImage.initrd
}

# prepare_rolo_rawdisk -- pepare boot files for LILO
prepare_rolo_rawdisk()
{
    check_banner
    echo -n "Writing rolo.cfg ... "
    cat > rolo.cfg <<-EOF
	$kernelparm
EOF

    rolo -k "boot/vmlinuz" -p "$ELINOS_PREFIX/share/rawdiskldr.bin" \
         -d "$ROLO_RD_DRIVE:" boot/rawdisk.img

    echo "ok."
}

# main()

case $ELINOS_BOOT_STRAT in
    floppy)
	echo
	echo "Preparing for floppy-boot:"
	prepare_syslinux
	echo "Ok."
	echo
	echo "As a final step to get a bootable floppy disk, please copy the"
	echo "following files to an empty, MS-DOS formatted floppy:"
	echo 
	echo "   cp syslinux.cfg /floppy/syslinux.cfg"
	echo "   cp banner /floppy/banner"
	echo "   cp boot/vmlinuz /floppy/linux"
	echo "   cp $image_file /floppy/$image_file"
	echo
	echo "To make the floppy bootable, please type:"
	echo
	echo "   /opt/elinos/bin/syslinux /dev/fd0"
	echo
	echo "                             - NOTE -"
	echo
	echo "   You may need root privileges to execute the above commands."
	;;
    lilo)
	echo
	echo "Preparing for LILO Bootstrap:"
	prepare_lilo
	echo
	echo "To make your target system bootable, the install system should"
	echo "now be loaded on your embedded system (e.g. by booting it from"
	echo "floppy disk)."
	echo "The install system will then allow you to upload the requisite"
	echo "files to the target's harddisk either via network or via floppy"
	echo "disk."
	echo
	echo "If you upload via network, You will be asked to run the"
	echo "\"elinos-isrv\" script from this directory."
	echo
	echo "If you upload via floppy disk, please copy the following"
	echo "files to an empty, MS-DOS formatted floppy:"
	echo 
	echo "   cp lilo.conf /floppy/lilo.cnf"
	echo "   cp boot/vmlinuz /floppy/linux"
	echo "   cp $image_file /floppy/project.tgz"
	echo
	echo "                             - NOTE -"
	echo
	echo "   You may need root privileges to execute the above commands."
	;;
    rolo)
	echo
	echo "Preparing for ROM Bootstrap:"
	prepare_rolo
	;;
    rolo_rawdisk)
	echo
	echo "Preparing for ROLO Rawdisk Bootstrap:"
	echo
	prepare_rolo_rawdisk
	echo
	echo "As a final step to get a bootable disk, please proceed"
	echo "as follows. Note that the commands assume you want to"
	echo "install the root filesystem on an ext2 type partition"
	echo "and the target disk is mounted as the first SCSI drive."
	echo "You will most likely need root privileges for this, too."
	echo
	echo "   sh# cat boot/rawdisk.img >/dev/sda"
	echo "   sh# fdisk /dev/sda"
	echo "   (-> create a partition for the root filesystem)"
	echo "   sh# mkfs.ext2 /dev/sda2"
	echo "   sh# mount /dev/sda2 /mnt"
	echo "   sh# tar -xzp -C /mnt -f $image_file"
	echo "   sh# umount /mnt"
	echo
	;;
    etherboot)
	echo
	echo "Preparing for etherboot Bootstrap:"
	prepare_etherboot
	;;
    etherboot_multi)
	echo
	echo "Preparing for etherboot Bootstrap:"
	prepare_etherboot_multi
	;;
    ppcboot)
	echo
	echo "Preparing for ppcboot Bootstrap:"
	echo ""
	prepare_ppcboot
	;;
    ppcboot_multi)
	echo
	echo "Preparing for ppcboot_multi Bootstrap:"
	echo ""
	prepare_ppcboot_multi
	;;
    armboot)
	echo
	echo "Preparing for armboot Bootstrap:"
	echo ""
	prepare_ppcboot
	;;
    armboot_multi)
	echo
	echo "Preparing for armboot_multi Bootstrap:"
	echo ""
	prepare_ppcboot_multi
	;;
    zImage)
	echo
	echo "Preparing for zImage Bootstrap:"
	echo ""
	prepare_zImage
	;;
    zImage_initrd)
	echo
	echo "Preparing for zImage_initrd Bootstrap:"
	echo ""
	prepare_zImage_initrd
	;;
    szImage)
	echo
	echo "Preparing for szImage Bootstrap:"
	echo ""
	prepare_szImage
	;;
    szImage_initrd)
	echo
	echo "Preparing for szImage_initrd Bootstrap:"
	echo ""
	prepare_szImage_initrd
	;;
    blob)
	echo
	echo "Preparing two uuencoded files:"
	echo ""
	prepare_blob
	;;
    *)	echo >&2 "$this: unsupported boot stategy \"$ELINOS_BOOT_STRAT\"."
	;;
esac

echo
echo "                             - NOTE -"
echo
echo "   You may want to customise this script to meet any special"
echo "   requirements of your target hardware. For instance, you could"
echo "   add the commands neccessary to copy the boot files to a floppy"
echo "   disk, or to the download directory of your tftp-server."
echo "   The script is located here:"
echo "   $ELINOS_PROJECT/makeboot"
echo

