summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Moussalem2025-12-03 19:22:09 +0000
committerRobert Marko2025-12-24 09:42:39 +0000
commitd02de1d35a37cdcb3890aef5cbddee598ff16a7d (patch)
treeb293960b5e7386e53c6e5ed8b3938a2558a63d63
parent606a87ec442736afe3ffed60c3572bbd1ae153aa (diff)
downloadopenwrt-d02de1d35a37cdcb3890aef5cbddee598ff16a7d.tar.gz
qualcommax: ipq50xx: functions for bootconfig partition
The BOOTCONFIG partition is used by Qualcomm's boot chain to store metadata about the device's startup configuration. It contains info such as versioning, configuration flags, primary boot partition, and more. Newer devices with dual boot partitions not only store the active boot partition in a U-boot variable but also in partition info in the BOOTCONFIG partition. As such, add library functions to set and toggle the active boot partition. Signed-off-by: George Moussalem <george.moussalem@outlook.com> Link: https://github.com/openwrt/openwrt/pull/21038 Signed-off-by: Robert Marko <robimarko@gmail.com>
-rw-r--r--target/linux/qualcommax/ipq50xx/base-files/lib/functions/bootconfig.sh177
1 files changed, 177 insertions, 0 deletions
diff --git a/target/linux/qualcommax/ipq50xx/base-files/lib/functions/bootconfig.sh b/target/linux/qualcommax/ipq50xx/base-files/lib/functions/bootconfig.sh
new file mode 100644
index 0000000000..3632c6a25e
--- /dev/null
+++ b/target/linux/qualcommax/ipq50xx/base-files/lib/functions/bootconfig.sh
@@ -0,0 +1,177 @@
+. /lib/functions.sh
+
+PART_SIZE=20
+NAME_SIZE=16
+MAX_NUM_PARTS=16
+
+MAGIC_START_HEX="a0 a1 a2 a3"
+MAGIC_START_TRY_HEX="a1 a1 a2 a3"
+MAGIC_END_HEX="b0 b1 b2 b3"
+
+validate_bootconfig_magic() {
+ local file=$1
+ magic_start=$(hexdump -v -n 4 -e '4/1 "%02x "' "$file")
+ magic_end=$(hexdump -v -s 332 -n 4 -e '4/1 "%02x "' "$file")
+
+ if [ "$magic_start" != "$MAGIC_START_HEX" ] && \
+ [ "$magic_start" != "$MAGIC_START_TRY_HEX" ]; then
+ echo "Not a valid bootconfig file, start magic does not match" >&2
+ return 1
+ fi
+
+ if [ "$magic_end" != "$MAGIC_END_HEX" ]; then
+ echo "Not a valid bootconfig file, end magic does not match" >&2
+ return 1
+ fi
+ return 0
+}
+
+get_bootconfig_numparts() {
+ local file=$1
+ numpartshex=$(hexdump -v -s 8 -n 4 -e '4/1 "%02x "' "$file")
+ numparts=$(( 0x$(echo $numpartshex | awk '{print $4$3$2$1}') ))
+ echo ${numparts}
+}
+
+get_bootconfig_partidx() {
+ local file=$1
+ local partname=$2
+ local numparts=$(get_bootconfig_numparts "$file")
+
+ if [ -z "$numparts" ]; then
+ echo "Could not get number of partitions" >&2
+ return
+ fi
+
+ if [ $numparts -gt $MAX_NUM_PARTS ]; then
+ numparts=$MAX_NUM_PARTS
+ fi
+
+ for i in $(seq 0 $((numparts -1))); do
+ nameoffset=$((12 + i * $PART_SIZE))
+ nameraw=$(dd if="$file" bs=1 skip="$nameoffset" count=12 2>/dev/null)
+ name=${nameraw//S'\x00'/}
+ if [ "$partname" = "$name" ]; then
+ echo $i
+ fi
+ done
+}
+
+get_bootconfig_primaryboot() {
+ local file=$1
+ local partname=$2
+
+ local partidx=$(get_bootconfig_partidx "$file" "$partname")
+ if ! echo "$partidx" | grep -Eq '^[0-9]+$'; then
+ echo "Could not get partition index for $partname in $file" >&2
+ return
+ fi
+
+ if [ "$partidx" -ge 0 ] && [ "$partidx" -lt $MAX_NUM_PARTS ]; then
+ offset=$((12 + $partidx * $PART_SIZE + $NAME_SIZE))
+ primaryboothex=$(hexdump -v -s "$offset" -n 4 -e '4/1 "%02x "' $file)
+ primaryboot=$(( 0x$(echo $primaryboothex | awk '{print $4$3$2$1}') ))
+ echo $primaryboot
+ fi
+}
+
+_set_bootconfig_primaryboot() {
+ local file=$1
+ local partname=$2
+ local primaryboot=$3
+ local primaryboothex
+ local partidx
+ local primarybootoffset
+
+ partidx=$(get_bootconfig_partidx "$file" "$partname")
+ if ! echo "$partidx" | grep -Eq '^[0-9]+$'; then
+ echo "Could not get partition index for $2" >&2
+ return 1
+ fi
+ primarybootoffset=$((12 + $partidx * $PART_SIZE + $NAME_SIZE))
+
+ case "$primaryboot" in
+ 0)
+ printf "\x00\x00\x00\x00" | dd of="$file" seek="$primarybootoffset" bs=1 count=4 conv=notrunc 2>/dev/null
+ ;;
+ 1)
+ printf "\x01\x00\x00\x00" | dd of="$file" seek="$primarybootoffset" bs=1 count=4 conv=notrunc 2>/dev/null
+ ;;
+ *)
+ echo "invalid argument: primaryboot must be 0 or 1" >&2
+ return 1
+ ;;
+ esac
+}
+
+set_bootconfig_primaryboot() {
+ local file=$1
+ local partname=$2
+ local primaryboot=$3
+
+ [ -z "$file" ] || [ -z "$partname" ] || [ -z "$primaryboot" ] && {
+ echo "usage: $0 <file> <partition name> <0|1>"
+ return 1
+ }
+
+ [ ! -e "$file" ] && {
+ echo "file $file not found" >&2
+ return 1
+ }
+
+ [ ! -w $file ] && {
+ echo "file $file not writable" >&2
+ return 1
+ }
+
+ validate_bootconfig_magic "$file"
+ [ $? -ne 0 ] && return 1
+
+ _set_bootconfig_primaryboot $file $partname $primaryboot
+ [ $? -ne 0 ] && return 1
+
+ return 0
+}
+
+toggle_bootconfig_primaryboot() {
+ local file=$1
+ local partname=$2
+ local primaryboot
+
+ [ -z "$file" ] || [ -z "$partname" ] && {
+ echo "usage: $0 <file> <partition name>"
+ return 1
+ }
+
+ [ ! -e "$file" ] && {
+ echo "file $file not found" >&2
+ return 1
+ }
+
+ [ ! -w $file ] && {
+ echo "file $file not writable" >&2
+ return 1
+ }
+
+ validate_bootconfig_magic "$file"
+ [ $? -ne 0 ] && return 1
+
+ primaryboot=$(get_bootconfig_primaryboot "$1" "$2")
+
+ case "$primaryboot" in
+ 0)
+ _set_bootconfig_primaryboot "$1" "$2" 1
+ ;;
+ 1)
+ _set_bootconfig_primaryboot "$1" "$2" 0
+ ;;
+ *)
+ echo "invalid value: primaryboot must be 0 or 1" >&2
+ return 1
+ ;;
+ esac
+
+ [ $? -ne 0 ] && return 1
+
+ return 0
+}