blob: 90fc5190d10bd3130caecf4e9ab6ccba303f374a [file] [log] [blame]
#. /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
}