#!/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> [-freq <frequency>] [-base <baseaddr>] [-cmdline <string>] [-amp <string>] [-ethmac <string>] [-ipi <irq_num>] [-ioarea <ioarea>]"
    echo "  <linux-image> linux image, normally <linux-dir>/arch/sparc/boot/image."
    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 retrived 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 "  -xml <file>       Specify a xml file that adds extra properties and nodes to the device tree."
    echo "                    The -xml switch only functions if the -allocinmem switch is choosen."
    echo "  -flat             Create a flat device-tree."

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

    exit 1;
}

xml=;
nolin=0;ioarea="";
isdump=0;isdbg=0;istest=0; ofile=""; ldir=""; baddr="0x40000000"; freq="0"; cmdline="console=ttyS0,38400"; amp=""; smp=""; ipi="0"
ethmac="00007ccc0145";
macrostr=""
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";;
	*) a[${#a[*]}]="$1";;
    esac
    shift
done

limg=${a[0]}
o=${a[1]}
prefix=`dirname $(readlink -f $0)`/

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 "==================================="
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 8" >> $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

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: cat ${xml} | awk -f ${prefix}scanxml.awk -v of=${tmpdir}/${xmlo}"
    echo > ${tmpdir}/${xmlo}
    cat ${xml} | awk -f ${prefix}scanxml.awk -v of=${tmpdir}/${xmlo}
    macrostr="${macrostr} -DHASXML="\"\\\"${tmpdir}/${xmlo}\\\"\"" "
fi

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

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



# The xml files format:
# tags:
#   add-property
#   add-node
#   property
#
# <add-property>:
#   Add properties to a choosen node(s).
#   There are 2 variants to:
#    <add-property vendor="0x1" device="0xc" idx="0" >
#     selects the node to add properties to by vendor:device:idx
#     where <idx> is the amba-scan index
#    <add-property parent="4" >
#     selects the node to add properties to by amba-scan index <parent>
#
# <add-node>:
#   Add node subtree to a choosen node(s) as child.
#   There are 2 variants to:
#    <add-node vendor="0x1" device="0xc" idx="0" >
#     selects the node to add node subtree to by vendor:device:idx
#     where <idx> is the amba-scan index
#    <add-node parent="4" >
#     selects the node to add node subtree to by amba-scan index <parent>
#
# <property name="[name]" type="[int|str]" value="val" >:
#   Add a property by name=value. 2 types are supported:
#   "int" : adds a integer, specified by "value"
#   "str" : adds a string, specified by "value"
#
# 
# example xml:
# --------------------- start ----------------------------
#<!-- add property by vendor:device:idx -->
#<add-property vendor="0x1" device="0xc" idx="0" >
#  <property name="add-prop-1.c.test1" type="int" value="1024"/>
#  <property name="add-prop-1.c.test2" type="str" >teststr</property>
#</add-property>
#
#<!-- add property by scan idx -->
#<add-property parent="4"  >
#  <property name="add-prop-p4.test1" type="int" value="1024"/>
#  <property name="add-prop-p4.test2" type="str" >teststr</property>
#</add-property>
#
#<!-- add subtree by vendor:device:idx -->
#<add-node name="newnode-add-node-1-c" vendor="0x1" device="0xc" idx="0" >
#  <property name="newnode-1-p1" type="int" value="5"/>
#  <property name="newnode-1-p2" type="int" value="6"/>
#  <add-node name="newnode-1-1" >
#    <property name="newnode-1-1-p1" type="int" value="7"/>
#    <property name="newnode-1-1-p2" type="int" value="8"/>
#  </add-node>
#  <add-node name="newnode-1-2" >
#    <property name="newnode-1-2-p1" type="int" value="9"/>
#    <property name="newnode-1-2-p2" type="int" value="10"/>
#  </add-node>
#</add-node>
#
#<!-- add subtree by scan idx -->
#<add-node name="newnode-add-p4" parent="4" >
#  <property name="newnode-p1" type="int" value="1"/>
#  <property name="newnode-p2" type="int" value="2"/>
#  <add-node name="newnode-2-1" >
#    <property name="newnode-2-1-p1" type="int" value="3"/>
#    <property name="newnode-2-1-p2" type="int" value="4"/>
#    <property name="newnode-2-1-p2-2" type="int" value="5"/>
#  </add-node>
#</add-node>
# ---------------------  end  ----------------------------
