[PATCH] bcm4908: support "rootfs_data" on U-Boot devices

Rafał Miłecki zajec5 at gmail.com
Wed Jan 5 14:16:20 PST 2022


From: Rafał Miłecki <rafal at milecki.pl>

1. Create "rootfs_data" dynamicaly

U-Boot firmware images can contain only kernel and rootfs volume
(squashfs in case of OpenWrt). 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
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 at milecki.pl>
---
Used "overlay_verify" file requires pending fstools change:
[PATCH fstools] libfstools: support custom executable validating overlay

An alternative way would be to mount ubifs manually in preinit script.
That would be a bit hacky but wouldn't require fstools to call that
custom validation script.

Felix suggested validation script however.
---
 .../base-files/lib/preinit/75_rootfs_prepare  | 19 +++++++
 .../base-files/usr/libexec/overlay_verify     | 57 +++++++++++++++++++
 2 files changed, 76 insertions(+)
 create mode 100644 target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare
 create mode 100755 target/linux/bcm4908/base-files/usr/libexec/overlay_verify

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..70bd71eea8
--- /dev/null
+++ b/target/linux/bcm4908/base-files/lib/preinit/75_rootfs_prepare
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+rootfs_prepare() {
+	local blocks
+
+	ubinfo /dev/ubi0 -N rootfs_data > /dev/null 2>&1 && return
+
+	blocks=$(cat /sys/class/ubi/ubi0/avail_eraseblocks)
+	[ -z "$blocks" ] && {
+		echo "Failed to read amount of available erase blocks"
+		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
+}
+
+boot_hook_add preinit_main rootfs_prepare
diff --git a/target/linux/bcm4908/base-files/usr/libexec/overlay_verify b/target/linux/bcm4908/base-files/usr/libexec/overlay_verify
new file mode 100755
index 0000000000..02b2f48ca7
--- /dev/null
+++ b/target/linux/bcm4908/base-files/usr/libexec/overlay_verify
@@ -0,0 +1,57 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+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"'
+}
+
+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
+}
+
+image_seq() {
+	platform_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
+	# Maybe this isn't U-Boot after all?
+	# Let booting try to proceed
+	exit 0
+}
+
+# Do nothing on CFE devices
+ubinfo /dev/ubi0 -N metadata1 > /dev/null 2>&1 || exit 0
+
+image_seq="$(image_seq)"
+
+# Wipe rootfs_data if it doesn't belong to us
+[ "$(readlink $1/.openwrt-image-seq)" != "$image_seq" ] && {
+	echo "Erasing old \"rootfs_data\""
+	rm -fR $1/*
+}
+
+# If rootfs_data is clean (or was just wiped) claim it
+[ -z "$(ls -A $1)" ] && {
+	# Claim this "rootfs_data"
+	ln -s $image_seq $1/.openwrt-image-seq
+	# Mark it readt to avoid "mount_root" wiping it again
+	ln -s $FS_STATE_READY $1/.fs_state
+}
+
+exit 0
-- 
2.31.1




More information about the openwrt-devel mailing list