diff --git a/package/system/mtd/src/Makefile b/package/system/mtd/src/Makefile index 08a9fb295da..e469e23ef7b 100644 --- a/package/system/mtd/src/Makefile +++ b/package/system/mtd/src/Makefile @@ -16,7 +16,7 @@ obj.ramips = $(obj.seama) $(obj.tpl) $(obj.wrg) obj.mvebu = linksys_bootcount.o obj.kirkwood = linksys_bootcount.o obj.ipq806x = linksys_bootcount.o -obj.ipq40xx = linksys_bootcount_fix.o +obj.ipq40xx = linksys_bootcount.o ifdef FIS_SUPPORT obj += fis.o diff --git a/package/system/mtd/src/linksys_bootcount.c b/package/system/mtd/src/linksys_bootcount.c index 500ede49727..bd06728696c 100644 --- a/package/system/mtd/src/linksys_bootcount.c +++ b/package/system/mtd/src/linksys_bootcount.c @@ -2,6 +2,7 @@ * Linksys boot counter reset code for mtd * * Copyright (C) 2013 Jonas Gorski + * Portions Copyright (c) 2019, Jeff Kletsky * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License v2 @@ -29,6 +30,7 @@ #include #include #include +#include #include #include @@ -37,6 +39,30 @@ #define BOOTCOUNT_MAGIC 0x20110811 +/* + * EA6350v3, and potentially other NOR-boot devices, + * use an offset increment of 16 between records, + * not mtd_info_user.writesize (often 1 on NOR devices). + */ + +#define BC_OFFSET_INCREMENT_MIN 16 + + + +#define DLOG_OPEN() + +#define DLOG_ERR(...) do { \ + fprintf(stderr, "ERROR: " __VA_ARGS__); fprintf(stderr, "\n"); \ + } while (0) + +#define DLOG_NOTICE(...) do { \ + fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); \ + } while (0) + +#define DLOG_DEBUG(...) + + + struct bootcounter { uint32_t magic; uint32_t count; @@ -50,25 +76,50 @@ int mtd_resetbc(const char *mtd) struct mtd_info_user mtd_info; struct bootcounter *curr = (struct bootcounter *)page; unsigned int i; + unsigned int bc_offset_increment; int last_count = 0; int num_bc; int fd; int ret; + int retval = 0; + + DLOG_OPEN(); fd = mtd_check_open(mtd); if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) { - fprintf(stderr, "failed to get mtd info!\n"); - return -1; + DLOG_ERR("Unable to obtain mtd_info for given partition name."); + + retval = -1; + goto out; } - num_bc = mtd_info.size / mtd_info.writesize; + + /* Detect need to override increment (for EA6350v3) */ + + if (mtd_info.writesize < BC_OFFSET_INCREMENT_MIN) { + + bc_offset_increment = BC_OFFSET_INCREMENT_MIN; + DLOG_DEBUG("Offset increment set to %i for writesize of %i", + bc_offset_increment, mtd_info.writesize); + } else { + + bc_offset_increment = mtd_info.writesize; + } + + num_bc = mtd_info.size / bc_offset_increment; for (i = 0; i < num_bc; i++) { - pread(fd, curr, sizeof(*curr), i * mtd_info.writesize); + pread(fd, curr, sizeof(*curr), i * bc_offset_increment); - if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) { - fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic); + /* Existing code assumes erase is to 0xff; left as-is (2019) */ + + if (curr->magic != BOOTCOUNT_MAGIC && + curr->magic != 0xffffffff) { + DLOG_ERR("Unexpected magic %08x at offset %08x; aborting.", + curr->magic, i * bc_offset_increment); + + retval = -2; goto out; } @@ -78,38 +129,59 @@ int mtd_resetbc(const char *mtd) last_count = curr->count; } - /* no need to do writes when last boot count is already 0 */ - if (last_count == 0) + + if (last_count == 0) { /* bootcount is already 0 */ + + retval = 0; goto out; + } if (i == num_bc) { + DLOG_NOTICE("Boot-count log full with %i entries; erasing (expected occasionally).", + i); + struct erase_info_user erase_info; erase_info.start = 0; erase_info.length = mtd_info.size; - /* erase block */ ret = ioctl(fd, MEMERASE, &erase_info); if (ret < 0) { - fprintf(stderr, "failed to erase block: %i\n", ret); - return -1; + DLOG_ERR("Failed to erase boot-count log MTD; ioctl() MEMERASE returned %i", + ret); + + retval = -3; + goto out; } i = 0; } - memset(curr, 0xff, mtd_info.writesize); + memset(curr, 0xff, bc_offset_increment); curr->magic = BOOTCOUNT_MAGIC; curr->count = 0; curr->checksum = BOOTCOUNT_MAGIC; - ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize); - if (ret < 0) - fprintf(stderr, "failed to write: %i\n", ret); - sync(); + /* Assumes bc_offset_increment is a multiple of mtd_info.writesize */ + + ret = pwrite(fd, curr, bc_offset_increment, i * bc_offset_increment); + if (ret < 0) { + DLOG_ERR("Failed to write boot-count log entry; pwrite() returned %i", + errno); + retval = -4; + goto out; + + } else { + sync(); + + DLOG_NOTICE("Boot count sucessfully reset to zero."); + + retval = 0; + goto out; + } + out: close(fd); - - return 0; + return retval; } diff --git a/package/system/mtd/src/linksys_bootcount_fix.c b/package/system/mtd/src/linksys_bootcount_fix.c deleted file mode 100644 index 3fc38012fb1..00000000000 --- a/package/system/mtd/src/linksys_bootcount_fix.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Linksys boot counter reset code for mtd - * - * Copyright (C) 2013 Jonas Gorski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License v2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "mtd.h" - -#define BOOTCOUNT_MAGIC 0x20110811 - -struct bootcounter { - uint32_t magic; - uint32_t count; - uint32_t checksum; -}; - -static char page[2048]; - -int mtd_resetbc(const char *mtd) -{ - struct mtd_info_user mtd_info; - struct bootcounter *curr = (struct bootcounter *)page; - unsigned int i; - int last_count = 0; - int num_bc; - int fd; - int ret; - - fd = mtd_check_open(mtd); - - if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) { - fprintf(stderr, "failed to get mtd info!\n"); - return -1; - } - - num_bc = mtd_info.size / 16; - - for (i = 0; i < num_bc; i++) { - pread(fd, curr, sizeof(*curr), i * 16); - - if (curr->magic != (BOOTCOUNT_MAGIC) && curr->magic != 0xffffffff) { - fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic); - goto out; - } - - if (curr->magic == 0xffffffff) - break; - - last_count = curr->count; - } - - /* no need to do writes when last boot count is already 0 */ - if (last_count == 0) - goto out; - - - if (i == num_bc) { - struct erase_info_user erase_info; - erase_info.start = 0; - erase_info.length = mtd_info.size; - - /* erase block */ - ret = ioctl(fd, MEMERASE, &erase_info); - if (ret < 0) { - fprintf(stderr, "failed to erase block: %i\n", ret); - return -1; - } - - i = 0; - } - - memset(curr, 0xff, 16); - - curr->magic = BOOTCOUNT_MAGIC; - curr->count = 0; - curr->checksum = BOOTCOUNT_MAGIC; - - ret = pwrite(fd, curr, 16, i * 16); - if (ret < 0) - fprintf(stderr, "failed to write: %i\n", ret); - sync(); -out: - close(fd); - - return 0; -} diff --git a/target/linux/ipq40xx/base-files/etc/init.d/bootcount b/target/linux/ipq40xx/base-files/etc/init.d/bootcount index 604f88c396d..abde12412a3 100755 --- a/target/linux/ipq40xx/base-files/etc/init.d/bootcount +++ b/target/linux/ipq40xx/base-files/etc/init.d/bootcount @@ -10,5 +10,8 @@ start() { [ -n "$(fw_printenv bootcount changed 2>/dev/null)" ] &&\ echo -e "bootcount\nchanged\n" | /usr/sbin/fw_setenv -s - ;; + linksys,ea6350v3) + mtd resetbc s_env || true + ;; esac } diff --git a/target/linux/ipq40xx/base-files/etc/init.d/zlinksys_recovery b/target/linux/ipq40xx/base-files/etc/init.d/zlinksys_recovery deleted file mode 100755 index ac6533e3fe3..00000000000 --- a/target/linux/ipq40xx/base-files/etc/init.d/zlinksys_recovery +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh /etc/rc.common -# -# This script sets auto_recovery to "yes" and resets the boot counter to 0. -# As a golden rule, this should be the latest script to run at boot. For a -# developer snapshot, it is fine to set auto_recovery here. But for a stable -# release, this script must in fact turn off auto_recovery. -# -# Why? Because the custom sysupgrade script for the device will turn on -# auto_recovery to "yes". And it's the job of this script to set the -# boot boot_count to 0 and then disable auto_recovery, as that condition -# means that the stable release went well. -# -# I have to repeat: this script should be changed for stable releases. - -START=99 -boot() { - . /lib/functions.sh - - case $(board_name) in - linksys,ea6350v3) - # make sure auto_recovery in uboot is always on - IS_AUTO_RECOVERY="$(fw_printenv -n auto_recovery)" - if [ "$IS_AUTO_RECOVERY" != "yes" ] ; then - fw_setenv auto_recovery yes - echo "Linksys EA6350v3: fw_setenv: auto_recovery has been set to yes" - fi - # reset the boot counter - fw_setenv boot_count 0 - mtd resetbc s_env - echo "Linksys EA6350v3: boot counter has been reset" - echo "Linksys EA6350v3: boot_part=$(fw_printenv -n boot_part)" - ;; - esac -} diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh b/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh index 9772d68f3d3..b8e6dd73524 100755 --- a/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh +++ b/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh @@ -1,26 +1,51 @@ linksys_get_target_firmware() { + + local cur_boot_part mtd_ubi0 + cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part) - target_firmware="" - if [ "$cur_boot_part" = "1" ]; then - # current primary boot - update alt boot - target_firmware="alt_kernel" - fw_setenv boot_part 2 - # In the Linksys EA6350v3, it is enough to set the boot_part as the boot command line is - # bootcmd=if test $boot_part = 1; then run bootpart1; else run bootpart2; fi - # - You probably want to use that if your device's uboot does not eval bootcmd - #fw_setenv bootcmd "run altnandboot" - elif [ "$cur_boot_part" = "2" ]; then - # current alt boot - update primary boot - target_firmware="kernel" - fw_setenv boot_part 1 - #fw_setenv bootcmd "run nandboot" + if [ -z "${cur_boot_part}" ] ; then + mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num) + case $(egrep "^mtd${mtd_ubi0}:" /proc/mtd | cut -d '"' -f 2) in + kernel|rootfs) + cur_boot_part=1 + ;; + alt_kernel|alt_rootfs) + cur_boot_part=2 + ;; + esac + >&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \ + "${cur_boot_part}" "${mtd_ubi0}" fi - # re-enable recovery so we get back if the new firmware is broken - fw_setenv auto_recovery yes - # see /etc/init.d/zlinksys_recovery + # OEM U-Boot for EA6350v3 and EA8300; bootcmd= + # if test $auto_recovery = no; + # then bootipq; + # elif test $boot_part = 1; + # then run bootpart1; + # else run bootpart2; + # fi - echo "$target_firmware" + case $cur_boot_part in + 1) + fw_setenv -s - <<-EOF + boot_part 2 + auto_recovery yes + EOF + printf "alt_kernel" + return + ;; + 2) + fw_setenv -s - <<-EOF + boot_part 1 + auto_recovery yes + EOF + printf "kernel" + return + ;; + *) + return + ;; + esac } linksys_get_root_magic() { diff --git a/target/linux/ipq806x/base-files/etc/init.d/bootcount b/target/linux/ipq806x/base-files/etc/init.d/bootcount new file mode 100755 index 00000000000..6a5a6d52add --- /dev/null +++ b/target/linux/ipq806x/base-files/etc/init.d/bootcount @@ -0,0 +1,13 @@ +#!/bin/sh /etc/rc.common + +START=99 + +start() { + . /lib/functions.sh + + case $(board_name) in + linksys,ea8500) + mtd resetbc s_env || true + ;; + esac +} diff --git a/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery b/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery deleted file mode 100755 index 6b4b38ec7bb..00000000000 --- a/target/linux/ipq806x/base-files/etc/init.d/linksys_recovery +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2015 OpenWrt.org - -START=97 -boot() { -. /lib/functions.sh - -case $(board_name) in - linksys,ea8500) - # make sure auto_recovery in uboot is always on - AUTO_RECOVERY_ENA="`fw_printenv -n auto_recovery`" - if [ "$AUTO_RECOVERY_ENA" != "yes" ] ; then - fw_setenv auto_recovery yes - fi - # reset the boot counter - mtd resetbc s_env - ;; -esac -} diff --git a/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh index 0234ce0a51a..2aa6e0f08c8 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh @@ -3,28 +3,47 @@ # linksys_get_target_firmware() { - cur_boot_part=`/usr/sbin/fw_printenv -n boot_part` - target_firmware="" - if [ "$cur_boot_part" = "1" ] - then - # current primary boot - update alt boot - target_firmware="kernel2" - fw_setenv boot_part 2 - #In EA8500 bootcmd is always "bootipq", so don't change - #fw_setenv bootcmd "run altnandboot" - elif [ "$cur_boot_part" = "2" ] - then - # current alt boot - update primary boot - target_firmware="kernel1" - fw_setenv boot_part 1 - #In EA8500 bootcmd is always "bootipq", so don't change - #fw_setenv bootcmd "run nandboot" + + local cur_boot_part mtd_ubi0 + + cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part) + if [ -z "${cur_boot_part}" ] ; then + mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num) + case $(egrep ^mtd${mtd_ubi0}: /proc/mtd | cut -d '"' -f 2) in + kernel1|rootfs1) + cur_boot_part=1 + ;; + kernel2|rootfs2) + cur_boot_part=2 + ;; + esac + >&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \ + "${cur_boot_part}" "${mtd_ubi0}" fi - # re-enable recovery so we get back if the new firmware is broken - fw_setenv auto_recovery yes + cur_boot_part=`/usr/sbin/fw_printenv -n boot_part` - echo "$target_firmware" + case $cur_boot_part in + 1) + fw_setenv -s - <<-EOF + boot_part 2 + auto_recovery yes + EOF + printf "kernel2" + return + ;; + 2) + fw_setenv -s - <<-EOF + boot_part 1 + auto_recovery yes + EOF + printf "kernel1" + return + ;; + *) + return + ;; + esac } linksys_get_root_magic() { diff --git a/target/linux/kirkwood/base-files/etc/init.d/bootcount b/target/linux/kirkwood/base-files/etc/init.d/bootcount new file mode 100755 index 00000000000..20fb3a425ca --- /dev/null +++ b/target/linux/kirkwood/base-files/etc/init.d/bootcount @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common + +START=99 + +start() { + . /lib/functions.sh + + case $(board_name) in + linksys,audi|\ + linksys,viper) + mtd resetbc s_env || true + ;; + esac +} diff --git a/target/linux/kirkwood/base-files/etc/init.d/linksys_recovery b/target/linux/kirkwood/base-files/etc/init.d/linksys_recovery deleted file mode 100755 index 8fd2f387abd..00000000000 --- a/target/linux/kirkwood/base-files/etc/init.d/linksys_recovery +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2015 OpenWrt.org - -START=97 -boot() { -. /lib/functions.sh - -case $(board_name) in - linksys,audi|linksys,viper) - # make sure auto_recovery in uboot is always on - AUTO_RECOVERY_ENA="`fw_printenv -n auto_recovery`" - if [ "$AUTO_RECOVERY_ENA" != "yes" ] ; then - fw_setenv auto_recovery yes - fi - # reset the boot counter - mtd resetbc s_env - ;; -esac -} diff --git a/target/linux/kirkwood/base-files/lib/upgrade/linksys.sh b/target/linux/kirkwood/base-files/lib/upgrade/linksys.sh index dde3bd1b219..b89aad3d7ed 100644 --- a/target/linux/kirkwood/base-files/lib/upgrade/linksys.sh +++ b/target/linux/kirkwood/base-files/lib/upgrade/linksys.sh @@ -3,23 +3,45 @@ # linksys_get_target_firmware() { - cur_boot_part=`/usr/sbin/fw_printenv -n boot_part` - target_firmware="" - if [ "$cur_boot_part" = "1" ] - then - # current primary boot - update alt boot - target_firmware="kernel2" - fw_setenv boot_part 2 - fw_setenv bootcmd "run altnandboot" - elif [ "$cur_boot_part" = "2" ] - then - # current alt boot - update primary boot - target_firmware="kernel1" - fw_setenv boot_part 1 - fw_setenv bootcmd "run nandboot" + + local cur_boot_part mtd_ubi0 + + cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part) + if [ -z "${cur_boot_part}" ] ; then + mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num) + case $(egrep ^mtd${mtd_ubi0}: /proc/mtd | cut -d '"' -f 2) in + kernel|rootfs) + cur_boot_part=1 + ;; + alt_kernel|alt_rootfs) + cur_boot_part=2 + ;; + esac + >&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \ + "${cur_boot_part}" "${mtd_ubi0}" fi - echo "$target_firmware" + case $cur_boot_part in + 1) + fw_setenv -s - <<-EOF + boot_part 2 + bootcmd "run altnandboot" + EOF + printf "kernel2" + return + ;; + 2) + fw_setenv -s - <<-EOF + boot_part 1 + bootcmd "run nandboot" + EOF + printf "kernel1" + return + ;; + *) + return + ;; + esac } linksys_get_root_magic() { diff --git a/target/linux/mvebu/base-files/etc/init.d/bootcount b/target/linux/mvebu/base-files/etc/init.d/bootcount new file mode 100755 index 00000000000..6e8e3108497 --- /dev/null +++ b/target/linux/mvebu/base-files/etc/init.d/bootcount @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common + +START=99 + +start() { + . /lib/functions.sh + + case $(board_name) in + linksys,caiman |\ + linksys,cobra |\ + linksys,mamba |\ + linksys,rango |\ + linksys,shelby |\ + linksys,venom) + mtd resetbc s_env || true + ;; + esac +} diff --git a/target/linux/mvebu/base-files/etc/init.d/linksys_recovery b/target/linux/mvebu/base-files/etc/init.d/linksys_recovery deleted file mode 100755 index b4f375ec993..00000000000 --- a/target/linux/mvebu/base-files/etc/init.d/linksys_recovery +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2015-2016 OpenWrt.org -# Copyright (C) 2016 LEDE-Project.org - -START=97 -boot() { -. /lib/functions.sh - -case $(board_name) in - linksys,caiman|linksys,cobra|linksys,mamba|linksys,rango|linksys,shelby|linksys,venom) - # make sure auto_recovery in uboot is always on - AUTO_RECOVERY_ENA="`fw_printenv -n auto_recovery`" - if [ "$AUTO_RECOVERY_ENA" != "yes" ] ; then - fw_setenv auto_recovery yes - fi - # reset the boot counter - mtd resetbc s_env - ;; -esac -} diff --git a/target/linux/mvebu/base-files/lib/upgrade/linksys.sh b/target/linux/mvebu/base-files/lib/upgrade/linksys.sh index aacaf55667e..3f45d6cac5e 100644 --- a/target/linux/mvebu/base-files/lib/upgrade/linksys.sh +++ b/target/linux/mvebu/base-files/lib/upgrade/linksys.sh @@ -3,26 +3,45 @@ # linksys_get_target_firmware() { + + local cur_boot_part mtd_ubi0 + cur_boot_part=`/usr/sbin/fw_printenv -n boot_part` - target_firmware="" - if [ "$cur_boot_part" = "1" ] - then - # current primary boot - update alt boot - target_firmware="kernel2" - fw_setenv boot_part 2 - fw_setenv bootcmd "run altnandboot" - elif [ "$cur_boot_part" = "2" ] - then - # current alt boot - update primary boot - target_firmware="kernel1" - fw_setenv boot_part 1 - fw_setenv bootcmd "run nandboot" + if [ -z "${cur_boot_part}" ] ; then + mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num) + case $(egrep ^mtd${mtd_ubi0}: /proc/mtd | cut -d '"' -f 2) in + kernel1|rootfs1) + cur_boot_part=1 + ;; + kernel2|rootfs2) + cur_boot_part=2 + ;; + esac + >&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \ + "${cur_boot_part}" "${mtd_ubi0}" fi - # re-enable recovery so we get back if the new firmware is broken - fw_setenv auto_recovery yes - - echo "$target_firmware" + case $cur_boot_part in + 1) + fw_setenv -s - <<-EOF + boot_part 2 + bootcmd "run altnandboot" + EOF + printf "kernel2" + return + ;; + 2) + fw_setenv -s - <<-EOF + boot_part 1 + bootcmd "run nandboot" + EOF + printf "kernel1" + return + ;; + *) + return + ;; + esac } linksys_get_root_magic() {