1#!/bin/sh -e 2# SPDX-License-Identifier: GPL-2.0-only 3# 4# Create eMMC block device image from boot, RPMB and user data images 5# 6# Copyright (c) Siemens, 2025 7# 8# Authors: 9# Jan Kiszka <jan.kiszka@siemens.com> 10# 11 12usage() { 13 echo "$0 [OPTIONS] USER_IMG[:SIZE] OUTPUT_IMG" 14 echo "" 15 echo "SIZE must be a power of 2 up to 2G and multiples of 512 byte from there on." 16 echo "If no SIZE is specified, the size of USER_ING will be used (rounded up)." 17 echo "" 18 echo "Supported options:" 19 echo " -b BOOT1_IMG[:SIZE] Add boot partitions. SIZE must be multiples of 128K. If" 20 echo " no SIZE is specified, the size of BOOT1_IMG will be" 21 echo " used (rounded up). BOOT1_IMG will be stored in boot" 22 echo " partition 1, and a boot partition 2 of the same size" 23 echo " will be created as empty (all zeros) unless -B is" 24 echo " specified as well." 25 echo " -B BOOT2_IMG Fill boot partition 2 with BOOT2_IMG. Must be combined" 26 echo " with -b which is also defining the partition size." 27 echo " -r RPMB_IMG[:SIZE] Add RPMB partition. SIZE must be multiples of 128K. If" 28 echo " no SIZE is specified, the size of RPMB_IMG will be" 29 echo " used (rounded up)." 30 echo " -h, --help This help" 31 echo "" 32 echo "All SIZE parameters support the units K, M, G. If SIZE is smaller than the" 33 echo "associated image, it will be truncated in the output image." 34 exit "$1" 35} 36 37process_size() { 38 name=$1 39 image_file=$2 40 alignment=$3 41 image_arg=$4 42 if [ "${image_arg#*:}" = "$image_arg" ]; then 43 if ! size=$(wc -c < "$image_file" 2>/dev/null); then 44 echo "Missing $name image '$image_file'." >&2 45 exit 1 46 fi 47 if [ "$alignment" = 128 ]; then 48 size=$(( (size + 128 * 1024 - 1) & ~(128 * 1024 - 1) )) 49 elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then 50 size=$(( (size + 511) & ~511 )) 51 elif [ $(( size & (size - 1) )) -gt 0 ]; then 52 n=0 53 while [ "$size" -gt 0 ]; do 54 size=$((size >> 1)) 55 n=$((n + 1)) 56 done 57 size=$((1 << n)) 58 fi 59 else 60 value="${image_arg#*:}" 61 if [ "${value%K}" != "$value" ]; then 62 size=${value%K} 63 multiplier=1024 64 elif [ "${value%M}" != "$value" ]; then 65 size=${value%M} 66 multiplier=$((1024 * 1024)) 67 elif [ "${value%G}" != "$value" ]; then 68 size=${value%G} 69 multiplier=$((1024 * 1024 * 1024)) 70 else 71 size=$value 72 multiplier=1 73 fi 74 # check if "$size" is a valid integer by doing a self-comparison 75 if [ "$size" -eq "$size" ] 2>/dev/null; then 76 size=$((size * multiplier)) 77 else 78 echo "Invalid value '$value' specified for $image_file image size." >&2 79 exit 1 80 fi 81 if [ "$alignment" = 128 ]; then 82 if [ $(( size & (128 * 1024 - 1) )) -ne 0 ]; then 83 echo "The $name image size must be multiples of 128K." >&2 84 exit 1 85 fi 86 elif [ $size -gt $((2 * 1024 * 1024 * 1024)) ]; then 87 if [ $(( size & 511)) -ne 0 ]; then 88 echo "The $name image size must be multiples of 512 (if >2G)." >&2 89 exit 1 90 fi 91 elif [ $(( size & (size - 1) )) -gt 0 ]; then 92 echo "The $name image size must be power of 2 (up to 2G)." >&2 93 exit 1 94 fi 95 fi 96 echo $size 97} 98 99check_truncation() { 100 image_file=$1 101 output_size=$2 102 if [ "$image_file" = "/dev/zero" ]; then 103 return 104 fi 105 if ! actual_size=$(wc -c < "$image_file" 2>/dev/null); then 106 echo "Missing image '$image_file'." >&2 107 exit 1 108 fi 109 if [ "$actual_size" -gt "$output_size" ]; then 110 echo "Warning: image '$image_file' will be truncated on output." 111 fi 112} 113 114userimg= 115outimg= 116bootimg1= 117bootimg2=/dev/zero 118bootsz=0 119rpmbimg= 120rpmbsz=0 121 122while [ $# -gt 0 ]; do 123 case "$1" in 124 -b) 125 shift 126 [ $# -ge 1 ] || usage 1 127 bootimg1=${1%%:*} 128 bootsz=$(process_size boot "$bootimg1" 128 "$1") 129 shift 130 ;; 131 -B) 132 shift 133 [ $# -ge 1 ] || usage 1 134 bootimg2=$1 135 shift 136 ;; 137 -r) 138 shift 139 [ $# -ge 1 ] || usage 1 140 rpmbimg=${1%%:*} 141 rpmbsz=$(process_size RPMB "$rpmbimg" 128 "$1") 142 shift 143 ;; 144 -h|--help) 145 usage 0 146 ;; 147 *) 148 if [ -z "$userimg" ]; then 149 userimg=${1%%:*} 150 usersz=$(process_size user "$userimg" U "$1") 151 elif [ -z "$outimg" ]; then 152 outimg=$1 153 else 154 usage 1 155 fi 156 shift 157 ;; 158 esac 159done 160 161[ -n "$outimg" ] || usage 1 162 163if [ "$bootsz" -gt $((32640 * 1024)) ]; then 164 echo "Boot image size is larger than 32640K." >&2 165 exit 1 166fi 167if [ "$rpmbsz" -gt $((16384 * 1024)) ]; then 168 echo "RPMB image size is larger than 16384K." >&2 169 exit 1 170fi 171 172echo "Creating eMMC image" 173 174truncate -s 0 "$outimg" 175pos=0 176 177if [ "$bootsz" -gt 0 ]; then 178 echo " Boot partition 1 and 2: $((bootsz / 1024))K each" 179 blocks=$(( bootsz / (128 * 1024) )) 180 check_truncation "$bootimg1" "$bootsz" 181 dd if="$bootimg1" of="$outimg" conv=sparse bs=128K count=$blocks \ 182 status=none 183 check_truncation "$bootimg2" "$bootsz" 184 dd if="$bootimg2" of="$outimg" conv=sparse bs=128K count=$blocks \ 185 seek=$blocks status=none 186 pos=$((2 * bootsz)) 187fi 188 189if [ "$rpmbsz" -gt 0 ]; then 190 echo " RPMB partition: $((rpmbsz / 1024))K" 191 blocks=$(( rpmbsz / (128 * 1024) )) 192 check_truncation "$rpmbimg" "$rpmbsz" 193 dd if="$rpmbimg" of="$outimg" conv=sparse bs=128K count=$blocks \ 194 seek=$(( pos / (128 * 1024) )) status=none 195 pos=$((pos + rpmbsz)) 196fi 197 198if [ "$usersz" -lt 1024 ]; then 199 echo " User data: $usersz bytes" 200elif [ "$usersz" -lt $((1024 * 1024)) ]; then 201 echo " User data: $(( (usersz + 1023) / 1024 ))K ($usersz)" 202elif [ "$usersz" -lt $((1024 * 1024 * 1024)) ]; then 203 echo " User data: $(( (usersz + 1048575) / 1048576))M ($usersz)" 204else 205 echo " User data: $(( (usersz + 1073741823) / 1073741824))G ($usersz)" 206fi 207check_truncation "$userimg" "$usersz" 208dd if="$userimg" of="$outimg" conv=sparse bs=128K seek=$(( pos / (128 * 1024) )) \ 209 count=$(( (usersz + 128 * 1024 - 1) / (128 * 1024) )) status=none 210pos=$((pos + usersz)) 211truncate -s $pos "$outimg" 212 213echo "" 214echo "Instantiate by appending to the qemu command line:" 215echo " -drive file=$outimg,if=none,format=raw,id=emmc-img" 216echo " -device emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img" 217