#!/bin/bash

# This script is used to setup a build environment and a configuration file
# from the command line options for mklinuximg build scripts. The result
# will be a RAM image of Linux that can boot on a SPARC/LEON with MMU.
#

usage() {
    echo "Usage:"
    echo "$0 <linux-image> <out-file> [optional parameters]..."
    echo "  <linux-image> linux image, for Linux 3.4 and older <linux-dir>/arch/sparc/boot/image."
    echo "                and for Linux 3.5 and newer <linux-dir>/vmlinux."
    echo "  <out-file>    output image that can be uploaded using GRMON or run in TSIM."
    echo ""
    echo " optional parameters:"
    echo "  -base <baseaddr>  optional baseaddress. The default is 0x40000000."
    echo "  -cmdline <string> kernel parameter string. Default is \"console=ttyS0,38400\"."
    echo "  -freq <frequency> optional frequency parameter in case if it cannot be retrieved from the Timer scalar."
    echo "  -amp <string>     optional string of format <idx0>=<val0>:<idx1>=<val1>:... that sets for core index"
    echo "                    n property ampopts to value n. Example 0=4:1=6 will set core index 0's ampopts to 4"
    echo "                      and core index 1's ampopts to 6."
    echo "  -ethmac <string>  set the ethernet mac address as 12 dgt hex. Default: 00007ccc0145"
    echo "  -ipi <irq_num>    IRQ number used by Linux SMP for IPIs. May not be shared. Allowed values: 1..14"
    echo "  -ioarea <ioarea>  GRLIB AMBA Plug&Play I/O AREA Base address. Defaults to 0xfff00000"
    echo "  -uartidx <index>  Select UART by index for PROM Console. Default 0 (first UART0)"
    echo "  -maxcpu <num>     Disable/Limit number of Linux CPUs 1..8 (default 8)"
    echo "  -wakediscpus      Wake the disabled/limited CPUs"
    echo "  --version         Print version of mklinuximg"
    echo "  -xml <file>       Specify an xml file that adds extra properties and nodes to the device tree."
    echo "  -flat             Create a flat device-tree."
    echo "  -grgpio-noprobe   Do not probe grgpio cores (otherwise mklinuximg probes grgpio cores for info)."
    echo "  -grgpio-nbits <comma-separated-list>"
    echo "                    Provide number of lines for grgpio cores (in scan order)."
    echo "  -grgpio-imask <comma-separated-list-of-bitmasks>"
    echo "                    Provide the imask generic (which gpio lines can generate interrupts)"
    echo "                    for grgpio cores (in scan order)."
    echo "  -grgpio-irqgen <comma-separated-list>"
    echo "                    Provide the irqgen generic for grgpio cores (in scan order)."

#    echo "  -maxcpu <max_num> Maximum CPUs in the system [1..8]"

    exit 1;
}

version() {
    grep VERSION $prefix/VERSION
    exit 1;
}

failexit() {
    if [ "$isdump" == "0" ]; then
	rm -rf $tmpdir
    fi
    exit 1
}

prefix=`dirname $(readlink -f $0)`/

