Bump agl-service-can-low-level revision
[AGL/meta-agl.git] / scripts / mkabl-agl.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2012, Intel Corporation.
4 # All rights reserved.
5 #
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.
10 #
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.
15 #
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
19 #
20 # Modification from mkefidisk.sh provided by the Yocto project by Dominig
21 # to install Automotive Grade Linux (AGL) on 
22 # Intel platforms equipped with the Automotive Linux Boot (ABL)
23 #
24 # Dependencies:
25 # Relies on the Intel iasImage tool to pakage the Kernel and the initrd in ABL format
26 #
27 # changes
28 #         - simpler use model
29 #         - keep initrd if present
30 #         - does not allocate swap
31 #         - accept .hddimg, wic and wic.xz as sources
32 #
33
34 LANG=C
35
36 # Set to 1 to enable additional output
37 DEBUG=0
38 exec 3>/dev/null
39
40 #
41 # Defaults
42 #
43 # 100 Mb for the boot partition
44 BOOT_SIZE=100
45 # min available space on TMP_DIR for uncompressing xz image in kB e.g. 5G (5000000)
46 TMP_SIZE_MIN=5000000
47 # TMP_DIR directory use for holding image file for uncompression (e.g. /tmp or $HOME)
48 TMP_DIR=/tmp
49 #
50 MRB_DEBUG_TTY="ttyS2,115200n8"
51 MRB_HDMI="HDMI-A-1:e"
52 #
53 IAS_PATH=""
54 IAS_EXE="ias_image_app"
55 IAS_CMD_LINE=/tmp/iasCommandLine.cmd
56
57 # Cleanup after die()
58 cleanup() {
59         debug "Syncing and unmounting devices"
60         # Unmount anything we mounted
61         unmount $ROOTFS_MNT || error "Failed to unmount $ROOTFS_MNT"
62         unmount $BOOTFS_MNT || error "Failed to unmount $BOOTFS_MNT"
63         unmount $HDDIMG_ROOTFS_MNT || error "Failed to unmount $HDDIMG_ROOTFS_MNT"
64         unmount $HDDIMG_MNT || error "Failed to unmount $HDDIMG_MNT"
65         if [ "$IMG_TYPE" = "DISK" ]; then
66         debug "de-attaching loop devices"
67         for LOOP_DEVICE in `losetup --list |grep $HDDIMG | cut -d" " -f1` ; do
68            losetup -d $LOOP_DEVICE  1>&3 2>&1 || error "Detaching $LOOP_DEVICE from $HDDIMG failled"
69         done   
70      fi
71         # Remove the TMPDIR
72         debug "Removing temporary files"
73         if [ -d "$TMPDIR" ]; then
74                 rm -rf $TMPDIR || error "Failed to remove $TMPDIR"
75         fi
76     [ -f "$TMP_DIR/TMP-AGL-wic-image.wic" ] || rm -f $TMP_DIR/TMP-AGL-wic-image.wic
77 }
78
79 trap 'die "Signal Received, Aborting..."' HUP INT TERM
80
81 # Logging routines
82 WARNINGS=0
83 ERRORS=0
84 CLEAR="$(tput sgr0)"
85 INFO="$(tput bold)"
86 RED="$(tput setaf 1)$(tput bold)"
87 GREEN="$(tput setaf 2)$(tput bold)"
88 YELLOW="$(tput setaf 3)$(tput bold)"
89 info() {
90         echo "${INFO}$1${CLEAR}"
91 }
92 error() {
93         ERRORS=$((ERRORS+1))
94         echo "${RED}$1${CLEAR}"
95 }
96 warn() {
97         WARNINGS=$((WARNINGS+1))
98         echo "${YELLOW}$1${CLEAR}"
99 }
100 success() {
101         echo "${GREEN}$1${CLEAR}"
102 }
103 die() {
104         error "$1"
105         cleanup
106         exit 1
107 }
108 debug() {
109         if [ $DEBUG -eq 1 ]; then
110                 echo "$1"
111         fi
112 }
113
114 usage() {
115         echo "Install AGL on a removable device to boot ABL based computer"
116         echo "ABL on the target must accept non signed development Linux kernel"
117         echo "In particular is can create USB or SD bootable support for Intel MRB"
118         echo ""
119         echo "Usage: $(basename $0) [-v] [-p path_to_iasImage_tool] HDDIMG REMOVABLE_DEVICE"
120         echo "       -v: Verbose debug"
121         echo "       path_to_iasImage_tool: path the iasImage tool provided by Intel."
122         echo "       HDDIMG: The hddimg file to generate the efi disk from"
123     echo "               Supported formats are .hddimg, .wic .wic.xz"
124         echo "       REMOVABLE_DEVICE: The block device to write the image to, e.g. /dev/sdh"
125         echo "ex:"
126         echo "   mkabl-agl.sh   agl-demo-platform-intel-corei7-64.wic.xz /dev/sdd"
127     echo "   mkabl-agl.sh   agl-demo-platform-intel-corei7-64.hddimg /dev/sdd"
128
129         echo "                  assuming that iasImage is accessible via your default path"
130         exit 1
131 }
132
133 image_details() {
134         IMG=$1
135         info "Image details"
136         echo "    image: $(stat --printf '%N\n' $IMG)"
137         echo "     size: $(stat -L --printf '%s bytes\n' $IMG)"
138         echo " modified: $(stat -L --printf '%y\n' $IMG)"
139         echo "     type: $(file -L -b $IMG)"
140         echo ""
141 }
142
143 device_details() {
144         DEV=$1
145         BLOCK_SIZE=512
146
147         info "Device details"
148         echo "  device: $DEVICE"
149         if [ -f "/sys/class/block/$DEV/device/vendor" ]; then
150                 echo "  vendor: $(cat /sys/class/block/$DEV/device/vendor)"
151         else
152                 echo "  vendor: UNKOWN"
153         fi
154         if [ -f "/sys/class/block/$DEV/device/model" ]; then
155                 echo "   model: $(cat /sys/class/block/$DEV/device/model)"
156         else
157                 echo "   model: UNKNOWN"
158         fi
159         if [ -f "/sys/class/block/$DEV/size" ]; then
160                 echo "    size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes"
161         else
162                 echo "    size: UNKNOWN"
163         fi
164         echo ""
165 }
166
167 unmount_device() {
168         grep -q $DEVICE /proc/mounts
169         if [ $? -eq 0 ]; then
170                 warn "$DEVICE listed in /proc/mounts, attempting to unmount"
171                 umount $DEVICE* 2>/dev/null
172                 ! grep -q $DEVICE /proc/mounts && info "Unmounted successfully"
173                 return $?
174         fi
175         return 0
176 }
177
178 unmount() {
179         if [ "$1" = "" ] ; then
180                 return 0
181         fi
182         grep -q $1 /proc/mounts
183         if [ $? -eq 0 ]; then
184                 debug "Unmounting $1"
185                 umount $1
186                 ! grep -q $1 /proc/mounts # check if unmounted successfully
187                 return $?
188         fi
189         return 0
190 }
191
192 #
193 # Parse and validate arguments
194 #
195
196 if [ "$1" = "-v" ] ; then
197         DEBUG=1
198         exec 3>&1
199         shift
200 fi
201
202 if [ "$1" = "-p" ] ; then
203         IAS_PATH="$2""/"
204         shift 2
205 fi
206
207 if  [ $# -ne 2 ]; then
208         usage
209 fi
210
211 IAS_IMAGE_TOOL="$IAS_PATH$IAS_EXE"
212 debug "iasImage tool is: $IAS_IMAGE_TOOL"
213 which $IAS_IMAGE_TOOL > IAS_IMAGE_TOOL_PATH
214 if  [ ! -x "$(command -v $IAS_IMAGE_TOOL)" ]; then
215    die "$IAS_IMAGE_TOOL not found pointed by the path via 'sudo; use -p option'"
216 fi
217
218 HDDIMG=$1
219 DEVICE=$2
220
221 LINK=$(readlink $DEVICE)
222 if [ $? -eq 0 ]; then
223         DEVICE="$LINK"
224 fi
225
226 if [ ! -w "$DEVICE" ]; then
227         if [ ! -e "${DEVICE}" ] ; then
228                 die "Device $DEVICE cannot be found"
229         else
230                 die "Device $DEVICE is not writable (need to run under sudo?)"
231         fi
232 fi
233
234 if [ ! -e "$HDDIMG" ]; then
235         die "HDDIMG $HDDIMG does not exist"
236 fi
237 HDDIMG_EXT=${HDDIMG##*.}
238 case $HDDIMG_EXT in
239   hddimg)
240      IMG_TYPE="MOUNT"
241      IMG_COMPRESS="NO"
242      debug "Detected: uncompressed image type .hddimg"
243      ;;
244   wic)
245      IMG_TYPE="DISK"
246      IMG_COMPRESS="NO"
247      debug "Detected: uncompressed image type .wic"
248      ;;
249   xz)
250      IMG_TYPE="DISK"
251      IMG_COMPRESS="YES"
252      debug "Detected: xz compressed image type .wic"
253      command -v xz >/dev/null 2>&1 || { die "xz command is not available, pleaes install xz package"; }
254      TMP_SIZE=`df -k $TMP_DIR | awk '/[0-9]%/{print $(NF-2)}'`
255      if [ "$TMP_SIZE" -lt "$TMP_SIZE_MIN" ]; then
256        die "Available space on $TMP_DIR must be at least $TMP_SIZE_MIN kB" 
257      fi
258      printf "Starting decompression of the image. It may take some time ..."
259      xz --decompress --keep --format=auto --force --threads=0 --stdout > $TMP_DIR/TMP-AGL-wic-image.wic  $HDDIMG|| \
260          die "xz command failled: xz --decompress --keep --format=auto --force --threads=0 --stdout > $TMP_DIR/TMP-AGL-wic-image.wic"
261      HDDIMG="$TMP_DIR/TMP-AGL-wic-image.wic"
262      echo "Image uncompressed, starting doing real work ..."
263      ;;
264   *)
265      die "Unsupported image format: $HDDIMG_EXT Supported format are .hddimg .wic wic.xz"
266      ;;
267 esac
268 #
269 # Ensure the hddimg is not mounted
270 #
271 debug "will now try to umount /detach previous images"
272 case $IMG_TYPE in
273   MOUNT)
274       unmount "$HDDIMG" || die "Failed to unmount $HDDIMG"
275       ;;
276   DISK)
277       [ `losetup --list |grep $HDDIMG | wc -l ` -gt 1 ] && die "Image mounted more than once, manual cleaning required see: losetup --list"
278       debug "ready to attach the wic image to aloop device"
279       LOOP_DEVICE=`losetup --find --show $HDDIMG`  && ( losetup -d $LOOP_DEVICE  1>&3 2>&1 || die "Detaching $LOOP_DEVICE from $HDDIMG failled")
280       ;;
281   *)
282       die "unknown image format $IMG_TYPE"
283       ;;
284 esac
285 #
286 # Check if any $DEVICE partitions are mounted
287 #
288 unmount_device || die "Failed to unmount $DEVICE"
289
290 #
291 # Confirm device with user
292 #
293 image_details $HDDIMG
294 device_details $(basename $DEVICE)
295 echo -n "${INFO}Prepare ABL image on $DEVICE [y/N]?${CLEAR} "
296 read RESPONSE
297 if [ "$RESPONSE" != "y" ]; then
298         echo "Image creation aborted"
299         exit 0
300 fi
301
302
303 #
304 # Prepare the temporary working space
305 #
306 TMPDIR=$(mktemp -d mkabldisk-XXX) || die "Failed to create temporary mounting directory."
307 HDDIMG_MNT=$TMPDIR/hddimg
308 debug "TEMPDIR is: $TMPDIR"
309 HDDIMG_ROOTFS_MNT=$TMPDIR/hddimg_rootfs
310 ROOTFS_MNT=$TMPDIR/rootfs
311 BOOTFS_MNT=$TMPDIR/bootfs
312 mkdir $HDDIMG_MNT || die "Failed to create $HDDIMG_MNT"
313 mkdir $HDDIMG_ROOTFS_MNT || die "Failed to create $HDDIMG_ROOTFS_MNT"
314 mkdir $ROOTFS_MNT || die "Failed to create $ROOTFS_MNT"
315 mkdir $BOOTFS_MNT || die "Failed to create $BOOTFS_MNT"
316
317
318 #
319 # Partition $DEVICE
320 #
321 DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//")
322 # If the device size is not reported there may not be a valid label
323 if [ "$DEVICE_SIZE" = "" ] ; then
324         parted -s $DEVICE mklabel msdos || die "Failed to create MSDOS partition table"
325         DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//")
326 fi
327 ROOTFS_SIZE=$((DEVICE_SIZE-BOOT_SIZE))
328 ROOTFS_START=$((BOOT_SIZE))
329 ROOTFS_END=$((ROOTFS_START+ROOTFS_SIZE))
330
331 # MMC devices use a partition prefix character 'p'
332 PART_PREFIX=""
333 if [ ! "${DEVICE#/dev/mmcblk}" = "${DEVICE}" ] || [ ! "${DEVICE#/dev/loop}" = "${DEVICE}" ]; then
334         PART_PREFIX="p"
335 fi
336 BOOTFS=$DEVICE${PART_PREFIX}1
337 ROOTFS=$DEVICE${PART_PREFIX}2
338
339 TARGET_PART_PREFIX=""
340 if [ ! "${TARGET_DEVICE#/dev/mmcblk}" = "${TARGET_DEVICE}" ]; then
341         TARGET_PART_PREFIX="p"
342 fi
343 TARGET_ROOTFS=$TARGET_DEVICE${TARGET_PART_PREFIX}2
344
345 echo ""
346 info "Boot partition size:   $BOOT_SIZE MB ($BOOTFS)"
347 info "ROOTFS partition size: $ROOTFS_SIZE MB ($ROOTFS)"
348 echo ""
349
350 # Use MSDOS by default as GPT cannot be reliably distributed in disk image form
351 # as it requires the backup table to be on the last block of the device, which
352 # of course varies from device to device.
353
354 info "Partitioning installation media ($DEVICE)"
355
356 debug "Deleting partition table on $DEVICE"
357 dd if=/dev/zero of=$DEVICE bs=512 count=2 1>&3 2>&1 || die "Failed to zero beginning of $DEVICE"
358
359 debug "Creating new partition table (MSDOS) on $DEVICE"
360 parted -s $DEVICE mklabel msdos 1>&3 2>&1 || die "Failed to create MSDOS partition table"
361
362 debug "Creating boot partition on $BOOTFS"
363 parted -s $DEVICE mkpart primary 0% $BOOT_SIZE 1>&3 2>&1 || die "Failed to create BOOT partition"
364
365 debug "Enabling boot flag on $BOOTFS"
366 parted -s $DEVICE set 1 boot on 1>&3 2>&1 || die "Failed to enable boot flag"
367
368 debug "Creating ROOTFS partition on $ROOTFS"
369 parted -s $DEVICE mkpart primary $ROOTFS_START $ROOTFS_END 1>&3 2>&1 || die "Failed to create ROOTFS partition"
370
371 # as blkid does not provide PARTUUID on Ubuntu LTS 14.04 we myst hack via fdisk
372 #ROOTFS_PARTUUID=$(blkid |grep -e "$ROOTFS" |sed -n 's/^.*PARTUUID=/PARTUUID=/p')
373 export LC_ALL=C
374 ROOTFS_DISKID=$(fdisk -l "$DEVICE" | grep -e "Disk identifier" | sed -n 's/^.*Disk identifier: 0x/PARTUUID=/p')
375 if [ $ROOTFS_DISKID = "" ]; then
376     die "Failed to read DISKID"
377 fi
378 BOOTFS_PARTUUID="$ROOTFS_DISKID-01"
379 ROOTFS_PARTUUID="$ROOTFS_DISKID-02"
380 debug "PARTUUID for ROOTFS is $ROOTFS_PARTUUID"
381
382 if [ $DEBUG -eq 1 ]; then
383         parted -s $DEVICE print
384 fi
385
386
387 #
388 # Check if any $DEVICE partitions are mounted after partitioning
389 #
390 unmount_device || die "Failed to unmount $DEVICE partitions"
391
392
393 #
394 # Format $DEVICE partitions
395 #
396 info "Formatting partitions"
397 debug "Formatting $BOOTFS as ext2"
398 mkfs.ext2 -F -F -L BOOT $BOOTFS  1>&3 2>&1 || die "Failed to format $BOOTFS"
399
400 debug "Formatting $ROOTFS as ext4"
401 mkfs.ext4 -F $ROOTFS -L "ROOT" 1>&3 2>&1 || die "Failed to format $ROOTFS"
402
403
404 # Mounting image file system on loop devices
405 #
406 case $IMG_TYPE in
407
408   MOUNT) 
409      debug "Mounting images and device in preparation for installation"
410      mount -o loop $HDDIMG $HDDIMG_MNT 1>&3 2>&1 || die "Failed to mount $HDDIMG"
411      mount -o loop $HDDIMG_MNT/rootfs.img $HDDIMG_ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount rootfs.img"
412      ;;
413   DISK)
414      debug "Attaching image and mounting partitions then device in preparation for installation"
415      LOOP_DEVICE=`losetup --find` || die "Failled to find an available loop device see: losetup --find"
416      losetup -P $LOOP_DEVICE $HDDIMG  1>&3 2>&1 || die "Attaching $LOOP_DEVICE from $HDDIMG failled"
417      mount "$LOOP_DEVICE"p2  $HDDIMG_ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount $LOOP_DEVICEp1 on $HDDIMG_ROOTFS_MNT"
418      mount "$LOOP_DEVICE"p1  $HDDIMG_MNT       1>&3 2>&1 || die "Failed to mount $LOOP_DEVICEp2 on $HDDIMG_MNT"
419      ;;
420   *)
421       die "unknown image format $IMG_TYPE"
422       ;;
423 esac
424
425 mount $ROOTFS $ROOTFS_MNT 1>&3 2>&1 || die "Failed to mount $ROOTFS on $ROOTFS_MNT"
426 mount $BOOTFS $BOOTFS_MNT 1>&3 2>&1 || die "Failed to mount $BOOTFS on $BOOTFS_MNT"
427
428 info "Preparing boot partition"
429 # create the config file for iasImage
430 # Remove any existing root= kernel parameters and:
431 # o Add a root= parameter with the target rootfs
432 # o Specify ro so fsck can be run during boot
433 # o Specify rootwait in case the target media is an asyncronous block device
434 #   such as MMC or USB disks
435 # o Specify "quiet" to minimize boot time when using slow serial consoles
436
437 # iasImage command line file creation
438 echo "root=$ROOTFS_PARTUUID"   > $IAS_CMD_LINE
439 echo "console=$MRB_DEBUG_TTY" >> $IAS_CMD_LINE
440 echo "earlycon=uart8250,mmio32,0xfc000000,115200n8" >> $IAS_CMD_LINE
441 echo "rootwait" >> $IAS_CMD_LINE
442 echo "video=$MRB_HDMI" >> $IAS_CMD_LINE
443 echo "i915.enable_initial_modeset=1" >> $IAS_CMD_LINE
444 debug "temp config for iasImage is $IAS_CMD_LINE"
445
446 if [ -f $HDDIMG_MNT/vmlinuz ]; then
447    KERNEL_TYPE="vmlinuz"
448    debug "kernel is vmlinuz"
449 fi
450 if [ -f $HDDIMG_MNT/bzimage ]; then
451    KERNEL_TYPE="bzimage"
452    debug "kernel is bzimage -> vmlinuz"
453 fi
454 if [ -f $HDDIMG_MNT/microcode.cpio ]; then
455      warn "initrd=microcode.cpio is not a supported configuration, microcode.cpio has been ignored"
456 fi
457 [ -z $KERNEL_TYPE ] && die "Linux kernel type in $HDDIMG is unsupported"
458
459 if [ -f $HDDIMG_MNT/initrd ]; 
460   then
461      info "creating ABL image with initramsfs"
462      debug "$IAS_IMAGE_TOOL -o  $BOOTFS_MNT/iasImage -i 0x30000 $IAS_CMD_LINE $HDDIMG_MNT/$KERNEL_TYPE $HDDIMG_MNT/initrd"
463      $IAS_IMAGE_TOOL -o  $BOOTFS_MNT/iasImage -i 0x30000 $IAS_CMD_LINE $HDDIMG_MNT/$KERNEL_TYPE $HDDIMG_MNT/initrd
464   else
465      info "creating ABL image without initramfs"
466      debug "$IAS_IMAGE_TOOL -o  $BOOTFS_MNT/iasImage -i 0x30000 $IAS_CMD_LINE $HDDIMG_MNT/$KERNEL_TYPE"
467      $IAS_IMAGE_TOOL -o  $BOOTFS_MNT/iasImage -i 0x30000 $IAS_CMD_LINE $HDDIMG_MNT/$KERNEL_TYPE
468 fi     
469
470 printf "Copying ROOTFS files ... "
471 command -v rsync >/dev/null 2>&1 # check if rsync exists
472 if [ $DEBUG -eq 1 ] && [ $? -eq 0 ]; then
473         rsync --info=progress2 -h -aHAXW --no-compress  $HDDIMG_ROOTFS_MNT/* $ROOTFS_MNT 1>&3 2>&1 || die "Root FS copy failed"
474 else
475         cp -a $HDDIMG_ROOTFS_MNT/* $ROOTFS_MNT 1>&3 2>&1 || die "Root FS copy failed"
476 fi
477
478 debug "removing any swap entry in /etc/fstab"
479 sed --in-place '/swap/d' $ROOTFS_MNT/etc/fstab 
480 debug "fixing PARTUUID for /boot"
481 sed --in-place -e "s#PARTUUID=[0-9a-z-]\+\t/boot#${BOOTFS_PARTUUID}\t/boot#" $ROOTFS_MNT/etc/fstab
482
483 printf "flushing data on removable device. May take a while ... "
484 sync --file-system $ROOTFS_MNT
485 echo done
486
487 # We dont want udev to mount our root device while we're booting...
488 if [ -d $ROOTFS_MNT/etc/udev/ ] ; then
489         echo "$TARGET_DEVICE" >> $ROOTFS_MNT/etc/udev/mount.blacklist
490 fi
491
492
493 # Call cleanup to unmount devices and images and remove the TMPDIR
494 cleanup
495
496 echo ""
497 if [ $WARNINGS -ne 0 ] && [ $ERRORS -eq 0 ]; then
498         echo "${YELLOW}Installation completed with warnings${CLEAR}"
499         echo "${YELLOW}Warnings: $WARNINGS${CLEAR}"
500 elif [ $ERRORS -ne 0 ]; then
501         echo "${RED}Installation encountered errors${CLEAR}"
502         echo "${RED}Errors: $ERRORS${CLEAR}"
503         echo "${YELLOW}Warnings: $WARNINGS${CLEAR}"
504 else
505         success "Installation completed successfully"
506 fi
507 echo ""