qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <philmd@linaro.org>
To: Jan Kiszka <jan.kiszka@siemens.com>, qemu-devel <qemu-devel@nongnu.org>
Cc: "Bin Meng" <bmeng.cn@gmail.com>,
	qemu-block@nongnu.org,
	"Ilias Apalodimas" <ilias.apalodimas@linaro.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Jan Lübbe" <jlu@pengutronix.de>,
	"Jerome Forissier" <jerome.forissier@linaro.org>,
	"Eric Blake" <eblake@redhat.com>
Subject: Re: [PATCH v5 5/6] scripts: Add helper script to generate eMMC block device images
Date: Mon, 3 Nov 2025 14:12:04 +0100	[thread overview]
Message-ID: <bfd49f9a-0a37-4e1d-b7e2-f0e59943915e@linaro.org> (raw)
In-Reply-To: <5c9c6495ad4afc9d11f856bafcb797fed8fccecc.1760702638.git.jan.kiszka@siemens.com>

Hi Jan,

On 17/10/25 14:03, Jan Kiszka wrote:
> From: Jan Kiszka <jan.kiszka@siemens.com>
> 
> 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>
> ---
>   scripts/mkemmc.sh | 218 ++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 218 insertions(+)
>   create mode 100755 scripts/mkemmc.sh
> 
> diff --git a/scripts/mkemmc.sh b/scripts/mkemmc.sh
> new file mode 100755
> index 0000000000..1a2b7a6193
> --- /dev/null
> +++ b/scripts/mkemmc.sh
> @@ -0,0 +1,218 @@
> +#!/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>
> +#
> +# This work is licensed under the terms of the GNU GPL version 2.
> +# See the COPYING file in the top-level directory.
> +#
> +
> +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=$(stat -L -c %s "$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
> +        if [ "$size" -eq "$size" ] 2>/dev/null; then

I don't get this check, should one be "$value"?

> +            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=$(stat -L -c %s "$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

Running on macOS:

scripts/mkemmc.sh: line 165: [: : integer expression expected
scripts/mkemmc.sh: line 169: [: : integer expression expected
scripts/mkemmc.sh: line 179: [: : integer expression expected
scripts/mkemmc.sh: line 191: [: : integer expression expected
scripts/mkemmc.sh: line 200: [: : integer expression expected
scripts/mkemmc.sh: line 202: [: : integer expression expected
scripts/mkemmc.sh: line 204: [: : integer expression expected

$ sh --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin24)

When using dash:

scripts/mkemmc.sh: 165: [: Illegal number:
scripts/mkemmc.sh: 169: [: Illegal number:
scripts/mkemmc.sh: 179: [: Illegal number:
scripts/mkemmc.sh: 191: [: Illegal number:
scripts/mkemmc.sh: 200: [: Illegal number:
scripts/mkemmc.sh: 202: [: Illegal number:
scripts/mkemmc.sh: 204: [: Illegal number:

Should we replace s/[/[[/?

> +    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 "$outimg" -s 0
I'd replace here by:
    truncate -s 0 "$outimg"

to avoid on macOS:

usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...
        truncate [-c] -r rfile file ...

> +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 "$outimg" -s $pos

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"



  reply	other threads:[~2025-11-03 13:13 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-17 12:03 [PATCH v5 0/6] sd: Add RPMB emulation to eMMC model Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 1/6] hw/sd/sdcard: Fix size check for backing block image Jan Kiszka
2025-10-20  7:29   ` Cédric Le Goater
2025-10-30 22:10   ` Philippe Mathieu-Daudé
2025-10-17 12:03 ` [PATCH v5 2/6] hw/sd/sdcard: Allow user-instantiated eMMC Jan Kiszka
2025-10-27 11:55   ` Daniel P. Berrangé
2025-10-27 12:23     ` Philippe Mathieu-Daudé
2025-10-27 12:35       ` Daniel P. Berrangé
2025-10-27 12:44         ` Philippe Mathieu-Daudé
2025-10-30 14:17           ` Jan Lübbe
2025-10-27 12:45       ` Jan Lübbe
2025-10-30 16:50   ` Jan Lübbe
2025-10-30 18:10     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 3/6] hw/sd/sdcard: Add basic support for RPMB partition Jan Kiszka
2025-11-03 15:08   ` Philippe Mathieu-Daudé
2025-11-04  6:34     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 4/6] hw/sd/sdcard: Handle RPMB MAC field Jan Kiszka
2025-11-03 15:18   ` Philippe Mathieu-Daudé
2025-11-04  6:43     ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 5/6] scripts: Add helper script to generate eMMC block device images Jan Kiszka
2025-11-03 13:12   ` Philippe Mathieu-Daudé [this message]
2025-11-04  6:30     ` Jan Kiszka
2025-11-04  9:26       ` Jan Kiszka
2025-11-04 12:33         ` Philippe Mathieu-Daudé
2025-11-04 12:40           ` Jan Kiszka
2025-11-04 14:14             ` Jan Kiszka
2025-10-17 12:03 ` [PATCH v5 6/6] docs: Add eMMC device model description Jan Kiszka
2025-11-03 13:15   ` Philippe Mathieu-Daudé
2025-10-20  7:28 ` [PATCH v5 0/6] sd: Add RPMB emulation to eMMC model Cédric Le Goater
2025-10-27 11:15 ` Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bfd49f9a-0a37-4e1d-b7e2-f0e59943915e@linaro.org \
    --to=philmd@linaro.org \
    --cc=alex.bennee@linaro.org \
    --cc=bmeng.cn@gmail.com \
    --cc=eblake@redhat.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=jan.kiszka@siemens.com \
    --cc=jerome.forissier@linaro.org \
    --cc=jlu@pengutronix.de \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).