scripts: Add helper script to generate eMMC block device images
As an eMMC block device image may consist of more than just the user data partition, provide a helper script that can compose the image from boot partitions, an RPMB partition and the user data image. The script also does the required size validation and/or rounding. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <eecefa8e-44ae-45ff-85d0-3f9b786948e0@siemens.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
parent
3acf956ea1
commit
2f00451fbe
1 changed files with 216 additions and 0 deletions
216
scripts/mkemmc.sh
Executable file
216
scripts/mkemmc.sh
Executable file
|
|
@ -0,0 +1,216 @@
|
|||
#!/bin/sh -e
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Create eMMC block device image from boot, RPMB and user data images
|
||||
#
|
||||
# Copyright (c) Siemens, 2025
|
||||
#
|
||||
# Authors:
|
||||
# Jan Kiszka <jan.kiszka@siemens.com>
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "$0 [OPTIONS] USER_IMG[:SIZE] OUTPUT_IMG"
|
||||
echo ""
|
||||
echo "SIZE must be a power of 2 up to 2G and multiples of 512 byte from there on."
|
||||
echo "If no SIZE is specified, the size of USER_ING will be used (rounded up)."
|
||||
echo ""
|
||||
echo "Supported options:"
|
||||
echo " -b BOOT1_IMG[:SIZE] Add boot partitions. SIZE must be multiples of 128K. If"
|
||||
echo " no SIZE is specified, the size of BOOT1_IMG will be"
|
||||
echo " used (rounded up). BOOT1_IMG will be stored in boot"
|
||||
echo " partition 1, and a boot partition 2 of the same size"
|
||||
echo " will be created as empty (all zeros) unless -B is"
|
||||
echo " specified as well."
|
||||
echo " -B BOOT2_IMG Fill boot partition 2 with BOOT2_IMG. Must be combined"
|
||||
echo " with -b which is also defining the partition size."
|
||||
echo " -r RPMB_IMG[:SIZE] Add RPMB partition. SIZE must be multiples of 128K. If"
|
||||
echo " no SIZE is specified, the size of RPMB_IMG will be"
|
||||
echo " used (rounded up)."
|
||||
echo " -h, --help This help"
|
||||
echo ""
|
||||
echo "All SIZE parameters support the units K, M, G. If SIZE is smaller than the"
|
||||
echo "associated image, it will be truncated in the output image."
|
||||
exit "$1"
|
||||
}
|
||||
|
||||
process_size() {
|
||||
name=$1
|
||||
image_file=$2
|
||||
alignment=$3
|
||||
image_arg=$4
|
||||
if [ "${image_arg#*:}" = "$image_arg" ]; then
|
||||
if ! size=$(wc -c < "$image_file" 2>/dev/null); then
|
||||
echo "Missing $name image '$image_file'." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$alignment" = 128 ]; then
|
||||
size=$(( (size + 128 * 1024 - 1) & ~(128 * 1024 - 1) ))
|
||||
elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then
|
||||
size=$(( (size + 511) & ~511 ))
|
||||
elif [ $(( size & (size - 1) )) -gt 0 ]; then
|
||||
n=0
|
||||
while [ "$size" -gt 0 ]; do
|
||||
size=$((size >> 1))
|
||||
n=$((n + 1))
|
||||
done
|
||||
size=$((1 << n))
|
||||
fi
|
||||
else
|
||||
value="${image_arg#*:}"
|
||||
if [ "${value%K}" != "$value" ]; then
|
||||
size=${value%K}
|
||||
multiplier=1024
|
||||
elif [ "${value%M}" != "$value" ]; then
|
||||
size=${value%M}
|
||||
multiplier=$((1024 * 1024))
|
||||
elif [ "${value%G}" != "$value" ]; then
|
||||
size=${value%G}
|
||||
multiplier=$((1024 * 1024 * 1024))
|
||||
else
|
||||
size=$value
|
||||
multiplier=1
|
||||
fi
|
||||
# check if "$size" is a valid integer by doing a self-comparison
|
||||
if [ "$size" -eq "$size" ] 2>/dev/null; then
|
||||
size=$((size * multiplier))
|
||||
else
|
||||
echo "Invalid value '$value' specified for $image_file image size." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$alignment" = 128 ]; then
|
||||
if [ $(( size & (128 * 1024 - 1) )) -ne 0 ]; then
|
||||
echo "The $name image size must be multiples of 128K." >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then
|
||||
if [ $(( size & 511)) -ne 0 ]; then
|
||||
echo "The $name image size must be multiples of 512 (if >2G)." >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [ $(( size & (size - 1) )) -gt 0 ]; then
|
||||
echo "The $name image size must be power of 2 (up to 2G)." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo $size
|
||||
}
|
||||
|
||||
check_truncation() {
|
||||
image_file=$1
|
||||
output_size=$2
|
||||
if [ "$image_file" = "/dev/zero" ]; then
|
||||
return
|
||||
fi
|
||||
if ! actual_size=$(wc -c < "$image_file" 2>/dev/null); then
|
||||
echo "Missing image '$image_file'." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$actual_size" -gt "$output_size" ]; then
|
||||
echo "Warning: image '$image_file' will be truncated on output."
|
||||
fi
|
||||
}
|
||||
|
||||
userimg=
|
||||
outimg=
|
||||
bootimg1=
|
||||
bootimg2=/dev/zero
|
||||
bootsz=0
|
||||
rpmbimg=
|
||||
rpmbsz=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-b)
|
||||
shift
|
||||
[ $# -ge 1 ] || usage 1
|
||||
bootimg1=${1%%:*}
|
||||
bootsz=$(process_size boot "$bootimg1" 128 "$1")
|
||||
shift
|
||||
;;
|
||||
-B)
|
||||
shift
|
||||
[ $# -ge 1 ] || usage 1
|
||||
bootimg2=$1
|
||||
shift
|
||||
;;
|
||||
-r)
|
||||
shift
|
||||
[ $# -ge 1 ] || usage 1
|
||||
rpmbimg=${1%%:*}
|
||||
rpmbsz=$(process_size RPMB "$rpmbimg" 128 "$1")
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage 0
|
||||
;;
|
||||
*)
|
||||
if [ -z "$userimg" ]; then
|
||||
userimg=${1%%:*}
|
||||
usersz=$(process_size user "$userimg" U "$1")
|
||||
elif [ -z "$outimg" ]; then
|
||||
outimg=$1
|
||||
else
|
||||
usage 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -n "$outimg" ] || usage 1
|
||||
|
||||
if [ "$bootsz" -gt $((32640 * 1024)) ]; then
|
||||
echo "Boot image size is larger than 32640K." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$rpmbsz" -gt $((16384 * 1024)) ]; then
|
||||
echo "RPMB image size is larger than 16384K." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating eMMC image"
|
||||
|
||||
truncate -s 0 "$outimg"
|
||||
pos=0
|
||||
|
||||
if [ "$bootsz" -gt 0 ]; then
|
||||
echo " Boot partition 1 and 2: $((bootsz / 1024))K each"
|
||||
blocks=$(( bootsz / (128 * 1024) ))
|
||||
check_truncation "$bootimg1" "$bootsz"
|
||||
dd if="$bootimg1" of="$outimg" conv=sparse bs=128K count=$blocks \
|
||||
status=none
|
||||
check_truncation "$bootimg2" "$bootsz"
|
||||
dd if="$bootimg2" of="$outimg" conv=sparse bs=128K count=$blocks \
|
||||
seek=$blocks status=none
|
||||
pos=$((2 * bootsz))
|
||||
fi
|
||||
|
||||
if [ "$rpmbsz" -gt 0 ]; then
|
||||
echo " RPMB partition: $((rpmbsz / 1024))K"
|
||||
blocks=$(( rpmbsz / (128 * 1024) ))
|
||||
check_truncation "$rpmbimg" "$rpmbsz"
|
||||
dd if="$rpmbimg" of="$outimg" conv=sparse bs=128K count=$blocks \
|
||||
seek=$(( pos / (128 * 1024) )) status=none
|
||||
pos=$((pos + rpmbsz))
|
||||
fi
|
||||
|
||||
if [ "$usersz" -lt 1024 ]; then
|
||||
echo " User data: $usersz bytes"
|
||||
elif [ "$usersz" -lt $((1024 * 1024)) ]; then
|
||||
echo " User data: $(( (usersz + 1023) / 1024 ))K ($usersz)"
|
||||
elif [ "$usersz" -lt $((1024 * 1024 * 1024)) ]; then
|
||||
echo " User data: $(( (usersz + 1048575) / 1048576))M ($usersz)"
|
||||
else
|
||||
echo " User data: $(( (usersz + 1073741823) / 1073741824))G ($usersz)"
|
||||
fi
|
||||
check_truncation "$userimg" "$usersz"
|
||||
dd if="$userimg" of="$outimg" conv=sparse bs=128K seek=$(( pos / (128 * 1024) )) \
|
||||
count=$(( (usersz + 128 * 1024 - 1) / (128 * 1024) )) status=none
|
||||
pos=$((pos + usersz))
|
||||
truncate -s $pos "$outimg"
|
||||
|
||||
echo ""
|
||||
echo "Instantiate by appending to the qemu command line:"
|
||||
echo " -drive file=$outimg,if=none,format=raw,id=emmc-img"
|
||||
echo " -device emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img"
|
||||
Loading…
Add table
Add a link
Reference in a new issue