bootcount_ext: Add flag to enable/disable bootcount

After a successful upgrade, multiple problem during boot sequence may
trigger the altbootcmd process.
This patch adds a version and an upgrade_available entries to the
bootcount file to enable/disable the bootcount check.
When failing to read the bootcount file it will consider that bootcount is
enabled, acting as previously, and update the file accordingly.

The bootcount file is only saved when `upgrade_available` is true, this
allows to save writes to the filesystem.

Signed-off-by: Frédéric Danis <frederic.danis@collabora.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Frédéric Danis 2020-03-17 17:59:09 +01:00 committed by Tom Rini
parent 080019b86c
commit df928f8549
2 changed files with 85 additions and 12 deletions

51
doc/README.bootcount Normal file
View file

@ -0,0 +1,51 @@
.. SPDX-License-Identifier: GPL-2.0+
Boot Count Limit
================
This allows to detect multiple failed attempts to boot Linux.
After a power-on reset, "bootcount" variable will be initialized with 1, and
each reboot will increment the value by 1.
If, after a reboot, the new value of "bootcount" exceeds the value of
"bootlimit", then instead of the standard boot action (executing the contents of
"bootcmd") an alternate boot action will be performed, and the contents of
"altbootcmd" will be executed.
If the variable "bootlimit" is not defined in the environment, the Boot Count
Limit feature is disabled. If it is enabled, but "altbootcmd" is not defined,
then U-Boot will drop into interactive mode and remain there.
It is the responsibility of some application code (typically a Linux
application) to reset the variable "bootcount", thus allowing for more boot
cycles.
BOOTCOUNT_EXT
-------------
This adds support for maintaining boot count in a file on an EXT filesystem.
The file to use is define by:
SYS_BOOTCOUNT_EXT_INTERFACE
SYS_BOOTCOUNT_EXT_DEVPART
SYS_BOOTCOUNT_EXT_NAME
The format of the file is:
==== =================
type entry
==== =================
u8 magic
u8 version
u8 bootcount
u8 upgrade_available
==== =================
To prevent unattended usage of "altbootcmd" the "upgrade_available" variable is
used.
If "upgrade_available" is 0, "bootcount" is not saved, if "upgrade_available" is
1 "bootcount" is save.
So the Userspace Application must set the "upgrade_available" and "bootcount"
variables to 0, if a boot was successfully.
This also prevents writes on all reboots.

View file

@ -7,11 +7,21 @@
#include <fs.h>
#include <mapmem.h>
#define BC_MAGIC 0xbc
#define BC_MAGIC 0xbd
#define BC_VERSION 1
typedef struct {
u8 magic;
u8 version;
u8 bootcount;
u8 upgrade_available;
} bootcount_ext_t;
static u8 upgrade_available = 1;
void bootcount_store(ulong a)
{
u8 *buf;
bootcount_ext_t *buf;
loff_t len;
int ret;
@ -21,20 +31,27 @@ void bootcount_store(ulong a)
return;
}
buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, 2);
buf[0] = BC_MAGIC;
buf[1] = (a & 0xff);
/* Only update bootcount during upgrade process */
if (!upgrade_available)
return;
buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, sizeof(bootcount_ext_t));
buf->magic = BC_MAGIC;
buf->version = BC_VERSION;
buf->bootcount = (a & 0xff);
buf->upgrade_available = upgrade_available;
unmap_sysmem(buf);
ret = fs_write(CONFIG_SYS_BOOTCOUNT_EXT_NAME,
CONFIG_SYS_BOOTCOUNT_ADDR, 0, 2, &len);
CONFIG_SYS_BOOTCOUNT_ADDR, 0, sizeof(bootcount_ext_t),
&len);
if (ret != 0)
puts("Error storing bootcount\n");
}
ulong bootcount_load(void)
{
u8 *buf;
bootcount_ext_t *buf;
loff_t len_read;
int ret;
@ -45,15 +62,20 @@ ulong bootcount_load(void)
}
ret = fs_read(CONFIG_SYS_BOOTCOUNT_EXT_NAME, CONFIG_SYS_BOOTCOUNT_ADDR,
0, 2, &len_read);
if (ret != 0 || len_read != 2) {
0, sizeof(bootcount_ext_t), &len_read);
if (ret != 0 || len_read != sizeof(bootcount_ext_t)) {
puts("Error loading bootcount\n");
return 0;
}
buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, 2);
if (buf[0] == BC_MAGIC)
ret = buf[1];
buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, sizeof(bootcount_ext_t));
if (buf->magic == BC_MAGIC && buf->version == BC_VERSION) {
upgrade_available = buf->upgrade_available;
if (upgrade_available)
ret = buf->bootcount;
} else {
puts("Incorrect bootcount file\n");
}
unmap_sysmem(buf);