bcm4908: support "rootfs_data" on U-Boot devices
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 <rafal@milecki.pl>
(cherry picked from commit 93259e8ca2)
			
			
This commit is contained in:
		
							
								
								
									
										73
									
								
								target/linux/bcm4908/base-files/lib/functions/bcm4908.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								target/linux/bcm4908/base-files/lib/functions/bcm4908.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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 || return | ||||
|  | ||||
| 	# 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 | ||||
| @@ -1,6 +1,8 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause | ||||
|  | ||||
| RAMFS_COPY_BIN="bcm4908img expr egrep fdtget fw_printenv fw_setenv tr" | ||||
| . /lib/functions/bcm4908.sh | ||||
|  | ||||
| RAMFS_COPY_BIN="bcm4908img expr egrep 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 | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Rafał Miłecki
					Rafał Miłecki