#!/var/busybox/ash

DBASE=/sys/firmware/devicetree/base

# get 4byte hex value from dtb node
# $1 - dtb node sub path
# $2 - val index
# $? - hex value: XXXXXXXX
dtb_hex4()
{
	if [ -f ${DBASE}$1 ]; then
		if [ -z "$2" ]; then
			hexdump ${DBASE}$1 -e '4/1 "%02X"' -n 4
		else
			skip=`expr $2 \* 4`
			hexdump ${DBASE}$1 -e '4/1 "%02X"' -n 4 -s ${skip}
		fi
	else
		echo ""
	fi
}

# get 8byte hex value from dtb node
# $1 - dtb node path
# $2 - val index
# $? - hex value: XXXXXXXXXXXXXXXXXX
dtb_hex8()
{
	if [ -f ${DBASE}$1 ]; then
		if [ -z "$2" ]; then
			hexdump ${DBASE}$1 -e '8/1 "%02X"' -n 8
		else
			skip=`expr $2 \* 8`
			hexdump ${DBASE}$1 -e '8/1 "%02X"' -n 8 -s ${skip}
		fi
	else
		echo ""
	fi
}

# update cells
# $1 - dtb node sub path, null as base
cells_upd()
{
	DADDR=$(printf "%d" 0x`dtb_hex4 $1/#address-cells`)
	DSIZE=$(printf "%d" 0x`dtb_hex4 $1/#size-cells`)
}

# get addr hex value from dtb node as default cells
# $1 - dtb node sub path
# $2 - val index
# $? - addr hex value: XX...XX
dtb_ahex()
{
	if [ $DADDR -eq 2 ]; then
		dtb_hex8 $1 $2
	else
		dtb_hex4 $1 $2
	fi
}

# get size hex value from dtb node as default cells
# $1 - dtb node sub path
# $2 - val index
# $? - size hex value: XX...XX
dtb_shex()
{
	if [ $DSIZE -eq 2 ]; then
		dtb_hex8 $1 $2
	else
		dtb_hex4 $1 $2
	fi
}

# get dec value from hex
# $1 - hex value: XX...XX
# $? - dec value: dd...dd
dtb_val()
{
	if [ -z "$1" ]; then
		echo "0"
	else
		printf "%lld" 0x$1
	fi
}

# format as 0x%08X
# $1 - XX...XX
# $2 - place holder
# $? - 0xXXXXXXXX
dtb_fmt()
{
	if [ -z "$1" ]; then
		echo "0x00000000"
	else
		printf 0x"%0$2X" 0x$1
	fi
}

# format as size: xxB/K/M/G
# $1 - dd...dd
# $2 - fmt length
# $3 - base
# $? - xxB/K/M/G
dtb_sizeht()
{
	if [ -z "$1" ]; then
		echo "0B"
	else
		size=$1
		s1K=`expr 1 \* 1024`
		s1M=`expr 1024 \* 1024`
		s1G=`expr 1024 \* 1024 \* 1024`
		if [ "$3" = "G" ] || ([ -z "$3" ] && [ ${size} -ge ${s1G} ]); then
			size_h=$(echo "${size} ${s1G}" | awk '{print $1/$2}')
			if [ "${size_h/./}" == "${size_h}" ]; then
				printf "%$2dG" ${size_h}
			else
				printf "%$2.2fG" ${size_h}
			fi
		elif [ "$3" = "M" ] || ([ -z "$3" ] && [ ${size} -ge ${s1M} ]); then
			size_h=$(echo "${size} ${s1M}" | awk '{print $1/$2}')
			if [ "${size_h/./}" == "${size_h}" ]; then
				printf "%$2dM" ${size_h}
			else
				printf "%$2.2fM" ${size_h}
			fi
		elif [ "$3" = "K" ] || ([ -z "$3" ] && [ ${size} -ge ${s1K} ]); then
			size_h=$(echo "${size} ${s1K}" | awk '{print $1/$2}')
			if [ "${size_h/./}" == "${size_h}" ]; then
				printf "%$2dK" ${size_h}
			else
				printf "%$2.2fK" ${size_h}
			fi
		else
			printf "%$2dB" ${size}
		fi
	fi
}

# format as size: xxB/K/M/G
# $1 - XX...XX
# $2 - fmt length
# $? - xxB/K/M/G
dtb_sizehtx()
{
	if [ -z "$1" ]; then
		echo "0B"
	else
		size=`printf "%lld" 0x$1`
		dtb_sizeht ${size} $2
	fi
}

# res display
# $1 - res sub string
res_disp()
{
	size=`echo $1 | awk '{print $1}'`
	name=`echo $1 | awk '{print $2 $3}'`
	printf "%-18s %-11s %9s %s\n" "-" "-" "${size}" "${name}"
}

echo "------------------------------------------------------------------"
echo "address            size(hex)  size       name"

cells_upd
memblk=0
memsizes=0
while [ ${memblk} -lt 10 ]; do
	membasehex=$(dtb_ahex /memory@3000000000/reg `expr ${memblk} \* 2`)
	memsizehex=$(dtb_shex /memory@3000000000/reg `expr ${memblk} \* 2 + 1`)
	if [ -z "${memsizehex}" ]; then
		break
	fi
	memblks="${memblks} ${membasehex}:${memsizehex}"
	memsizes=$((${memsizes} + 0x${memsizehex}))
	memblk=`expr ${memblk} + 1`
done
if [ ${memblk} -eq 0 ]; then
	echo "error: no memblk reg here"
	echo "------------------------------------------------------------------"
	exit 1
fi
memsizehex=`printf "%x" ${memsizes}`

