From 93259e8ca261c7965618fe11c2d385638da5cfa6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 4 Mar 2022 16:03:26 +0100 Subject: [PATCH] bcm4908: support "rootfs_data" on U-Boot devices MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 1. Create "rootfs_data" dynamicaly U-Boot firmware images can contain only 2 UBI volumes: bootfs (container with U-Boot + kernel + DTBs) and rootfs (e.g. squashfs). There is no way to include "rootfs_data" UBI volume or make firmware file tell U-Boot to create one. For that reason "rootfs_data" needs to be created dynamically. Use preinit script to handle that. Fire it right before "mount_root" one. 2. Relate "rootfs_data" to flashed firmware As already explained flashing new firmware with U-Boot will do nothing to the "rootfs_data". It could result in new firmware reusing old "rootfs_data" overlay UBI volume and its file. Users expect a clean state after flashing firmware (even if flashing the same one). Solve that by reading flash counter of running firmware and storing it in "rootfs_data" UBI volume. Every mismatch will result in wiping old data. Signed-off-by: Rafał Miłecki --- .../base-files/lib/functions/bcm4908.sh | 73 +++++++++++++++++++ .../base-files/lib/preinit/75_rootfs_prepare | 35 +++++++++ .../base-files/lib/upgrade/platform.sh | 27 +++---- 3 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 target/linux/bcm4908/base-files/lib/functions/bcm4908.sh create mode 100644 target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare diff --git a/target/linux/bcm4908/base-files/lib/functions/bcm4908.sh b/target/linux/bcm4908/base-files/lib/functions/bcm4908.sh new file mode 100644 index 0000000000..aea31e794b --- /dev/null +++ b/target/linux/bcm4908/base-files/lib/functions/bcm4908.sh @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + +FS_STATE_READY=2 + +# $(1): file to read from +# $(2): offset in bytes +get_hex_u32_le() { + dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -e '1/4 "%02x"' +} + +# Setup /tmp/env.config to provide "metadata" UBI volume access +# +# It can be used with "fw_printenv -c /tmp/env.config" +bcm4908_pkgtb_setup_env_config() { + local size=$((0x$(get_hex_u32_le /dev/ubi0_1 4))) + + dd if=/dev/ubi0_1 of=/tmp/env.head count=8 iflag=count_bytes + dd if=/dev/ubi0_1 of=/tmp/env.body skip=8 iflag=skip_bytes + printf "%s\t0x%x\t0x%x\t0x%x" "/tmp/env.body" 0x0 $size $size > /tmp/env.config +} + +bcm4908_committed_image_seq() { + bcm4908_pkgtb_setup_env_config + + commited="$(fw_printenv -n -c /tmp/env.config COMMITTED)" + [ -n "$commited" ] && { + seq=$(fw_printenv -n -c /tmp/env.config SEQ | cut -d ',' -f $commited) + [ -n "$seq" ] && { + echo $seq + return + } + } + + echo "Failed to read COMMITED and SEQ from metadata1" >&2 +} + +# Make sure "rootfs_data" UBI volume matches currently flashed image +# +# On mismatch "rootfs_data" will be wiped and assigned +# +# $1: UBI volume of "rootfs_data" (e.g. ubi0_123) +bcm4908_verify_rootfs_data() { + local ubivol="$1" + local dir=/tmp/rootfs_data + local seq="$(bcm4908_committed_image_seq)" + + [ -z "$seq" ] && return + + mkdir $dir + if ! mount -t ubifs /dev/$ubivol $dir; then + echo "Failed to mount $ubivol UBI volume" >&2 + rmdir $dir + return + fi + + # Wipe rootfs_data if it doesn't belong to us + [ "$(readlink $dir/.openwrt-image-seq)" != "$seq" ] && { + echo "Removing \"rootfs_data\" content" + rm -rf $dir/..?* $dir/.[!.]* $dir/* + } + + # If rootfs_data is clean (or was just wiped) claim it + [ -z "$(ls -A $dir)" ] && { + echo "Assigning \"rootfs_data\" to the current firmware" + # Claim this "rootfs_data" + ln -s $seq $dir/.openwrt-image-seq + # Mark it ready to avoid "mount_root" wiping it again + ln -s $FS_STATE_READY $dir/.fs_state + } + + umount $dir + rmdir $dir +} diff --git a/target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare b/target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare new file mode 100644 index 0000000000..07fa21814e --- /dev/null +++ b/target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + +. /lib/functions/bcm4908.sh + +rootfs_create() { + local blocks + + blocks=$(cat /sys/class/ubi/ubi0/avail_eraseblocks) + [ -z "$blocks" ] && { + echo "Failed to read amount of available erase blocks" >&2 + return + } + + # Use 80% of remaining flash size for "rootfs_data" + ubimkvol /dev/ubi0 -n 20 -N rootfs_data --lebs $((blocks / 100 * 80)) + mknod -m 0600 /dev/ubi0_20 c 252 21 + + bcm4908_verify_rootfs_data ubi0_20 +} + +rootfs_prepare() { + # Do nothing on CFE devices + ubinfo /dev/ubi0 -N metadata1 > /dev/null 2>&1 || exit 0 + + # Find UBI volume device (e.g. ubi0_123) + local ubivol="$(grep rootfs_data /sys/devices/virtual/ubi/ubi*/ubi*/name | sed -n 's/.*\(ubi\d*_\d*\).*/\1/p')" + if [ -n "$ubivol" ]; then + bcm4908_verify_rootfs_data $ubivol + else + echo "Creating \"rootfs_data\" UBI volume" + rootfs_create + fi +} + +boot_hook_add preinit_main rootfs_prepare diff --git a/target/linux/bcm4908/base-files/lib/upgrade/platform.sh b/target/linux/bcm4908/base-files/lib/upgrade/platform.sh index 1b94801fb0..0974331801 100644 --- a/target/linux/bcm4908/base-files/lib/upgrade/platform.sh +++ b/target/linux/bcm4908/base-files/lib/upgrade/platform.sh @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -RAMFS_COPY_BIN="bcm4908img expr grep fdtget fw_printenv fw_setenv tr" +. /lib/functions/bcm4908.sh + +RAMFS_COPY_BIN="bcm4908img expr grep ln fdtget fw_printenv fw_setenv readlink tr" PART_NAME=firmware @@ -134,17 +136,7 @@ platform_pkgtb_get_image() { } } -platform_pkgtb_setup_env_config() { - local size=$((0x$(get_hex_u32_le /dev/ubi0_1 4))) - - dd if=/dev/ubi0_1 of=/tmp/env.head count=8 iflag=count_bytes - dd if=/dev/ubi0_1 of=/tmp/env.body skip=8 iflag=skip_bytes - printf "%s\t0x%x\t0x%x\t0x%x" "/tmp/env.body" 0x0 $size $size > /tmp/env.config -} - platform_pkgtb_get_upgrade_index() { - platform_pkgtb_setup_env_config - case "$(fw_printenv -l /tmp -n -c /tmp/env.config COMMITTED)" in 1) echo 2;; 2) echo 1;; @@ -160,8 +152,6 @@ platform_pkgtb_commit() { local seq2 local tmp - platform_pkgtb_setup_env_config - # Read current values for valid in $(fw_printenv -l /tmp -n -c /tmp/env.config VALID | tr ',' ' '); do case "$valid" in @@ -272,11 +262,20 @@ platform_check_image() { # upgrade # +platform_pkgtb_clean_rootfs_data() { + local ubidev=$(nand_find_ubi $CI_UBIPART) + local ubivol="$(nand_find_volume $ubidev rootfs_data)" + + bcm4908_verify_rootfs_data "$ubivol" +} + platform_do_upgrade_pkgtb() { local cmd="${2:-cat}" local size local idx bootfs_id rootfs_id + bcm4908_pkgtb_setup_env_config + idx=$(platform_pkgtb_get_upgrade_index) case "$idx" in 1) bootfs_id=3; rootfs_id=4;; @@ -295,6 +294,8 @@ platform_do_upgrade_pkgtb() { platform_pkgtb_commit $idx + CI_UBIPART="image" + platform_pkgtb_clean_rootfs_data nand_do_upgrade_success } -- 2.30.2