| |
| |
| #. /lib/functions.sh |
| |
| # 'kernel' partition on NAND contains the kernel |
| CI_KERNPART="${CI_KERNPART:-kernel}" |
| |
| # 'ubi' partition on NAND contains UBI |
| CI_UBIPART="${CI_UBIPART:-ubi}" |
| |
| # 'rootfs' partition on NAND contains the rootfs |
| CI_ROOTPART="${CI_ROOTPART:-rootfs}" |
| |
| find_mtd_index() { |
| local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')" |
| local INDEX="${PART##mtd}" |
| |
| echo ${INDEX} |
| } |
| |
| ubi_mknod() { |
| local dir="$1" |
| local dev="/dev/$(basename $dir)" |
| |
| [ -e "$dev" ] && return 0 |
| |
| local devid="$(cat $dir/dev)" |
| local major="${devid%%:*}" |
| local minor="${devid##*:}" |
| mknod "$dev" c $major $minor |
| } |
| |
| nand_find_volume() { |
| local ubidevdir ubivoldir |
| ubidevdir="/sys/devices/virtual/ubi/$1" |
| [ ! -d "$ubidevdir" ] && return 1 |
| for ubivoldir in $ubidevdir/${1}_*; do |
| [ ! -d "$ubivoldir" ] && continue |
| if [ "$( cat $ubivoldir/name )" = "$2" ]; then |
| basename $ubivoldir |
| ubi_mknod "$ubivoldir" |
| return 0 |
| fi |
| done |
| } |
| |
| nand_find_ubi() { |
| local ubidevdir ubidev mtdnum |
| mtdnum="$( find_mtd_index $1 )" |
| [ ! "$mtdnum" ] && return 1 |
| for ubidevdir in /sys/devices/virtual/ubi/ubi*; do |
| [ ! -d "$ubidevdir" ] && continue |
| cmtdnum="$( cat $ubidevdir/mtd_num )" |
| [ ! "$mtdnum" ] && continue |
| if [ "$mtdnum" = "$cmtdnum" ]; then |
| ubidev=$( basename $ubidevdir ) |
| ubi_mknod "$ubidevdir" |
| echo $ubidev |
| return 0 |
| fi |
| done |
| } |
| |
| nand_get_magic_long() { |
| dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"' |
| } |
| |
| get_magic_long_tar() { |
| ( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null |
| } |
| |
| identify_magic() { |
| local magic=$1 |
| case "$magic" in |
| "55424923") |
| echo "ubi" |
| ;; |
| "31181006") |
| echo "ubifs" |
| ;; |
| "68737173") |
| echo "squashfs" |
| ;; |
| "d00dfeed") |
| echo "fit" |
| ;; |
| "4349"*) |
| echo "combined" |
| ;; |
| *) |
| echo "unknown $magic" |
| ;; |
| esac |
| } |
| |
| |
| identify() { |
| identify_magic $(nand_get_magic_long "$1" "${2:-0}") |
| } |
| |
| identify_tar() { |
| identify_magic $(get_magic_long_tar "$1" "$2") |
| } |
| |
| nand_restore_config() { |
| sync |
| local ubidev=$( nand_find_ubi $CI_UBIPART ) |
| local ubivol="$( nand_find_volume $ubidev rootfs_data )" |
| [ ! "$ubivol" ] && |
| ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )" |
| mkdir /tmp/new_root |
| if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then |
| echo "mounting ubifs $ubivol failed" |
| rmdir /tmp/new_root |
| return 1 |
| fi |
| mv "$1" "/tmp/new_root/$BACKUP_FILE" |
| umount /tmp/new_root |
| sync |
| rmdir /tmp/new_root |
| } |
| |
| nand_upgrade_prepare_ubi() { |
| local rootfs_length="$1" |
| local rootfs_type="$2" |
| local has_kernel="${3:-0}" |
| local has_env="${4:-0}" |
| |
| local mtdnum="$( find_mtd_index "$CI_UBIPART" )" |
| echo -e "mtdnum = $mtdnum" |
| if [ ! "$mtdnum" ]; then |
| echo "cannot find ubi mtd partition $CI_UBIPART" |
| return 1 |
| fi |
| |
| local ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| |
| echo -e "ubidev = $ubidev" |
| if [ ! "$ubidev" ]; then |
| ubiattach -m "$mtdnum" |
| sync |
| ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| fi |
| |
| if [ ! "$ubidev" ]; then |
| ubiformat /dev/mtd$mtdnum -y |
| ubiattach -m "$mtdnum" |
| sync |
| ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| [ "$has_env" -gt 0 ] && { |
| ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB |
| ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB |
| } |
| fi |
| |
| local kern_ubivol="$( nand_find_volume $ubidev $CI_KERNPART )" |
| local root_ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )" |
| local data_ubivol="$( nand_find_volume $ubidev rootfs_data )" |
| |
| echo -e "root_ubivol = $root_ubivol" |
| # remove ubiblock device of rootfs |
| local root_ubiblk="ubiblock${root_ubivol:3}" |
| |
| echo -e "root_ubiblk = $root_ubiblk" |
| |
| if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then |
| echo "removing $root_ubiblk" |
| if ! ubiblock -r /dev/$root_ubivol; then |
| echo "cannot remove $root_ubiblk" |
| return 1; |
| fi |
| fi |
| |
| # kill volumes |
| [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_KERNPART || true |
| [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_ROOTPART || true |
| [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true |
| |
| # update kernel |
| if [ "$has_kernel" = "1" ]; then |
| if ! ubimkvol /dev/$ubidev -N $CI_KERNPART -s $kernel_length; then |
| echo "cannot create kernel volume" |
| return 1; |
| fi |
| fi |
| |
| # update rootfs |
| echo -e "rootfs_type = $rootfs_type" |
| |
| local root_size_param |
| if [ "$rootfs_type" = "ubifs" ]; then |
| root_size_param="-m" |
| else |
| root_size_param="-s $rootfs_length" |
| fi |
| if ! ubimkvol /dev/$ubidev -N $CI_ROOTPART $root_size_param; then |
| echo "cannot create rootfs volume" |
| return 1; |
| fi |
| |
| # create rootfs_data for non-ubifs rootfs |
| if [ "$rootfs_type" != "ubifs" ]; then |
| if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then |
| echo "cannot initialize rootfs_data volume" |
| return 1 |
| fi |
| fi |
| sync |
| return 0 |
| } |
| |
| nand_do_upgrade_success() { |
| local conf_tar="/tmp/sysupgrade.tgz" |
| |
| sync |
| [ -f "$conf_tar" ] && nand_restore_config "$conf_tar" |
| echo "sysupgrade successful" |
| umount -a |
| reboot -f |
| } |
| |
| # Flash the UBI image to MTD partition |
| nand_upgrade_ubinized() { |
| local ubi_file="$1" |
| local mtdnum="$(find_mtd_index "$CI_UBIPART")" |
| |
| [ ! "$mtdnum" ] && { |
| CI_UBIPART="rootfs" |
| mtdnum="$(find_mtd_index "$CI_UBIPART")" |
| } |
| |
| if [ ! "$mtdnum" ]; then |
| echo "cannot find mtd device $CI_UBIPART" |
| umount -a |
| reboot -f |
| fi |
| |
| local mtddev="/dev/mtd${mtdnum}" |
| ubidetach -p "${mtddev}" || true |
| sync |
| ubiformat "${mtddev}" -y -f "${ubi_file}" |
| ubiattach -p "${mtddev}" |
| nand_do_upgrade_success |
| } |
| |
| # Write the UBIFS image to UBI volume |
| nand_upgrade_ubifs() { |
| local rootfs_length=$( (cat $1 | wc -c) 2> /dev/null) |
| |
| nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0" |
| |
| local ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)" |
| ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1 |
| |
| nand_do_upgrade_success |
| } |
| |
| nand_upgrade_tar() { |
| local tar_file="$1" |
| local kernel_mtd="$(find_mtd_index $CI_KERNPART)" |
| |
| local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') |
| board_dir=${board_dir%/} |
| |
| local kernel_length=$( (tar xf $tar_file ${board_dir}/kernel -O | wc -c) 2> /dev/null) |
| local rootfs_length=$( (tar xf $tar_file ${board_dir}/root -O | wc -c) 2> /dev/null) |
| |
| local rootfs_type="$(identify_tar "$tar_file" ${board_dir}/root)" |
| |
| local has_kernel=1 |
| local has_env=0 |
| |
| [ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && { |
| tar xf $tar_file ${board_dir}/kernel -O | mtd write - $CI_KERNPART |
| } |
| [ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0 |
| |
| nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env" |
| |
| local ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| [ "$has_kernel" = "1" ] && { |
| local kern_ubivol="$(nand_find_volume $ubidev $CI_KERNPART)" |
| tar xf $tar_file ${board_dir}/kernel -O | \ |
| ubiupdatevol /dev/$kern_ubivol -s $kernel_length - |
| } |
| |
| local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)" |
| tar xf $tar_file ${board_dir}/root -O | \ |
| ubiupdatevol /dev/$root_ubivol -s $rootfs_length - |
| |
| nand_do_upgrade_success |
| } |
| |
| # Recognize type of passed file and start the upgrade process |
| nand_do_upgrade() { |
| local file_type=$(identify $1) |
| |
| [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs" |
| |
| case "$file_type" in |
| "ubi") nand_upgrade_ubinized $1;; |
| "ubifs") nand_upgrade_ubifs $1;; |
| *) nand_upgrade_tar $1;; |
| esac |
| } |
| |
| # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts |
| # 3 types of files: |
| # 1) UBI - should contain an ubinized image, header is checked for the proper |
| # MAGIC |
| # 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume, |
| # header is checked for the proper MAGIC |
| # 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty |
| # "CONTROL" file (at this point its content isn't verified) |
| # |
| # You usually want to call this function in platform_check_image. |
| # |
| # $(1): board name, used in case of passing TAR file |
| # $(2): file to be checked |
| nand_do_platform_check() { |
| local board_name="$1" |
| local tar_file="$2" |
| local control_length=$( (tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null) |
| local file_type="$(identify $2)" |
| |
| [ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && { |
| echo "Invalid sysupgrade file." |
| return 1 |
| } |
| |
| return 0 |
| } |
| |
| dual_boot_upgrade_prepare_ubi() { |
| local kernel_vol_name="$1" |
| local rootfs_vol_name="$2" |
| local kernel_length="$3" |
| local rootfs_length="$4" |
| local reserve_rootfs_data="$5" |
| |
| local mtdnum="$( find_mtd_index "$CI_UBIPART" )" |
| if [ ! "$mtdnum" ]; then |
| echo "cannot find ubi mtd partition $CI_UBIPART" |
| return 1 |
| fi |
| |
| local ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| if [ ! "$ubidev" ]; then |
| ubiattach -m "$mtdnum" |
| sync |
| ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| fi |
| |
| if [ ! "$ubidev" ]; then |
| ubiformat /dev/mtd$mtdnum -y |
| ubiattach -m "$mtdnum" |
| sync |
| ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| ubimkvol /dev/$ubidev -n 0 -N u-boot-env -s 512KiB |
| fi |
| |
| local rootfs_data_vol_name=$(cat /sys/module/boot_param/parameters/rootfs_data_part 2>/dev/null) |
| |
| local kern_ubivol="$( nand_find_volume $ubidev $kernel_vol_name )" |
| local root_ubivol="$( nand_find_volume $ubidev $rootfs_vol_name )" |
| local data_ubivol="$( nand_find_volume $ubidev $rootfs_data_vol_name )" |
| |
| # remove ubiblock device of rootfs |
| local root_ubiblk="ubiblock${root_ubivol:3}" |
| if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then |
| echo "removing $root_ubiblk" |
| if ! ubiblock -r /dev/$root_ubivol; then |
| echo "cannot remove $root_ubiblk" |
| return 1; |
| fi |
| fi |
| |
| # kill volumes |
| [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N $kernel_vol_name || true |
| [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N $rootfs_vol_name || true |
| |
| # update kernel |
| if ! ubimkvol /dev/$ubidev -N $kernel_vol_name -s $kernel_length; then |
| echo "cannot create kernel volume" |
| return 1; |
| fi |
| |
| # update rootfs |
| if ! ubimkvol /dev/$ubidev -N $rootfs_vol_name -s $rootfs_length; then |
| echo "cannot create rootfs volume" |
| return 1; |
| fi |
| |
| if [ x"${reserve_rootfs_data}" = xY ]; then |
| # Do not touch rootfs_data |
| sync |
| return 0 |
| fi |
| |
| # 'format' rootfs_data volume |
| [ "$data_ubivol" ] && { |
| local rootfs_data_length=$(cat /sys/class/ubi/$data_ubivol/data_bytes) |
| |
| # kill rootfs_data volume |
| ubirmvol /dev/$ubidev -N $rootfs_data_vol_name || true |
| |
| # update rootfs_data |
| if ! ubimkvol /dev/$ubidev -N $rootfs_data_vol_name -s $rootfs_data_length; then |
| echo "cannot create $rootfs_data_vol_name volume" |
| fi |
| } |
| |
| sync |
| return 0 |
| } |
| |
| ubi_dual_boot_upgrade_tar() { |
| local tar_file="$1" |
| local board_dir=$(tar tf ${tar_file} | grep -m 1 '^sysupgrade-.*/$') |
| local reserve_rootfs_data=$(cat /sys/module/boot_param/parameters/reserve_rootfs_data 2>/dev/null) |
| board_dir=${board_dir%/} |
| |
| kernel_vol_name=$(cat /sys/module/boot_param/parameters/upgrade_kernel_part 2>/dev/null) |
| [ -z "${kernel_vol_name}" -o $? -ne 0 ] && return 1 |
| |
| rootfs_vol_name=$(cat /sys/module/boot_param/parameters/upgrade_rootfs_part 2>/dev/null) |
| [ -z "${rootfs_vol_name}" -o $? -ne 0 ] && return 1 |
| |
| local kernel_length=$( (tar xf ${tar_file} ${board_dir}/kernel -O | wc -c) 2> /dev/null) |
| local rootfs_length=$( (tar xf ${tar_file} ${board_dir}/root -O | wc -c) 2> /dev/null) |
| |
| dual_boot_upgrade_prepare_ubi "${kernel_vol_name}" "${rootfs_vol_name}" \ |
| "${kernel_length}" "${rootfs_length}" \ |
| "${reserve_rootfs_data}" |
| |
| local ubidev="$( nand_find_ubi "$CI_UBIPART" )" |
| |
| [ "${kernel_length}" != 0 ] && { |
| local kern_ubivol="$(nand_find_volume $ubidev ${kernel_vol_name})" |
| tar xf ${tar_file} ${board_dir}/kernel -O | \ |
| ubiupdatevol /dev/${kern_ubivol} -s ${kernel_length} - |
| } |
| |
| [ "${rootfs_length}" != 0 ] && { |
| local root_ubivol="$(nand_find_volume $ubidev ${rootfs_vol_name})" |
| tar xf ${tar_file} ${board_dir}/root -O | \ |
| ubiupdatevol /dev/${root_ubivol} -s ${rootfs_length} - |
| } |
| |
| upgrade_image_slot=$(cat /sys/module/boot_param/parameters/upgrade_image_slot 2>/dev/null) |
| [ -n "${upgrade_image_slot}" ] && { |
| v "Set new boot image slot to ${upgrade_image_slot}" |
| # Force the creation of fw_printenv.lock |
| mkdir -p /var/lock |
| touch /var/lock/fw_printenv.lock |
| fw_setenv "dual_boot.current_slot" "${upgrade_image_slot}" |
| fw_setenv "dual_boot.slot_${upgrade_image_slot}_invalid" "0" |
| } |
| |
| if [ x"${reserve_rootfs_data}" != xY ]; then |
| # do normal upgrade flow |
| nand_do_upgrade_success |
| fi |
| |
| # Do not touch rootfs_data |
| sync |
| |
| echo "sysupgrade successful" |
| #umount -a |
| #reboot -f |
| } |
| |
| ubi_do_upgrade() { |
| local dual_boot=$(cat /sys/module/boot_param/parameters/dual_boot 2>/dev/null) |
| local file_type=$(identify $1) |
| |
| if [ -b /dev/dm-0 ]; then |
| v "Detach all device mapper devices" |
| dmsetup remove_all |
| fi |
| |
| if [ x"${dual_boot}" != xY ]; then |
| nand_do_upgrade "$1" |
| return |
| fi |
| |
| case "$file_type" in |
| "ubi") v "Unsupported firmware type: ubinized";; |
| "ubifs") v "Unsupported firmware type: ubifs";; |
| *) ubi_dual_boot_upgrade_tar $1;; |
| esac |
| } |