RESMEM_SORT=$(ls $DBASE/reserved-memory -l | grep ^d | awk -F '@' '{print $2}' | while read hex; do printf "%s %d\n" "$hex" $((16#$hex)); done | sort -k2n | awk '{ print $1 }')
cells_upd /reserved-memory

echo "------------------ ---------- ---------- <reserved memory>--------"
same_index=1
old_resdir=""
resmem_nomap_total=0
for res in ${RESMEM_SORT}; do
	resdir=`ls ${DBASE}/reserved-memory | grep "@${res}$"`
	if [ "$resdir" = "$old_resdir" ];then
		same_index=$(($same_index + 1))
	else
		same_index=1
	fi
	old_resdir=$resdir
	resdir=`ls ${DBASE}/reserved-memory | grep "@${res}$" | sed -n "${same_index}p"`
	resname=`echo ${resdir} | awk -F '@' '{print $1}'`
	resbasehex=$(dtb_ahex /reserved-memory/${resdir}/reg 0)
	ressizehex=$(dtb_shex /reserved-memory/${resdir}/reg 1)
	resbase=$(dtb_fmt ${resbasehex} 16)
	ressize=$(dtb_fmt ${ressizehex} 8)
	ressizeht=$(dtb_sizehtx ${ressizehex} 9)
	if [ -f ${DBASE}/reserved-memory/${resdir}/status ]; then
		status=`cat ${DBASE}/reserved-memory/${resdir}/status`
		if [ $status != "okay" ]; then
			continue;
		fi
	fi
	if [ -f ${DBASE}/reserved-memory/${resdir}/no-map ]; then
		echo "${resbase} ${ressize} ${ressizeht} ${resname}"
		resmem_nomap_total=`expr ${resmem_nomap_total} + $(dtb_val ${ressizehex})`
	fi
done
mem_resv="$(dtb_sizeht ${resmem_nomap_total} 7) total"
res_disp "${mem_resv}"

echo "------------------ ---------- ---------- <ion memory>-------------"
same_index=1
old_resdir=""
resmem_map_total=0
for res in ${RESMEM_SORT}; do
	resdir=`ls ${DBASE}/reserved-memory | grep "@${res}$"`
	if [ "$resdir" = "$old_resdir" ];then
		same_index=$(($same_index + 1))
	else
		same_index=1
	fi
	old_resdir=$resdir
	resdir=`ls ${DBASE}/reserved-memory | grep "@${res}$" | sed -n "${same_index}p"`
	resname=`echo ${resdir} | awk -F '@' '{print $1}'`
	resbasehex=$(dtb_ahex /reserved-memory/${resdir}/reg 0)
	ressizehex=$(dtb_shex /reserved-memory/${resdir}/reg 1)
	resbase=$(dtb_fmt ${resbasehex} 16)
	ressize=$(dtb_fmt ${ressizehex} 8)
	ressizeht=$(dtb_sizehtx ${ressizehex} 9)
	if [ -f ${DBASE}/reserved-memory/${resdir}/status ]; then
		status=`cat ${DBASE}/reserved-memory/${resdir}/status`
		if [ $status != "okay" ]; then
			continue;
		fi
	fi
	if [ -f ${DBASE}/reserved-memory/${resdir}/no-map ]; then
		continue;
	else
		echo "${resbase} ${ressize} ${ressizeht} ${resname}"
		resmem_map_total=`expr ${resmem_map_total} + $(dtb_val ${ressizehex})`
	fi
done

mem_resv="$(dtb_sizeht ${resmem_map_total} 7) total"
res_disp "${mem_resv}"

echo "------------------ ---------- ---------- <memory summary>---------"

reserved_memsize=`expr ${resmem_nomap_total} + ${resmem_map_total}`
mem_resv="$(dtb_sizeht ${reserved_memsize} 7) reserved"
res_disp "${mem_resv}"

available_memsize=$(cat /proc/meminfo | grep "MemTotal" | awk -F ' ' '{print $2}')
available_memsize=`expr ${available_memsize} \* 1024`
mem_resv="$(dtb_sizeht ${available_memsize} 7) available"
res_disp "${mem_resv}"

total_memsize=0
for memblkx in ${memblks}; do
	memsizehex=`echo "${memblkx}" | awk -F ':' '{print $2}'`
	size=`printf "%lld" 0x${memsizehex}`
	total_memsize=`expr ${total_memsize} + ${size}`
done

linuxsys_memsize=`expr ${total_memsize} - ${reserved_memsize} - ${available_memsize}`
mem_resv="$(dtb_sizeht ${linuxsys_memsize} 7) linux-sys"
res_disp "${mem_resv}"

mem_resv="$(dtb_sizeht ${total_memsize} 7) total"
res_disp "${mem_resv}"

echo "------------------ ---------- ---------- <memory region>----------"
memblk=0
for memblkx in ${memblks}; do
	membasehex=`echo "${memblkx}" | awk -F ':' '{print $1}'`
	memsizehex=`echo "${memblkx}" | awk -F ':' '{print $2}'`
	membase=$(dtb_fmt ${membasehex} 16)
	memsize=$(dtb_fmt ${memsizehex} 8)
	if [ ${memblk} -eq 0 ]; then
		memsizeht=$(dtb_sizehtx ${memsizehex} 9)
		echo "${membase} ${memsize} ${memsizeht} `hostname`"
	else
		memsizeht=$(dtb_sizehtx ${memsizehex} 9)
		echo "${membase} ${memsize} ${memsizeht}"
	fi
	memblk=`expr ${memblk} + 1`
done

echo "------------------------------------------------------------------"

exit 0
