summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-02-26 03:04:24 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-02-26 03:04:24 +0200
commitda38494a24cda48a0a41b12ae798a7414bda98cc (patch)
tree62ec886ce1579a76560a224e82524f3d21dffd31
parentbd2675a8b0f51d91d65da0101bba13c147cad59b (diff)
Add a kflash.sh flashing script
The script eases flashing a kernel, modules and DT to a removable device. It detects the device based on partition name patterns defined in platform files, performs sanity checks to avoid overwriting system disks (such as making sure none of the target partitions are already mounted), copies files to raw partitions with dd or to file systems with cp or rsync, and beeps when done. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--config.sh6
-rwxr-xr-xkflash.sh322
2 files changed, 328 insertions, 0 deletions
diff --git a/config.sh b/config.sh
index d6b6db8..d11551e 100644
--- a/config.sh
+++ b/config.sh
@@ -9,6 +9,12 @@ cross_compile[arm64]=aarch64-buildroot-linux-gnu-
#
# Directories
#
+# Variable name: flash_mount_point
+#
+# Path to a directory where the target disk can be mounted.
+#
+flash_mount_point=/mnt/disk
+#
# Variable name: target_root[]
#
# Path to the root directory of the target file system for each architecture.
diff --git a/kflash.sh b/kflash.sh
new file mode 100755
index 0000000..92ca9dd
--- /dev/null
+++ b/kflash.sh
@@ -0,0 +1,322 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0+
+
+set -e
+
+kbuild_root=$(dirname $(readlink -f "$0"))
+
+declare -A cross_compile
+declare -A extra_kcflags
+declare -A target_root
+
+if [[ -r $kbuild_root/config.sh ]] ; then
+ source $kbuild_root/config.sh || exit 1
+fi
+
+#
+# Options parsing
+#
+
+dry_run=0
+silent=0
+sudo=sudo
+
+while [[ $# != 0 ]] ; do
+ option=$1
+ shift
+
+ case $option in
+ --dry-run)
+ dry_run=1
+ sudo=echo
+ ;;
+ --silent)
+ silent=1
+ ;;
+ --*|-*)
+ echo "Unrecognized option $option"
+ exit 1
+ ;;
+ *)
+ platform=$option
+ ;;
+ esac
+done
+
+#
+# Platform
+#
+
+if [[ -z "$platform" ]] ; then
+ for f in $kbuild_root/platforms/*.sh ; do
+ pattern=$(cat $f | grep "dir_pattern=" | head -1)
+ pattern=${pattern/#dir_pattern=/}
+ if [[ -n "$pattern" ]] ; then
+ echo $PWD | grep -q "$pattern" || continue
+ platform=$(basename -s .sh $f)
+ break
+ fi
+ done
+fi
+
+if [[ ! -r "$kbuild_root/platforms/$platform.sh" ]] ; then
+ echo "Unknown platform '$platform'. Supported platforms are"
+ for f in $kbuild_root/platforms/*.sh ; do
+ echo "- $(basename -s .sh $f)"
+ done
+ exit 1
+fi
+
+source "${kbuild_root}/platforms/$platform.sh" || exit 1
+
+if [[ "${#flash_parts[@]}" -lt 1 ]] ; then
+ echo "Platform '$platform' doesn't declare flash_parts, can't flash"
+ exit 1
+fi
+
+#
+# Architecture
+#
+
+if [[ ! -r "$kbuild_root/arch/$arch.sh" ]] ; then
+ echo "Unknown architecture '$arch'. Supported architectures are"
+ for f in $kbuild_root/arch/*.sh ; do
+ echo "- $(basename -s .sh $f)"
+ done
+ exit 1
+fi
+
+source "${kbuild_root}/arch/$arch.sh" || exit 1
+
+# Override the output directory for ARM for historical reasons
+case $arch in
+ arm)
+ output_dir=$PWD/output/arm32
+ ;;
+ *)
+ output_dir=$PWD/output/$arch
+ ;;
+esac
+
+target_dir=${target_dir:-${target_root[$arch]}}
+tftp_dir=${tftp_dir:-$tftp_root/$platform}
+
+if [[ -r "$kbuild_root/images/$image.sh" ]] ; then
+ source "${kbuild_root}/images/$image.sh" || exit 1
+ eval make_${image}_image
+else
+ image_file=$output_dir/arch/$arch/boot/$image
+fi
+
+#
+# Validate the partition names and paths
+#
+
+for part_name in ${!flash_parts[@]} ; do
+ case $part_name in
+ dt|kernel|modules)
+ ;;
+ *)
+ echo "Unknown partition name '$part_name'"
+ exit 1
+ ;;
+ esac
+
+ ifs="$IFS"; IFS=";" read -ra flash_part <<< "${flash_parts[$part_name]}"; IFS="$ifs"
+ part_path=${flash_part[2]}
+
+ case $part_path in
+ RAW|/*)
+ ;;
+ *)
+ echo "Unknown partition path '$part_path'"
+ exit 1
+ ;;
+ esac
+done
+
+#
+# Locate the flash device
+#
+
+probe_device() {
+ local dev=$1
+
+ # Skip devices that don't exist.
+ if [[ ! -b /dev/$dev ]] ; then
+ return
+ fi
+
+ # Add the 'p' suffix for MMC devices.
+ local partdev=$dev
+ echo $dev | grep -q mmcblk && partdev=${partdev}p
+
+ #
+ # Safety check: make sure the number and name of the partitions we will
+ # flash match the expectations.
+ #
+ local part_count=$(ls -1 /dev/ | grep "${partdev}[0-9]" | wc -l)
+ if [[ $part_count != $flash_parts_num ]] ; then
+ echo "Device /dev/$dev has $part_count partitions, $flash_parts_num expected" >&2
+ return
+ fi
+
+ local part_name
+ for part_name in ${!flash_parts[@]} ; do
+ local flash_part
+ IFS=";" read -ra flash_part <<< "${flash_parts[$part_name]}"
+
+ local part_idx=${flash_part[0]}
+ local part_label=${flash_part[1]}
+ local part_dev=/dev/${partdev}${i}
+
+ local label=$(blkid ${part_dev} -s PARTLABEL | sed 's/.*PARTLABEL="\([^"]*\)"$/\1/')
+ if [[ $label != ${part_label} ]] ; then
+ echo "Partition ${part_dev} has label '$label', expected '${part_label}'" >&2
+ return
+ fi
+ done
+
+ echo /dev/$partdev
+}
+
+disks="mmcblk0 sda"
+dev=
+
+for disk in $disks ; do
+ dev=$(probe_device "$disk")
+ if [[ -n "$dev" ]] ; then
+ break
+ fi
+done
+
+if [[ -z "$dev" ]] ; then
+ echo "No flash device found"
+ exit 1
+fi
+
+echo "Found flash device ${dev}"
+
+#
+# Safety check: make sure nothing is mounted on $flash_mount_point, and no
+# partition from the device is mounted.
+#
+
+if mount | grep -q " on $flash_mount_point " ; then
+ echo "File system already mounted on $flash_mount_point."
+ exit 1
+fi
+
+if mount | grep -q "$dev" ; then
+ echo "Please unmount partitions $dev* before proceeding."
+ exit 1
+fi
+
+#
+# Safety check: make sure the kernel modules are installed.
+#
+
+version=$(cat $output_dir/include/generated/utsrelease.h | cut -d '"' -f 2)
+mod_path="$target_dir/lib/modules/$version"
+
+if [[ ! -d "$mod_path" ]] ; then
+ echo "Modules not installed in $mod_path"
+ exit 1
+fi
+
+#
+# Flash
+#
+
+for part_name in ${!flash_parts[@]} ; do
+ IFS=";" read -ra flash_part <<< "${flash_parts[$part_name]}"
+ part_idx=${flash_part[0]}
+
+ if [[ -z "$flash_msg" ]] ; then
+ flash_msg="Will flash $part_name to ${dev}${part_idx}"
+ else
+ flash_msg="${flash_msg}, $part_name to ${dev}${part_idx}"
+ fi
+done
+
+if [[ ${dry_run} == 1 ]] ; then
+ flash_msg="${flash_msg} (dry-run)"
+fi
+
+echo "${flash_msg}."
+echo -n "Proceed? [y/N] "
+
+read answer
+
+if [[ x$answer != xy ]] ; then
+ echo "Aborted"
+ exit 1
+fi
+
+flash_raw() {
+ local dst="$1"
+ local src="$3"
+
+ ${sudo} dd if="$src" of="$dst" bs=64k
+}
+
+flash_fs() {
+ local dev="$1"
+ local dst="${flash_mount_point}$2"
+ local src="$3"
+
+ ${sudo} mount "$dev" "$flash_mount_point"
+ trap "${sudo} umount $flash_mount_point" EXIT
+
+ if [[ -f "$src" ]] ; then
+ ${sudo} cp "$src" "$dst"
+ else
+ ${sudo} rsync -av --delete "$src" "$dst"
+ fi
+
+ trap - EXIT
+ ${sudo} umount "$flash_mount_point"
+}
+
+for part_name in ${!flash_parts[@]} ; do
+ IFS=";" read -ra flash_part <<< "${flash_parts[$part_name]}"
+ part_idx=${flash_part[0]}
+ part_path=${flash_part[2]}
+
+ echo "Flashing ${part_name} (${part_path})"
+
+ case $part_path in
+ RAW)
+ flash_cmd="flash_raw"
+ ;;
+ /*)
+ flash_cmd="flash_fs"
+ ;;
+ esac
+
+ case $part_name in
+ dt)
+ # For DT, only flash the first entry. This can be improved later if
+ # needed.
+ read -ra _dtbs <<< "$dtbs"
+ _dtb=${_dtbs[0]}
+ _dtb_src="$output_dir/arch/${arch}/boot/dts/${_dtb/:*/}"
+ _dtb_dst=${_dtb/*:/}
+ _dtb_dst=${_dtb_dst/*\//}
+
+ $flash_cmd "${dev}${part_idx}" "${part_path}/${_dtb_dst}" "${_dtb_src}"
+ ;;
+ kernel)
+ $flash_cmd "${dev}${part_idx}" "${part_path}/" "${image_file}"
+ ;;
+ modules)
+ $flash_cmd "${dev}${part_idx}" "${part_path}/" "${mod_path}"
+ ;;
+ esac
+done
+
+echo "Files copied, syncing"
+${sudo} sync
+echo "Done"
+
+[[ $silent == 0 ]] && play -q -n synth 0.1 sin 880