forked from lf-edge/eve
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmake-raw
executable file
·669 lines (582 loc) · 22.8 KB
/
make-raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
#!/bin/sh
# shellcheck shell=dash
#
# This script creates a raw disk image partitioned with GPT partition table
# and set up for UEFI boot sequence with a GRUB UEFI payload and a default
# grub.cfg attempting to chainload GRUB from one of the actual rootfs
# partitions. This means that at the very minimum the output of this script
# will produce a disk that looks like:
#
# +----------------------------+
# | UEFI partition |
# | w/ GRUB + grub.cfg |
# +----------------------------+
# | rootfs partition w/GRUB |
# +----------------------------+
#
# In addition to producing this minimalistic (but fully functional!) layout,
# this script is also capable of initializing a few additional partitions
# that are required for live upgrade and configuration:
# * 2nd rootfs partition
# * /config partition
# * /persist partition
#
# The script CLI UX is really not user friendly for now, since it is expected
# to be called mostly from other scripts (and also linuxkit VMs).
# The syntax is:
# [-C] [-r] <img> [part1...]
#
# -C recreate disk image
# -r use random_disk_uuids (old behavior)
# <img> file name of the raw disk image (we expect it to be pre-created and
# sized correctly OR be an actual physical device)
# [part1...] list of partitions to be created: efi imga imgb conf persist
# Can be omitted. Default is: efi imga imgb conf persist
#
# On stdin, this scripts expects to receive a tarball full of partition images
# that will be used to pre-populate actual partitions it creates. This tarball
# is going to be received from stdin and extracted into /parts folder. This means,
# of course, that if you don't supply a tarball stream to the script you can just
# pre-populate /parts with the same images:
# * rootfs*.img for rootfs partition
# * config.tar for config partition
#
set -e
[ -n "$DEBUG" ] && set -x
RANDOM_DISK_UUIDS=
while getopts Cr o
do case "$o" in
C) CREATE_IMG=1;;
r) RANDOM_DISK_UUIDS="-r";;
[?]) echo "Usage: $0 [-C] [-r] <img> [parts...]"
exit 1;;
esac
done
shift $((OPTIND-1))
IMGFILE=$1
shift
PARTS=${*:-"efi imga imgb conf persist"}
# This is the only partition type that PARTITION_TYPE_USR_X86_64
# grub-core/commands/gptprio.c code will pay attention to
PARTITION_TYPE_USR_X86_64=5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6
# The static UUIDs for the disk and the partitions
# Also in install and storage-init.sh
DISK_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30050
EFI_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30051
IMGA_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30052
IMGB_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30053
CONF_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30054
PERSIST_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30059
INSTALLER_UUID=ad6871ee-31f9-4cf3-9e09-6f7a25c30060
# content of rootfs partition
ROOTFS_IMG=/parts/rootfs.img
# contents of installer partition
INSTALLER_IMG=/parts/installer.img
# content of conf partition
CONF_FILE=/parts/config.img
# content of persist partition
PERSIST_FILE=/parts/persist.img
# EFI boot directory
EFI_DIR=/parts/EFI
# early bootloader directory (optional)
BOOT_DIR=/parts/boot
# content of initrd installer image (optional)
INITRD_IMG=/parts/initrd.img
# IMX8 flash blob that needs to be written to image
IMX8_BLOB=/parts/imx8-flash.bin
# IMX8 configuration file with flashing parameters
IMX8_CONF=/parts/imx8-flash.conf
# EFI partition size in bytes
EFI_PART_SIZE=$((36 * 1024 * 1024))
# Min rootfs partition size in bytes
# Warning: don't change the rootfs partition size, before
# Warning: fixing the EVE upgrade logic, which should find
# Warning: free space and rellocate all tables if image has
# Warning: been bloated.
ROOTFS_PART_SIZE_MIN=$((512 * 1024 * 1024))
# conf partition size in bytes
CONF_PART_SIZE=$((1024 * 1024))
# installer inventory partition size in bytes
WIN_INVENTORY_PART_SIZE=$((40240 * 1024))
# resulting FAT FS image size factor for installer
# 1.5 is enough for FAT to keep all our files.
INSTALLER_PART_SIZE_FACTOR="1.5"
# imx8 boot blob size in bytes
IMX8_BLOB_SIZE=$(( 8 * 1024 * 1024 ))
# sector where the first partition starts on a blank disk
FIRST_PART_SEC=2048
# offset in the GPT partition table from which we can start our numbering
# this may change, so we only set the actual values when we know the final
# PART_OFFSET
PART_OFFSET=0
# the rest of these are which partition number in the GPT table each one is,
# relative to the beginning of PART_OFFSET
SYSTEM_VFAT_PART_OFFSET=1
VFAT_PART_OFFSET=4
IMGA_PART_OFFSET=2
IMGB_PART_OFFSET=3
EFI_PART_OFFSET=1
CONF_PART_OFFSET=4
PERSIST_PART_OFFSET=9
INVENTORY_WIN_PART_OFFSET=5
INSTALLER_PART_OFFSET=6
USB_CONF_PART_OFFSET=1
# starting sector for our portion of the disk
CUR_SEC="$FIRST_PART_SEC"
sgdisk() {
# filter out annoying messages we can't get rid of:
# https://github.com/kini/gptfdisk/blob/master/diskio-unix.cc#L153
local OUT
local RET
OUT=$(/usr/bin/sgdisk "$@" 2>&1)
RET=$?
echo "$OUT" | grep -Ev "$(echo '^Disk device is
when determining sector size! Setting sector size to 512
Warning: The kernel is still using the old partition table
The new table will be used at the next reboot or after you
run partprobe.*or kpartx
The operation has completed successfully.' | tr '\012' '|')$^" || :
return $RET
}
imx8_exists() {
[ -f "$IMX8_BLOB" ] && [ -f "$IMX8_CONF" ]
}
file_size() {
stat -L -c %s "$1" 2>/dev/null || echo "0"
}
calc_rootfs_part_size() {
local SIZE
SIZE=$(file_size "$ROOTFS_IMG")
# Take max
SIZE=$((SIZE > ROOTFS_PART_SIZE_MIN ? SIZE : ROOTFS_PART_SIZE_MIN))
echo $SIZE
}
calc_installer_part_size() {
local MB
local SIZE
MB=$((1<<20))
# Add extra 1MB to be on the safe side in all our calculations
SIZE=$MB
SIZE=$((SIZE + $(file_size "$INSTALLER_IMG")))
if imx8_exists; then
SIZE=$((SIZE + $(file_size "$IMX8_BLOB")))
SIZE=$((SIZE + $(file_size "$IMX8_CONF")))
fi
# Round up on 1MB
SIZE=$(((SIZE + MB - 1) / MB * MB))
# /1 for integer
echo "$SIZE"
}
# calc_image_size() - calculates overall size required for the whole image
# with specified partitions
calc_image_size() {
local MB
local SIZE
SIZE=0
# Account every requested partition
for p in $PARTS ; do
case $p in
efi)
SIZE=$((SIZE + EFI_PART_SIZE))
;;
conf_win | conf)
SIZE=$((SIZE + CONF_PART_SIZE))
;;
inventory_win)
SIZE=$((SIZE + WIN_INVENTORY_PART_SIZE))
;;
imga)
SIZE=$((SIZE + $(calc_rootfs_part_size)))
;;
imgb)
SIZE=$((SIZE + $(calc_rootfs_part_size)))
;;
installer)
SIZE=$((SIZE + $(calc_installer_part_size)))
;;
persist)
SIZE=$((SIZE + $(file_size "$PERSIST_FILE")))
;;
*)
echo "Unknown partition: $p"
exit 1
;;
esac
done
# Account for IMX8 blob if needed
if imx8_exists; then
SIZE=$((SIZE + IMX8_BLOB_SIZE))
fi
MB=$((1<<20))
# Add extra 10MB to be on the safe side in all our calculations
SIZE=$((SIZE + 10*MB))
# Round up on 1MB
SIZE=$(((SIZE + MB - 1) / MB * MB))
echo $SIZE
}
cp_with_backup() {
local MD5_SUM=$(md5sum "$2" | cut -f1 -d\ )
[ -f "$2".$MD5_SUM ] || cp "$2" "$2".$MD5_SUM
[ $? -eq 0 ] && cp "$1" "$2"
}
grow_part() {
local MB
local IMAGE_SIZE
# Round up to 1MB as a requirement of some firmwares
MB=$((1<<20))
IMAGE_SIZE=$((($2 + MB - 1) / MB * MB))
# The output is the last sector
echo $(($1 + (IMAGE_SIZE >> 9) - 1))
}
dir2vfat() {
# <img name> dir2vfat <dir> <image size> [label]
local IMG=`mktemp -u -p /tmp/data`
local LABEL=${3:-EVE}
local FORCE_FAT32="-F32"
# FAT32 can only reside on disks larger than 33Mb
[ "$2" -lt 33792 ] && FORCE_FAT32="-v"
(rm -rf /tmp/data
mkdir /tmp/data
mkfs.vfat "$FORCE_FAT32" -v -n "$LABEL" -C "$IMG" "$2"
mcopy -i $IMG -s $1/* ::/ ) >&2
echo $IMG
}
do_system_vfat_part() {
eval "local SEC_START=\$$1"
local SEC_END="$(grow_part "$SEC_START" "$2")"
local NUM_PART=$3
local SOURCEDIR=$4
local PART_TYPE="ef00"
local partlabel='EFI System'
PROTECTIVE_MBR_LIST="$PROTECTIVE_MBR_LIST$NUM_PART:"
# Create a partition
sgdisk --new "$NUM_PART:$SEC_START:$SEC_END" \
--typecode="$NUM_PART:$PART_TYPE" \
--change-name="$NUM_PART:$partlabel" \
--attributes "$NUM_PART:set:2" \
"$IMGFILE"
# ...copy EFI fs to EFI partition
dd if="$(dir2vfat $SOURCEDIR $(( (SEC_END - SEC_START) / 2)))" of="$IMGFILE" bs=1M conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
eval "$1=$((SEC_END + 1))"
}
# do_efi create the EFI partition and copy the bootloaders and other boot pieces needed.
do_efi() {
eval "local SEC_START=\$$1"
local customparts=$2
# Create EFI partition and include the bootloaders
rm -rf /efifs/*
cp -Lr "$EFI_DIR" /efifs/EFI
# the grub.cfg.in is embedded in the script to avoid any external filesystem dependency for this make-raw script
sed -e 's#@PATH_TO_GRUB@#'"$(cd /efifs; echo EFI/BOOT/BOOT*EFI)"'#' > /efifs/EFI/BOOT/grub.cfg <<'EOF'
# this finds the next available bootable partition in GPT, with the highest priority
# and sets the value of the device it is on to $dev, and the uuid of the partition to $uuid
#
# to understand how this works, see pkg/grub/patches/0000-core-os-merge.patch
#
# it does the following:
# 1. Look for all GPT partitions on all storage devices it can find
# 2. Filter out for partitions marked as "successful", i.e. bootable to it, based on attribute bit 56 set; this is hard-coded in the patch as GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL
# if none successful, error out
# 3. See if any of the partitions has the priority bit set, based on attribute bit 48 set; this is hard-coded in the patch as GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY
# if none priority, use all successful; if 1 or more priority, continue with those
# 4. Of the remaining partitions, take the first one in order
#
# To change to a different partition, set the attribute bits appropriately
gptprio.next -d dev -u uuid
set root=$dev
chainloader ($dev)/@PATH_TO_GRUB@
boot
reboot
EOF
# Copy bootloaders to usb root
cp -r "$BOOT_DIR"/* /efifs/ 2>/dev/null || :
if [ -n "$customparts" ]; then
$customparts
fi
do_system_vfat_part "$1" "$EFI_PART_SIZE" $SYSTEM_VFAT_PART /efifs
if [ -z "$RANDOM_DISK_UUIDS" ]; then
sgdisk --partition-guid="$EFI_PART:$EFI_UUID" "$IMGFILE"
fi
}
do_efiinstaller() {
do_efi "$1" efi_installer_extension
}
efi_installer_extension() {
if imx8_exists; then
cp "$IMX8_BLOB" "$IMX8_CONF" /efifs
fi
# Copy bootloaders to boot folder for installer
mkdir -p /efifs/boot
touch /efifs/boot/.boot_repository
od -An -x -N 16 /dev/random | tr -d ' ' > /efifs/boot/.uuid
cp /UsbInvocationScript.txt /efifs
}
# do_installer prepares an installation image:
# 1. insert the installer image squashfs into a partition, and set that partition to boot.
# 2. copy the bits we need for installation - persist.img, rootfs.img - to the INSTALLERPARTS partition
do_installer() {
# install the installer.img as our bootable rootfs
do_rootfs $1 INSTALLER "$(calc_installer_part_size)" $INSTALLER_PART $INSTALLER_UUID $INSTALLER_IMG
}
do_rootfs() {
eval SEC_START=\$$1
LABEL=$2
local partsize=$3
local NUM_PART=$4
local IMG_UUID=$5
IMG=$6
local SEC_END=$(grow_part "$SEC_START" "$partsize")
# Calculate partition size and add a partition
sgdisk --new "$NUM_PART:$SEC_START:$SEC_END" \
--typecode="$NUM_PART:$PARTITION_TYPE_USR_X86_64" \
--change-name="$NUM_PART:$LABEL" $EXTRA_ATTR "$IMGFILE"
if [ -z "$RANDOM_DISK_UUIDS" ]; then
sgdisk --partition-guid="$NUM_PART:$IMG_UUID" "$IMGFILE"
fi
if [ -n "$IMG" ]; then
# Copy rootfs or installer
dd if="$IMG" of="$IMGFILE" bs=1M conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
else
# clean first block of partition
# to avoid mounting of stale data
dd if=/dev/zero of="$IMGFILE" bs=512 count=1 conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
fi
eval $1=$(( $SEC_END + 1))
}
do_imga() {
do_rootfs $1 IMGA $(calc_rootfs_part_size) $IMGA_PART $IMGA_UUID $ROOTFS_IMG
}
do_imgb() {
# for now we are wiping IMGB - hence not passing the source
do_rootfs $1 IMGB $(calc_rootfs_part_size) $IMGB_PART $IMGB_UUID
}
# create a VFAT partition with the specified UUID
do_vfat() {
eval local SEC_START=\$$1
local SEC_END=$(grow_part $SEC_START $2)
local NUM_PART=$3
local PART_TYPE=$4
local partlabel=$5
local partdatafile=$6
sgdisk --new $NUM_PART:$SEC_START:$SEC_END \
--typecode=$NUM_PART:$PART_TYPE \
--change-name="$NUM_PART:$partlabel" \
"$IMGFILE"
dd if=$partdatafile of=$IMGFILE bs=1M conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
eval $1=$(( $SEC_END + 1))
}
do_conf() {
do_vfat $1 $CONF_PART_SIZE $VFAT_PART 13307e62-cd9c-4920-8f9b-91b45828b798 CONFIG $CONF_FILE
if [ -z "$RANDOM_DISK_UUIDS" ]; then
local NUM_PART=$CONF_PART
sgdisk --partition-guid="$NUM_PART:$CONF_UUID" "$IMGFILE"
fi
}
do_conf_win() {
do_vfat $1 $CONF_PART_SIZE $VFAT_PART EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 CONFIG $CONF_FILE
}
do_inventory_win() {
eval local SEC_START="\$$1"
# shellcheck disable=SC2155
local SEC_END=$(grow_part "$SEC_START" "$WIN_INVENTORY_PART_SIZE")
local NUM_PART=$INVENTORY_WIN_PART
local PART_TYPE=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
PROTECTIVE_MBR_LIST="$PROTECTIVE_MBR_LIST${CONF_PART}:$NUM_PART:"
sgdisk --new "$NUM_PART:$SEC_START:$SEC_END" \
--typecode="$NUM_PART:$PART_TYPE" \
--change-name="$NUM_PART:INVENTORY" "$IMGFILE"
# shellcheck disable=SC2046
dd if=$(dir2vfat $(mktemp -d) $(( (SEC_END - SEC_START) / 2)) INVENTORY) of="$IMGFILE" bs=1M conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
eval "$1=$(( SEC_END + 1))"
}
do_persist() {
eval SEC_START=\$$1
# Persistent Purgeable Partition. It is set at partition
# number 9 to reserve the first 8 partitions to system types.
local NUM_PART=$PERSIST_PART
# P3 takes all space available
local SEC_END=0
sgdisk --new $NUM_PART:$SEC_START:$SEC_END \
--typecode=$NUM_PART:5f24425a-2dfa-11e8-a270-7b663faccc2c \
--change-name=$NUM_PART:'P3' $IMGFILE
if [ -z "$RANDOM_DISK_UUIDS" ]; then
sgdisk --partition-guid="$NUM_PART:$PERSIST_UUID" "$IMGFILE"
fi
dd if="$PERSIST_FILE" of="$IMGFILE" bs=1M conv=notrunc seek="$(( SEC_START * 512 ))" oflag=seek_bytes
eval $1=0
}
do_usb_conf() {
eval local SEC_START="\$$1"
# shellcheck disable=SC2155
local SEC_END=$(sgdisk -E "$IMGFILE")
local NUM_PART=$USB_CONF_PART
local PART_TYPE=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
local FAT_SIZE=$(( SEC_END - SEC_START ))
sgdisk --new "$NUM_PART:$SEC_START:$SEC_END" \
--typecode="$NUM_PART:$PART_TYPE" \
--change-name="$NUM_PART:DevicePortConfig" "$IMGFILE"
mformat -i "${IMGFILE}@@$(( SEC_START * 512 ))" -h $(( FAT_SIZE / 65535 + 1 )) -t 1 -s 65535 -l EVEDPC ::
mcopy -i "${IMGFILE}@@$(( SEC_START * 512 ))" /parts/* ::/
eval "$1=$(( SEC_END + 1))"
}
# This function deploys GRUB stage1 into MBR (sector 0) and GRUB stage2 into the gap between
# where GPT ends and first partition begins (sector 34 - sector FIRST_PART_SEC). It relies
# on the knowledge of where GRUB implementation stores the value for the 1st and 2nd sectors
# of stage2 (see the seek offsets for dd below). Whenever GRUB version changes there's a chance
# these offsets may change and will have to be adjusted accordingly as per:
# * grub-core/boot/i386/pc/boot.S kernel_sector
# * grub-core/boot/i386/pc/diskboot.S blocklist_default_start
# NOTE: theoretically one can patch grub-install to do this, but it requires much more hoop jumping
deploy_legacy_grub() {
# put GRUB stage1 loader into the MBR (don't overwrite MBR partition table -- hence size 446 not 512)
dd if=/efifs/EFI/BOOT/BOOT.img of="$IMGFILE" bs=446 count=1 conv=noerror,sync,notrunc
# embed GRUB stage2 into the gap between the end of GPT (sector 34) and start of the first partition (FIRST_PART_SEC)
dd if=/efifs/EFI/BOOT/BOOT.pc of="$IMGFILE" bs=512 seek=34 conv=noerror,sync,notrunc
# update locations where stage1 and stage2 store the value of the first (34 == \042)...
printf '\042' | dd of="$IMGFILE" bs=1 seek=92 count=1 conv=noerror,sync,notrunc
# ...and 2nd (35 == \043) sector of where stage2 is located on disk
printf '\043' | dd of="$IMGFILE" bs=1 seek=$((34 * 512 + 500)) count=1 conv=noerror,sync,notrunc
}
adjust_protective_mbr() {
# Since sgdisk by default puts protective partition first, we need to swap the
# order to make some legacy BIOS implementations happy. Strictly speaking, this
# goes against good recommendations of how to build a protective MBR for the GPT
# but it doesn't seem to cause any troubles and it helps with compatibility.
# On top of that we need to mark 1st MBR partition bootable and vfat type to
# make legacy BIOSes real happy:
(fdisk "$IMGFILE" > /dev/null <<__EOT__
M
a
1
t
1
c
w
q
__EOT__
) || :
# the : above is here to make sure fdisk doesn't get too upset about us not using
# an actual device, but a file instead. In the ideal world, we would be able to
# catch other errors, but this particular usecase of fdisk is so trivial, that we
# shouldn't be too concerned about missing much.
}
#
# Extract partitions from stdin if /parts not exists or empty
#
if [ ! -d /parts ] || [ -z "$(ls -A -- /parts)" ]; then
mkdir -p /parts
(cd /parts ; bsdtar xzf -)
fi
# Create image file
if [ -n "$CREATE_IMG" ]; then
SIZE=$(calc_image_size)
# Careful! This does not wipe out the image file if exists, only truncates
dd if=/dev/zero of="$IMGFILE" seek=$((SIZE - 1)) bs=1 count=1
fi
if imx8_exists; then
# For imx8 boards we need to write boot blob with the specified offset
IMX_BLOB_END_SEC=$(( IMX8_BLOB_SIZE / 512 ))
CUR_SEC="$IMX_BLOB_END_SEC"
IMG_SEEK=$(cat $IMX8_CONF | sed "/^#/d" | grep "^offset.*" | tr -d '[:space:]' | sed "s/offset=\(.*\)/\1/")
# If offset was not specified, use 32 as default
[ -z "$IMG_SEEK" ] && IMG_SEEK=32
# Write blob to image file
dd if="$IMX8_BLOB" of="$IMGFILE" bs=1024 seek=$IMG_SEEK conv=notrunc
fi
# Lets see if GPT partition exists and it is one of the
# kinds we recognize
case "$(sgdisk -p $IMGFILE 2>/dev/null | sed -ne '/^Number/,$s/^.* //p' | tr '\012' ' ')" in
"Name vrl vrl_backup mcuimage fastboot nvme boot reserved cache"*)
echo "Found Android GPT partition table on $IMGFILE"
for p in $(sgdisk -p $IMGFILE 2>/dev/null | sed -e '1,/cache$/d' | awk '{print $1;}') ; do
sgdisk -d $p $IMGFILE
done
PART_OFFSET=10
CUR_SEC=$(( ( $(sgdisk -p $IMGFILE 2>/dev/null | tail -1 | awk '{print $3;}') / 2048 + 1 ) * 2048 ))
EMBED_BOOT_START=$(sgdisk -i 6 $IMGFILE 2>/dev/null | awk '/First sector:/{ print $3; }')
EMBED_BOOT_SIZE=$(sgdisk -i 6 $IMGFILE 2>/dev/null | awk '/Partition size:/{ print $3; }')
;;
"Name System IMGA IMGB CONFIG P3"*)
echo "Found EVE GPT partition table on $IMGFILE"
# apparently sgdisk -Z doesn't clear MBR and keeps complaining
dd if=/dev/zero of="$IMGFILE" bs=512 count=1 conv=notrunc
sgdisk -Z --clear $IMGFILE 2>/dev/null || :
;;
*) echo "Unknown (or unrecognizable) GPT partition table on $IMGFILE"
# apparently sgdisk -Z doesn't clear MBR and keeps complaining
dd if=/dev/zero of="$IMGFILE" bs=512 count=1 conv=notrunc
sgdisk -Z --clear $IMGFILE 2>/dev/null || :
;;
esac
if [ -z "$RANDOM_DISK_UUIDS" ]; then
sgdisk --disk-guid=$DISK_UUID "$IMGFILE"
fi
# at this point, the base PART_OFFSET is set, so we can calculate the rest
SYSTEM_VFAT_PART=$(( PART_OFFSET + $SYSTEM_VFAT_PART_OFFSET ))
VFAT_PART=$(( PART_OFFSET + $VFAT_PART_OFFSET ))
INSTALLER_PART=$(( PART_OFFSET + $INSTALLER_PART_OFFSET ))
IMGA_PART=$(( PART_OFFSET + $IMGA_PART_OFFSET ))
IMGB_PART=$(( PART_OFFSET + $IMGB_PART_OFFSET ))
EFI_PART=$(( PART_OFFSET + $EFI_PART_OFFSET ))
CONF_PART=$(( PART_OFFSET + $CONF_PART_OFFSET ))
PERSIST_PART=$(( PART_OFFSET + $PERSIST_PART_OFFSET ))
INVENTORY_WIN_PART=$(( PART_OFFSET + $INVENTORY_WIN_PART_OFFSET ))
USB_CONF_PART=$(( PART_OFFSET + $USB_CONF_PART_OFFSET ))
# override regular efi for efiinstaller if both efi and installer are here
if echo "$PARTS" | grep -q "efi" && echo "$PARTS" | grep -q "installer"; then
PARTS=$(echo "$PARTS" | sed -e 's/efi/efiinstaller/')
fi
for p in $PARTS ; do
eval do_$p CUR_SEC
done
# set the appropriate boot partition for grub gptprio.next
# rule is: installer, then imga then imgb
BOOTABLE_PART=""
if echo "$PARTS" | grep -q "installer"; then
BOOTABLE_PART=$INSTALLER_PART
elif echo "$PARTS" | grep -q "imga"; then
BOOTABLE_PART=$IMGA_PART
elif echo "$PARTS" | grep -q "imgb"; then
BOOTABLE_PART=$IMGB_PART
fi
if [ -n "$BOOTABLE_PART" ]; then
sgdisk --attributes=$BOOTABLE_PART:set:56 --attributes=$BOOTABLE_PART:set:49 "$IMGFILE"
fi
if [ "$PARTS" = usb_conf ]; then
# Validate the health of our creation
sgdisk -v "$IMGFILE"
exit 0
fi
# Create a hybrid MBR to allow booting on legacy BIOS PC systems and ARM boards that
# look for bootloaders in the first entry of the MBR
sgdisk -h"${PROTECTIVE_MBR_LIST}EE" "$IMGFILE"
# if we happen to be building an x86 image - deploy legacy GRUB into the GPT gap
if [ -e /efifs/EFI/BOOT/BOOT.pc ]; then
deploy_legacy_grub
fi
# Update embedded boot partition with our own bootloader - this only happens if
# we noticed a recognizable GPT structure and we are ADDING ourselves to it,
# as opposed to replacing the entire GPT with our own structure (currently this
# only happens for HiKey but the approach of using partitions to store firmware
# blobs on flash is fairly common on ARM so we expect to see others as well)
# On the other hand...
GRUB_IMG="$(echo /efifs/EFI/BOOT/BOOT*.EFI)"
if [ ${EMBED_BOOT_START:-0} -gt 0 -a ${EMBED_BOOT_SIZE:-0} -gt 0 -a -f "$GRUB_IMG" ] ; then
if mount $IMGFILE /mnt -o loop,offset=$(( EMBED_BOOT_START * 512 )),sizelimit=$(( EMBED_BOOT_SIZE * 512 )) ; then
FASTBOOT=$(cd /mnt/EFI/BOOT/ ; ls | grep -i '^fastboot.efi$')
if $(set ${FASTBOOT:-. .} ; test $# -eq 1) ; then
cp_with_backup "$GRUB_IMG" "/mnt/EFI/BOOT/$FASTBOOT"
(echo 'set root=hd0,gpt11' ; echo 'configfile /efi/boot/grub.cfg') > /tmp/grub.cfg
cp_with_backup /tmp/grub.cfg /mnt/EFI/BOOT/grub.cfg
fi
fi
umount /mnt || :
else
# ...if we're NOT adding ourselves to an existing GPT - assume we own protective MBR
# as well and can adjust it accordingly to maximize our chances of booting on something
# like Raspberry Pi (which is pretty strict about how the first entry in the MBR partition
# table needs to look like)
adjust_protective_mbr
fi
# Validate the health of our creation
sgdisk -v $IMGFILE