3 # Copyright (c) 2012, Intel Corporation.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 # the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # Modification from mkefidisk.sh provided by the Yocto project by Dominig
21 # to install Automotive Grade Linux (AGL) on Minnowboard and any PC with UEFI boot
25 # - keep initrd if present
26 # - create a grub config with PARTUID to ease boot from various devices automaticaly
27 # - add a UEFI startup.nsh script for autoboot
28 # - remove any configured swap is fstab
29 # - accept .hddimg, wic and wic.xz as sources
33 # Set to 1 to enable additional output
40 # 100 Mb for the boot partition
42 # min available space on TMP_DIR for uncompressing xz image in kB e.g. 5G (5000000)
44 # TMP_DIR directory use for holding image file for uncompression (e.g. /tmp or $HOME)
49 debug "Syncing and unmounting devices"
50 # Unmount anything we mounted
51 unmount $ROOTFS_MNT || error "Failed to unmount $ROOTFS_MNT"
52 unmount $BOOTFS_MNT || error "Failed to unmount $BOOTFS_MNT"
53 unmount $HDDIMG_ROOTFS_MNT || error "Failed to unmount $HDDIMG_ROOTFS_MNT"
54 unmount $HDDIMG_MNT || error "Failed to unmount $HDDIMG_MNT"
55 if [ "$IMG_TYPE" = "DISK" ]; then
56 debug "de-attaching loop devices"
57 for LOOP_DEVICE in `losetup --list |grep $HDDIMG | cut -d" " -f1` ; do
58 losetup -d $LOOP_DEVICE 1>&3 2>&1 || error "Detaching $LOOP_DEVICE from $HDDIMG failled"
63 debug "Removing temporary files"
64 if [ -d "$TMPDIR" ]; then
65 rm -rf "$TMPDIR" || error "Failed to remove $TMPDIR"
67 [ -f "$TMP_DIR/TMP-AGL-wic-image.wic" ] && rm -f $TMP_DIR/TMP-AGL-wic-image.wic
70 trap 'die "Signal Received, Aborting..."' HUP INT TERM
77 RED="$(tput setaf 1)$(tput bold)"
78 GREEN="$(tput setaf 2)$(tput bold)"
79 YELLOW="$(tput setaf 3)$(tput bold)"
81 echo "${INFO}$1${CLEAR}"
85 echo "${RED}$1${CLEAR}"
88 WARNINGS=$((WARNINGS+1))
89 echo "${YELLOW}$1${CLEAR}"
92 echo "${GREEN}$1${CLEAR}"
100 if [ $DEBUG -eq 1 ]; then
106 echo "Install AGL on a removable device to boot on IA UEFI based computer"
107 echo "In particular is can create USB or SD bootable support for Minnowboard"
109 echo "Usage: $(basename $0) [-v] IDSK_IMAGE REMOVABLE_DEVICE"
110 echo " -v: Verbose debug"
111 echo " HDDIMG: The DISK_IMAGE file generated by Yocto the efi disk from"
112 echo " Supported formats are .hddimg, .wic .wic.xz"
113 echo " REMOVABLE_DEVICE: The block device to write the image to, e.g. /dev/sdh"
115 echo " mkefi-agl.sh agl-demo-platform-intel-corei7-64.hddimg /dev/sdd"
116 echo " mkefi-agl.sh agl-demo-platform-intel-corei7-64.wic.xz /dev/sdd"
123 echo " image: $(stat --printf '%N\n' $IMG)"
124 echo " size: $(stat -L --printf '%s bytes\n' $IMG)"
125 echo " modified: $(stat -L --printf '%y\n' $IMG)"
126 echo " type: $(file -L -b $IMG)"
134 info "Device details"
135 echo " device: $DEVICE"
136 if [ -f "/sys/class/block/$DEV/device/vendor" ]; then
137 echo " vendor: $(cat /sys/class/block/$DEV/device/vendor)"
139 echo " vendor: UNKOWN"
141 if [ -f "/sys/class/block/$DEV/device/model" ]; then
142 echo " model: $(cat /sys/class/block/$DEV/device/model)"
144 echo " model: UNKNOWN"
146 if [ -f "/sys/class/block/$DEV/size" ]; then
147 echo " size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes"
149 echo " size: UNKNOWN"
155 grep -q $DEVICE /proc/mounts
156 if [ $? -eq 0 ]; then
157 warn "$DEVICE listed in /proc/mounts, attempting to unmount"
158 umount $DEVICE* 2>/dev/null
159 ! grep -q $DEVICE /proc/mounts && info "Unmounted successfully"
166 if [ "$1" = "" ] ; then
169 grep -q $1 /proc/mounts
170 if [ $? -eq 0 ]; then
171 debug "Unmounting $1"
173 ! grep -q $1 /proc/mounts # check if unmounted successfully
180 # Parse and validate arguments
182 if [ "$1" != "-v" ] && [ $# -ne 2 ]; then
185 if [ "$1" = "-v" ] && [ $# -ne 3 ]; then
189 if [ "$1" = "-v" ] ; then
198 LINK=$(readlink $DEVICE)
199 if [ $? -eq 0 ]; then
203 if [ ! -w "$DEVICE" ]; then
204 if [ ! -e "${DEVICE}" ] ; then
205 die "Device $DEVICE cannot be found"
207 die "Device $DEVICE is not writable (need to run under sudo?)"
211 if [ ! -e "$HDDIMG" ]; then
212 die "HDDIMG $HDDIMG does not exist"
214 HDDIMG_EXT=${HDDIMG##*.}
219 debug "Detected: uncompressed image type .hddimg"
224 debug "Detected: uncompressed image type .wic"
229 debug "Detected: xz compressed image type .wic"
230 command -v xz >/dev/null 2>&1 || { die "xz command is not available, pleaes install xz package"; }
231 TMP_SIZE=`df -k $TMP_DIR | awk '/[0-9]%/{print $(NF-2)}'`
232 if [ "$TMP_SIZE" -lt "$TMP_SIZE_MIN" ]; then
233 die "Available space on $TMP_DIR must be at least $TMP_SIZE_MIN kB"
235 printf "Starting decompression of the image. It may take some time ..."
236 xz --decompress --keep --format=auto --force --threads=0 --stdout > $TMP_DIR/TMP-AGL-wic-image.wic $HDDIMG|| \
237 die "xz command failled: xz --decompress --keep --format=auto --force --threads=0 --stdout > $TMP_DIR/TMP-AGL-wic-image.wic"
238 HDDIMG="$TMP_DIR/TMP-AGL-wic-image.wic"
239 echo "Image uncompressed, starting doing real work ..."
242 die "Unsupported image format: $HDDIMG_EXT Supported format are .hddimg .wic wic.xz"
247 # Ensure the hddimg is not mounted
249 debug "will now try to umount /detach previous images"
252 unmount "$HDDIMG" || die "Failed to unmount $HDDIMG"
255 [ `losetup --list |grep $HDDIMG | wc -l ` -gt 1 ] && die "Image mounted more than once, manual cleaning required see: losetup --list"
256 debug "ready to attach the wic image to aloop device"
257 LOOP_DEVICE=`losetup --find --show $HDDIMG` && ( losetup -d $LOOP_DEVICE 1>&3 2>&1 || die "Detaching $LOOP_DEVICE from $HDDIMG failled")
260 die "unknown image format $IMG_TYPE"
265 # Check if any $DEVICE partitions are mounted
267 unmount_device || die "Failed to unmount $DEVICE"
270 # Confirm device with user
272 image_details $HDDIMG
273 device_details $(basename $DEVICE)
274 echo -n "${INFO}Prepare EFI image on $DEVICE [y/N]?${CLEAR} "
276 if [ "$RESPONSE" != "y" ]; then
277 die "Image creation aborted"
282 # Prepare the temporary working space
284 TMPDIR=$(mktemp -d mkefidisk-XXX) || die "Failed to create temporary mounting directory."
285 HDDIMG_MNT=$TMPDIR/hddimg
286 HDDIMG_ROOTFS_MNT=$TMPDIR/hddimg_rootfs
287 ROOTFS_MNT=$TMPDIR/rootfs
288 BOOTFS_MNT=$TMPDIR/bootfs
289 mkdir $HDDIMG_MNT || die "Failed to create $HDDIMG_MNT"
290 mkdir $HDDIMG_ROOTFS_MNT || die "Failed to create $HDDIMG_ROOTFS_MNT"
291 mkdir $ROOTFS_MNT || die "Failed to create $ROOTFS_MNT"
292 mkdir $BOOTFS_MNT || die "Failed to create $BOOTFS_MNT"
298 DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//")
299 # If the device size is not reported there may not be a valid label
300 if [ "$DEVICE_SIZE" = "" ] ; then
301 parted -s $DEVICE mklabel msdos || die "Failed to create MSDOS partition table"
302 DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//")
304 ROOTFS_SIZE=$((DEVICE_SIZE-BOOT_SIZE))
305 ROOTFS_START=$((BOOT_SIZE))
306 ROOTFS_END=$((ROOTFS_START+ROOTFS_SIZE))
308 # MMC devices use a partition prefix character 'p'
310 if [ ! "${DEVICE#/dev/mmcblk}" = "${DEVICE}" ] || [ ! "${DEVICE#/dev/nvme0n}" = "${DEVICE}" ] || [ ! "${DEVICE#/dev/loop}" = "${DEVICE}" ]; then
313 BOOTFS=$DEVICE${PART_PREFIX}1
314 ROOTFS=$DEVICE${PART_PREFIX}2
316 TARGET_PART_PREFIX=""
317 if [ ! "${TARGET_DEVICE#/dev/mmcblk}" = "${TARGET_DEVICE}" ] || [ ! "${TARGET_DEVICE#/dev/nvme0n}" = "${TARGET_DEVICE}" ]; then
318 TARGET_PART_PREFIX="p"
320 TARGET_ROOTFS=$TARGET_DEVICE${TARGET_PART_PREFIX}2
323 info "Boot partition size: $BOOT_SIZE MB ($BOOTFS)"
324 info "ROOTFS partition size: $ROOTFS_SIZE MB ($ROOTFS)"
327 # Use MSDOS by default as GPT cannot be reliably distributed in disk image form
328 # as it requires the backup table to be on the last block of the device, which
329 # of course varies from device to device.
331 info "Partitioning installation media ($DEVICE)"
333 debug "Deleting partition table on $DEVICE"
334 dd if=/dev/zero of=$DEVICE bs=512 count=2 1>&3 2>&1 || die "Failed to zero beginning of $DEVICE"
336 debug "Creating new partition table (MSDOS) on $DEVICE"
337 parted -s $DEVICE mklabel msdos 1>&3 2>&1 || die "Failed to create MSDOS partition table"
339 debug "Creating boot partition on $BOOTFS"
340 parted -s $DEVICE mkpart primary 0% $BOOT_SIZE 1>&3 2>&1 || die "Failed to create BOOT partition"
342 debug "Enabling boot flag on $BOOTFS"
343 parted -s $DEVICE set 1 boot on 1>&3 2>&1 || die "Failed to enable boot flag"
345 debug "Creating ROOTFS partition on $ROOTFS"
346 parted -s $DEVICE mkpart primary $ROOTFS_START $ROOTFS_END 1>&3 2>&1 || die "Failed to create ROOTFS partition"
348 # as blkid does not provide PARTUUID on Ubuntu LTS 14.04 we myst hack via fdisk
349 #ROOTFS_PARTUUID=$(blkid |grep -e "$ROOTFS" |sed -n 's/^.*PARTUUID=/PARTUUID=/p')
351 ROOTFS_DISKID=$(fdisk -l "$DEVICE" | grep -e "Disk identifier" | sed -n 's/^.*Disk identifier: 0x/PARTUUID=/p')
352 if [ $ROOTFS_DISKID = "" ]; then
353 die "Failed to read DISKID"
355 BOOTFS_PARTUUID="$ROOTFS_DISKID-01"
356 ROOTFS_PARTUUID="$ROOTFS_DISKID-02"
357 debug "PARTUUID for ROOTFS is $ROOTFS_PARTUUID"
359 if [ $DEBUG -eq 1 ]; then
360 parted -s $DEVICE print
365 # Check if any $DEVICE partitions are mounted after partitioning
367 unmount_device || die "Failed to unmount $DEVICE partitions"
371 # Format $DEVICE partitions
373 info "Formatting partitions"
374 debug "Formatting $BOOTFS as vfat"
375 if [ ! "${DEVICE#/dev/loop}" = "${DEVICE}" ]; then
376 mkfs.vfat -I $BOOTFS -n "EFI" 1>&3 2>&1 || die "Failed to format $BOOTFS"
378 mkfs.vfat $BOOTFS -n "EFI" 1>&3 2>&1 || die "Failed to format $BOOTFS"
381 debug "Formatting $ROOTFS as ext4"
382 mkfs.ext4 -F $ROOTFS -L "ROOT" 1>&3 2>&1 || die "Failed to format $ROOTFS"
386 # Mounting image file system on loop devices
391 debug "Mounting images and device in preparation for installation"
392 mount -o loop $HDDIMG $HDDIMG_MNT 1>&3 2>&1 || die "Failed to mount $HDDIMG"
393 mount -o loop $HDDIMG_MNT/rootfs.img $HDDIMG_ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount rootfs.img"
396 debug "Attaching image and mounting partitions then device in preparation for installation"
397 LOOP_DEVICE=`losetup --find` || die "Failled to find an available loop device see: losetup --find"
398 losetup -P $LOOP_DEVICE $HDDIMG 1>&3 2>&1 || die "Attaching $LOOP_DEVICE from $HDDIMG failled"
399 mount "$LOOP_DEVICE"p2 $HDDIMG_ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount $LOOP_DEVICEp1 on $HDDIMG_ROOTFS_MNT"
400 mount "$LOOP_DEVICE"p1 $HDDIMG_MNT 1>&3 2>&1 || die "Failed to mount $LOOP_DEVICEp2 on $HDDIMG_MNT"
403 die "unknown image format $IMG_TYPE"
406 # Mount removable device
407 mount $ROOTFS $ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount $ROOTFS on $ROOTFS_MNT"
408 mount $BOOTFS $BOOTFS_MNT 1>&3 2>&1 || die "Failed to mount $BOOTFS on $BOOTFS_MNT"
411 info "Preparing boot partition"
412 EFIDIR="$BOOTFS_MNT/EFI/BOOT"
413 if [ -f $HDDIMG_MNT/vmlinuz ]; then
414 cp $HDDIMG_MNT/vmlinuz $BOOTFS_MNT 1>&3 2>&1 || die "Failed to copy vmlinuz"
415 KERNEL_TYPE="VMLINUZ"
416 debug "kernel is vmlinuz"
418 if [ -f $HDDIMG_MNT/bzimage ]; then
419 cp $HDDIMG_MNT/bzimage $BOOTFS_MNT 1>&3 2>&1 || die "Failed to copy bzimage"
420 KERNEL_TYPE="BZIMAGE"
421 debug "kernel is bzimage"
423 if [ -f $HDDIMG_MNT/microcode.cpio ]; then
424 cp $HDDIMG_MNT/microcode.cpio $BOOTFS_MNT 1>&3 2>&1 || die "Failed to copy microcode.cpio"
425 debug "microcode.cpio copied"
427 [ -z $KERNEL_TYPE ] && die "Linux kernel type in $HDDIMG is unsupported"
429 if [ -f $HDDIMG_MNT/initrd ]
431 echo "initrd detected"
432 cp $HDDIMG_MNT/initrd $BOOTFS_MNT 1>&3 2>&1 || die "Failed to copy initrd"
434 warn "initrd missing"
436 echo "bootx64.efi" > $BOOTFS_MNT/startup.nsh || die "Failed to create startup.nsh"
437 # Copy the efi loader and configs (booti*.efi and grub.cfg if it exists)
438 cp -r $HDDIMG_MNT/EFI $BOOTFS_MNT 1>&3 2>&1 || die "Failed to copy EFI dir"
439 # Silently ignore a missing systemd-boot or gummiboot loader dir (we might just be a GRUB image)
440 cp -r $HDDIMG_MNT/loader $BOOTFS_MNT 1>&3 2>&1
442 # Update the boot loaders configurations for an installed image
443 # Remove any existing root= kernel parameters and:
444 # o Add a root= parameter with the target rootfs
445 # o Specify ro so fsck can be run during boot
446 # o Specify rootwait in case the target media is an asyncronous block device
447 # such as MMC or USB disks
448 # o Specify "quiet" to minimize boot time when using slow serial consoles
450 # Look for a GRUB installation
451 GRUB_CFG="$EFIDIR/grub.cfg"
452 if [ -e "$GRUB_CFG" ]; then
453 info "Configuring GRUB"
454 # Delete the install entry
455 sed -i "/menuentry 'install'/,/^}/d" $GRUB_CFG
456 # Delete any LABEL= strings
457 sed -i "s/ LABEL=[^ ]*/ /" $GRUB_CFG
458 # detect config initrd=microcode.cpio
459 if grep -q microcode $GRUB_CFG; then
460 warn "initrd=microcode.cpio detected, might not work on all boot configurations"
462 sed -i "s@ root=[^ ]*@ @" $GRUB_CFG
463 sed -i "s@vmlinuz @vmlinuz root=$ROOTFS_PARTUUID @" $GRUB_CFG
466 # look for a systemd-boot loader.conf file and create a default boot entry
467 SYSTEMDBOOT_CFG="$BOOTFS_MNT/loader/loader.conf"
468 if [ -e "$SYSTEMDBOOT_CFG" ]; then
469 info "Configuring SYSTEMD-BOOT"
470 SYSTEMDBOOT_BOOT="$BOOTFS_MNT/loader/entries/boot.conf"
471 SYSTEMDBOOT_DEBUG="$BOOTFS_MNT/loader/entries/debug.conf"
472 # Delete the install entry
473 sed -i "/menuentry 'install'/,/^}/d" $SYSTEMDBOOT_CFG
474 rm -rf "$BOOTFS_MNT/loader/entries/install.conf" 1>&3 2>&1
475 # Add PARTUUID to the boot entry file
476 if [ ! -e "$SYSTEMDBOOT_BOOT" ]; then
477 die "no boot.conf entry found in systemd-boot directories"
479 # Delete any LABEL= strings
480 sed -i "s/ LABEL=[^ ]*/ /" $SYSTEMDBOOT_BOOT
481 # detect config initrd=microcode.cpio
482 if grep -q microcode $SYSTEMDBOOT_BOOT; then
483 warn "initrd=microcode.cpio detected, might not work on all boot configurations"
485 sed -i "s@ root=[^ ]*@ @" $SYSTEMDBOOT_BOOT
486 sed -i "s@options @options root=$ROOTFS_PARTUUID @" $SYSTEMDBOOT_BOOT
490 # Ensure we have at least one EFI bootloader configured
491 if [ ! -e $GRUB_CFG ] && [ ! -e $SYSTEMDBOOT_CFG ] ; then
492 die "No EFI bootloader configuration found"
495 printf "Copying ROOTFS files ... "
496 command -v rsync >/dev/null 2>&1 # check if rsync exists
497 if [ $DEBUG -eq 1 ] && [ $? -eq 0 ]; then
498 rsync --info=progress2 -h -aHAXW --no-compress $HDDIMG_ROOTFS_MNT/* $ROOTFS_MNT 1>&3 2>&1 || die "Root FS copy failed"
500 cp -a $HDDIMG_ROOTFS_MNT/* $ROOTFS_MNT 1>&3 2>&1 || die "Root FS copy failed"
502 debug "removing any swap entry in /etc/fstab"
503 sed --in-place '/swap/d' $ROOTFS_MNT/etc/fstab
504 debug "fixing PARTUUID for /boot"
505 sed --in-place -e "s#PARTUUID=[0-9a-z-]\+\t/boot#${BOOTFS_PARTUUID}\t/boot#" $ROOTFS_MNT/etc/fstab
507 printf "flushing data on removable device. May take a while ... "
508 sync --file-system $ROOTFS_MNT
511 # We dont want udev to mount our root device while we're booting...
512 if [ -d $ROOTFS_MNT/etc/udev/ ] ; then
513 echo "$TARGET_DEVICE" >> $ROOTFS_MNT/etc/udev/mount.blacklist
517 # Call cleanup to unmount devices and images and remove the TMPDIR
521 if [ $WARNINGS -ne 0 ] && [ $ERRORS -eq 0 ]; then
522 echo "${YELLOW}Installation completed with warnings${CLEAR}"
523 echo "${YELLOW}Warnings: $WARNINGS${CLEAR}"
524 elif [ $ERRORS -ne 0 ]; then
525 echo "${RED}Installation encountered errors${CLEAR}"
526 echo "${RED}Errors: $ERRORS${CLEAR}"
527 echo "${YELLOW}Warnings: $WARNINGS${CLEAR}"
529 success "Installation completed successfully"