diff options
-rw-r--r-- | config.sh | 6 | ||||
-rwxr-xr-x | kflash.sh | 322 |
2 files changed, 328 insertions, 0 deletions
@@ -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 |