xml=;
nolin=0;ioarea="";uartidx="0";
isdump=0;isdbg=0;istest=0; ofile=""; ldir=""; baddr="0x40000000"; freq="0"; cmdline="console=ttyS0,38400"; amp=""; smp=""; ipi="0";
ethmac="00007ccc0145";
max_cpus="8"
wake_dis_cpus="0";wake_dis_cpus_str="NO"
macrostr=""
grgpio_probe=1
while [ $# -ne 0 ]
do
    case "$1" in
	#-o) shift; ofile="$1";
	-dump) isdump=1;;
	-d) isdbg=1;;
	-nolin) nolin=1;;
	-t) istest=1;;
	-freq) shift; freq="$1";;
	-flat) shift; macrostr="${macrostr} -DFLATOFTREE ";;
	-cmdline) shift; cmdline="$1";;
	-base) shift; baddr="$1";;
	-ethmac) shift; ethmac="$1";;
	-amp) shift; amp="$1";;
	-xml) shift; xml="$1";;
	-smp) ;; # ignore deprecated SMP flag, is autodetected
	-ipi) shift; ipi="$1";;
	-ioarea) shift; ioarea="$1";;
	-uartidx) shift; uartidx="$1";;
	-maxcpu) shift; max_cpus="$1";;
	-wakediscpus) wake_dis_cpus=1; wake_dis_cpus_str="YES";;
	--version) shift; version ;;
	-grgpio-noprobe) grgpio_probe=0 ;;
	-grgpio-nbits) shift; grgpio_nbits="$1" ;;
	-grgpio-imask) shift; grgpio_imask="$1" ;;
	-grgpio-irqgen) shift; grgpio_irqgen="$1" ;;
	*) a[${#a[*]}]="$1";;
    esac
    shift
done

limg=`readlink -f ${a[0]}`
o=${a[1]}

if [ "${#a[*]}" != "2" ]; then usage; fi


# Setup build environment
tmpdir=`mktemp -d`
#tmpdir="/tmp/mklinuximg"
mkdir -p $tmpdir/include
cfg="$tmpdir/include/config_auto.h"
ampoptfile="$tmpdir/include/config_ampopts.h"
xmlo="xml.c"

# Autodetect if SMP image (if symbol trapbase_cpu0 exists)
smp_img="NO"
if sparc-linux-readelf -s $limg | grep trapbase_cpu0 > /dev/null ; then
	smp_img="YES"
	smp="1"
fi


# Autodetect Linux version from Linux header in head_32.S
hdr_base_adr=`sparc-linux-objdump -x $limg | grep root_flags | sed 's/[0-9a-fA-F][ ].*$//g'`
hdr_base_adr=`echo ${hdr_base_adr}0`
linux_ver=`sparc-linux-readelf -x 1 $limg | grep -E "^  0x${hdr_base_adr}" | cut -d' ' -f5`


# Find Linux BSS in Virtual Addresses
bss_addr=0x`sparc-linux-objdump -h $limg | grep \\\\.bss\\[\\[:space:\\]\\] | awk '{ print $4 }' `;
bss_size=0x`sparc-linux-objdump -h $limg | grep \\\\.bss\\[\\[:space:\\]\\] | awk '{ print $3 }' `;
bss_end=$((($bss_addr+$bss_size)))

# Print settings
echo "======== DETECTED SETTINGS ========"
echo "Linux version :" $linux_ver
echo "Linux-img     :" $limg
echo "Output:       :" $o
echo "prefix        :" $prefix
echo "tmpdir        :" $tmpdir
echo "base          :" $baddr
echo "amp           :" $amp
echo "ethmac        :" $ethmac
echo "SMP detected  :" $smp_img
echo "ipi           :" $ipi "(zero = use Linux default)"
echo "Linux BSS VA  :" $bss_addr " of size " $bss_size " bytes"
echo "custom-xml    :" ${xml}
echo "Max CPU       :" $max_cpus
echo "-wakediscpus  :" $wake_dis_cpus_str
echo "==================================="
echo
echo

# force a "symbol <FORCE_GRMON_LOAD_SYM>" after loading in grmon and grsim
macrostr="${macrostr} -DFORCE_GRMON_LOAD_SYM="\"\\\"${limg}\\\"\"" "

# Create configuration header file from arguments and Linux image, the
# header-file will override the defaults in include/config_auto.h

echo "/* Auto generated by mklinuximg utility */" > $cfg
echo "" >> $cfg
echo "#define CONFIG_RAM_START " $baddr >> $cfg
if [ "$freq" != "0" ]; then
  echo "#define CONFIG_BOOTLOADER_FREQ $freq">> $cfg
fi
if [ -n "$ioarea" ]; then
  echo "#define CONFIG_AMBA_IO_AREA 0x$ioarea">> $cfg
fi
echo "#define CONFIG_IPI_NUM " $ipi >> $cfg
if [ -n "$smp" ]; then
  echo "#define CONFIG_SMP" >> $cfg
fi
echo "#define CONFIG_MAX_CPUS $max_cpus" >> $cfg
echo "#define CONFIG_WAKE_DISABLED_CPUS $wake_dis_cpus" >> $cfg
echo "#define CONFIG_ETHMAC 0x${ethmac}ULL" >> $cfg
if [ -n "$amp" ]; then
  echo "#define CONFIG_AMPOPTS" >> $cfg
fi
echo "#define CONFIG_LINUX_CMDLINE \"$cmdline\"" >> $cfg
echo "#define CONFIG_LINUX_VERSION_CODE 0x${linux_ver}" >> $cfg
echo "#define CONFIG_LINUX_BSS_START ${bss_addr}" >> $cfg
echo "#define CONFIG_LINUX_BSS_SIZE ${bss_size}" >> $cfg
echo "#define CONFIG_UART_INDEX ${uartidx}" >> $cfg
echo "#define CONFIG_GRGPIO_PROBE ${grgpio_probe}" >> $cfg
echo "#define CONFIG_GRGPIO_NBITS ${grgpio_nbits}" >> $cfg
echo "#define CONFIG_GRGPIO_IMASKGEN ${grgpio_imask}" >> $cfg
echo "#define CONFIG_GRGPIO_IRQGEN ${grgpio_irqgen}" >> $cfg

if [ "$isdbg" != 0 ]; then
  echo "#define CONFIG_DEBUG" >> $cfg
fi
# For debugging only
if [ "$nolin" != 0 ]; then
  echo "#define CONFIG_NO_LINUX" >> $cfg
fi

# Build optional AMP Options c-file
echo "" > ${ampoptfile}
if [ -n "$amp" ]; then
    echo $amp | awk '{split($0,a,":"); for (v in a) { print a[v]; }; }' | awk '{split($0,a,"="); print "\t{" a[1] "," a[2] "},"; }; ' >> ${ampoptfile}
fi

# custom xml 
if [ "${xml}" != "" ]; then
    echo "processing xml: ${prefix}scanxml ${xml} ${tmpdir}/${xmlo}"
    ${prefix}scanxml ${xml} ${tmpdir}/${xmlo} || failexit
    macrostr="${macrostr} -DHASXML="\"\\\"${tmpdir}/${xmlo}\\\"\"" "
fi

# Build mklinuximg
cd $tmpdir
make -C $prefix/src O=`pwd` LINUX_IMAGE=$limg CFLAGS_EXTRA="${macrostr}" all || failexit
cd -
mv $tmpdir/image $o || failexit

echo
echo

if [ "$isdump" == "0" ]; then
    rm -rf $tmpdir
else
    sparc-linux-objdump -d $tmpdir/image_virt.o > ${tmpdir}/image_virt.S
    echo TMPDIR: $tmpdir
fi

ls -l $o
sparc-linux-objdump -h $o
