master
sh 216 lines 6.94 KB
Raw
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
12 usage() {
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
37 process_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 2>/dev/null < "$image_file"); 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
99 check_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 2>/dev/null < "$image_file"); 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
114 userimg=
115 outimg=
116 bootimg1=
117 bootimg2=/dev/zero
118 bootsz=0
119 rpmbimg=
120 rpmbsz=0
121
122 while [ $# -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
159 done
160
161 [ -n "$outimg" ] || usage 1
162
163 if [ "$bootsz" -gt $((32640 * 1024)) ]; then
164 echo "Boot image size is larger than 32640K." >&2
165 exit 1
166 fi
167 if [ "$rpmbsz" -gt $((16384 * 1024)) ]; then
168 echo "RPMB image size is larger than 16384K." >&2
169 exit 1
170 fi
171
172 echo "Creating eMMC image"
173
174 truncate -s 0 "$outimg"
175 pos=0
176
177 if [ "$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))
187 fi
188
189 if [ "$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))
196 fi
197
198 if [ "$usersz" -lt 1024 ]; then
199 echo " User data: $usersz bytes"
200 elif [ "$usersz" -lt $((1024 * 1024)) ]; then
201 echo " User data: $(( (usersz + 1023) / 1024 ))K ($usersz)"
202 elif [ "$usersz" -lt $((1024 * 1024 * 1024)) ]; then
203 echo " User data: $(( (usersz + 1048575) / 1048576))M ($usersz)"
204 else
205 echo " User data: $(( (usersz + 1073741823) / 1073741824))G ($usersz)"
206 fi
207 check_truncation "$userimg" "$usersz"
208 dd if="$userimg" of="$outimg" conv=sparse bs=128K seek=$(( pos / (128 * 1024) )) \
209 count=$(( (usersz + 128 * 1024 - 1) / (128 * 1024) )) status=none
210 pos=$((pos + usersz))
211 truncate -s $pos "$outimg"
212
213 echo ""
214 echo "Instantiate by appending to the qemu command line:"
215 echo " -drive file=$outimg,if=none,format=raw,id=emmc-img"
216 echo " -device emmc,boot-partition-size=$bootsz,rpmb-partition-size=$rpmbsz,drive=emmc-img"