diff --git a/kdump-lib.sh b/kdump-lib.sh
index 9a21a18..5edb549 100755
--- a/kdump-lib.sh
+++ b/kdump-lib.sh
@@ -993,62 +993,125 @@ has_aarch64_smmu()
 	ls /sys/devices/platform/arm-smmu-* 1> /dev/null 2>&1
 }
 
-# $1 crashkernel=""
-# $2 delta in unit of MB
-_crashkernel_add()
+is_memsize() { [[ "$1" =~ ^[+-]?[0-9]+[KkMmGg]?$ ]]; }
+
+# range defined for crashkernel parameter
+# i.e. <start>-[<end>]
+is_memrange()
+{
+	is_memsize "${1%-*}" || return 1
+	[[ -n ${1#*-} ]] || return 0
+	is_memsize "${1#*-}"
+}
+
+to_bytes()
+{
+	local _s
+
+	_s="$1"
+	is_memsize "$_s" || return 1
+
+	case "${_s: -1}" in
+		K|k)
+			_s=${_s::-1}
+			_s="$((_s * 1024))"
+			;;
+		M|m)
+			_s=${_s::-1}
+			_s="$((_s * 1024 * 1024))"
+			;;
+		G|g)
+			_s=${_s::-1}
+			_s="$((_s * 1024 * 1024 * 1024))"
+			;;
+		*)
+			;;
+	esac
+	echo "$_s"
+}
+
+memsize_add()
+{
+	local -a units=("" "K" "M" "G")
+	local i a b
+
+	a=$(to_bytes "$1") || return 1
+	b=$(to_bytes "$2") || return 1
+	i=0
+
+	(( a += b ))
+	while :; do
+		[[ $(( a / 1024 )) -eq 0 ]] && break
+		[[ $(( a % 1024 )) -ne 0 ]] && break
+		[[ $(( ${#units[@]} - 1 )) -eq $i ]] && break
+
+		(( a /= 1024 ))
+		(( i += 1 ))
+	done
+
+	echo "${a}${units[$i]}"
+}
+
+_crashkernel_parse()
 {
-	local _ck _add _entry _ret
-	local _range _size _offset
+	local ck entry
+	local range size offset
 
-	_ck="$1"
-	_add="$2"
-	_ret=""
+	ck="$1"
 
-	if [[ "$_ck" == *@* ]]; then
-		_offset="@${_ck##*@}"
-		_ck=${_ck%@*}
-	elif [[ "$_ck" == *,high ]] || [[ "$_ck" == *,low ]]; then
-		_offset=",${_ck##*,}"
-		_ck=${_ck%,*}
+	if [[ "$ck" == *@* ]]; then
+		offset="@${ck##*@}"
+		ck=${ck%@*}
+	elif [[ "$ck" == *,high ]] || [[ "$ck" == *,low ]]; then
+		offset=",${ck##*,}"
+		ck=${ck%,*}
 	else
-		_offset=''
+		offset=''
 	fi
 
-	while read -d , -r _entry; do
-		[[ -n "$_entry" ]] || continue
-		if [[ "$_entry" == *:* ]]; then
-			_range=${_entry%:*}
-			_size=${_entry#*:}
+	while read -d , -r entry; do
+		[[ -n "$entry" ]] || continue
+		if [[ "$entry" == *:* ]]; then
+			range=${entry%:*}
+			size=${entry#*:}
 		else
-			_range=""
-			_size=${_entry}
+			range=""
+			size=${entry}
 		fi
 
-		case "${_size: -1}" in
-			K)
-				_size=${_size::-1}
-				_size="$((_size + (_add * 1024)))K"
-				;;
-			M)
-				_size=${_size::-1}
-				_size="$((_size + _add))M"
-				;;
-			G)
-				_size=${_size::-1}
-				_size="$((_size * 1024 + _add))M"
-				;;
-			*)
-				_size="$((_size + (_add * 1024 * 1024)))"
-				;;
-		esac
+		echo "$size;$range;"
+	done <<< "$ck,"
+	echo ";;$offset"
+}
+
+# $1 crashkernel command line parameter
+# $2 size to be added
+_crashkernel_add()
+{
+	local ck delta ret
+	local range size offset
+
+	ck="$1"
+	delta="$2"
+	ret=""
+
+	while IFS=';' read -r size range offset; do
+		if [[ -n "$offset" ]]; then
+			ret="${ret%,}$offset"
+			break
+		fi
+
+		[[ -n "$size" ]] || continue
+		if [[ -n "$range" ]]; then
+			is_memrange "$range" || return 1
+			ret+="$range:"
+		fi
 
-		[[ -n "$_range" ]] && _ret+="$_range:"
-		_ret+="$_size,"
-	done <<< "$_ck,"
+		size=$(memsize_add "$size" "$delta") || return 1
+		ret+="$size,"
+	done < <( _crashkernel_parse "$ck")
 
-	_ret=${_ret%,}
-	[[ -n "$_offset" ]] && _ret+=$_offset
-	echo "$_ret"
+	echo "${ret%,}"
 }
 
 # get default crashkernel
@@ -1098,7 +1161,7 @@ kdump_get_arch_recommend_crashkernel()
 			#4k kernel, mlx5 consumes extra 124M memory, and choose 150M
 			has_mlx5 && ((_delta += 150))
 		fi
-		_ck_cmdline=$(_crashkernel_add "$_ck_cmdline" "$_delta")
+		_ck_cmdline=$(_crashkernel_add "$_ck_cmdline" "${_delta}M")
 	elif [[ $_arch == "ppc64le" ]]; then
 		if [[ $_dump_mode == "fadump" ]]; then
 			_ck_cmdline="4G-16G:768M,16G-64G:1G,64G-128G:2G,128G-1T:4G,1T-2T:6G,2T-4T:12G,4T-8T:20G,8T-16T:36G,16T-32T:64G,32T-64T:128G,64T-:180G"