[PATCH v1 6/8] bootcount: gpt: introduce GPT-backed bootcount device
dmukhin at ford.com
dmukhin at ford.com
Fri Jun 5 05:39:05 CEST 2026
From: Denis Mukhin <dmukhin at ford.com>
Introduce bootcount device backed by GPT PTE attributes (bits 48:63).
Signed-off-by: Denis Mukhin <dmukhin at ford.com>
---
drivers/bootcount/Kconfig | 7 ++
drivers/bootcount/Makefile | 1 +
drivers/bootcount/bootcount-gpt.c | 140 ++++++++++++++++++++++++++++++
3 files changed, 148 insertions(+)
create mode 100644 drivers/bootcount/bootcount-gpt.c
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 4c0c8d89bb40..eccd610e3390 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -171,6 +171,13 @@ config DM_BOOTCOUNT_ZYNQMP
Enable support for the bootcount API by utilising the Persistent
Global General Storage Register 2 of the PMU.
+config DM_BOOTCOUNT_GPT
+ bool "Support GPT PTE-backed boot counter"
+ depends on EFI_PARTITION
+ help
+ Add support for maintaining boot count within bits 48:63 of GUID
+ partition table entry attributes (similarly to ChromiumOS).
+
endmenu
endif
diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
index 0cf79e428d68..927694979801 100644
--- a/drivers/bootcount/Makefile
+++ b/drivers/bootcount/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_DM_BOOTCOUNT_I2C) += bootcount_dm_i2c.o
obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH) += spi-flash.o
obj-$(CONFIG_DM_BOOTCOUNT_SYSCON) += bootcount_syscon.o
obj-$(CONFIG_DM_BOOTCOUNT_ZYNQMP) += bootcount_zynqmp.o
+obj-$(CONFIG_DM_BOOTCOUNT_GPT) += bootcount-gpt.o
diff --git a/drivers/bootcount/bootcount-gpt.c b/drivers/bootcount/bootcount-gpt.c
new file mode 100644
index 000000000000..d2bbff2ba120
--- /dev/null
+++ b/drivers/bootcount/bootcount-gpt.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#define pr_fmt(fmt) "bootcount-gpt: " fmt
+#define LOG_CATEGORY UCLASS_BOOTCOUNT
+
+#include <blk.h>
+#include <bootcount.h>
+#include <dm.h>
+#include <linux/printk.h>
+#include <part.h>
+
+struct bootcount_gpt_priv {
+ struct blk_desc *blk_desc;
+ const char *partition_name;
+ int uclass_id;
+ int devnum;
+ int partnum;
+};
+
+static int bootcount_gpt_find(struct udevice *dev)
+{
+ struct bootcount_gpt_priv *priv = dev_get_priv(dev);
+ struct udevice *bdev;
+ struct disk_partition info;
+ int partnum, rc;
+
+ rc = blk_get_device(priv->uclass_id, priv->devnum, &bdev);
+ if (rc < 0)
+ return -ENODEV;
+
+ partnum = part_get_info_by_name(dev_get_uclass_plat(bdev),
+ priv->partition_name, &info);
+ if (partnum < 0)
+ return -ENODEV;
+
+ if (info.bootable & PART_BOOTABLE) {
+ pr_warn("partition %s: legacy boot flag enabled, no GPT accounting\n",
+ priv->partition_name);
+ return -EPERM;
+ }
+
+ priv->blk_desc = dev_get_uclass_plat(bdev);
+ priv->partnum = partnum;
+
+ return 0;
+}
+
+static int bootcount_gpt_get(struct udevice *dev, u32 *val)
+{
+ struct bootcount_gpt_priv *priv = dev_get_priv(dev);
+ int rc;
+
+ if (!priv->blk_desc) {
+ rc = bootcount_gpt_find(dev);
+ if (rc < 0)
+ return rc;
+ }
+
+ rc = read_disk_flags(priv->blk_desc, priv->partnum, (u16 *)val);
+ if (rc < 0) {
+ pr_err("partnum %d: failed to read GPT flags: %d\n",
+ priv->partnum, rc);
+ return rc;
+ }
+
+ pr_debug("partnum %d: read GPT flags 0x%04x\n", priv->partnum, *val);
+
+ return 0;
+}
+
+static int bootcount_gpt_set(struct udevice *dev, const u32 val)
+{
+ struct bootcount_gpt_priv *priv = dev_get_priv(dev);
+ int rc;
+
+ if (!priv->blk_desc) {
+ rc = bootcount_gpt_find(dev);
+ if (rc < 0)
+ return rc;
+ }
+
+ pr_debug("partnum %d: write GPT flags 0x%04x\n", priv->partnum, val);
+
+ rc = write_disk_flags(priv->blk_desc, priv->partnum, (u16)val);
+ if (rc < 0) {
+ pr_err("partnum %d: failed to write GPT flags: %d\n",
+ priv->partnum, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int bootcount_gpt_probe(struct udevice *dev)
+{
+ struct bootcount_gpt_priv *priv = dev_get_priv(dev);
+ const char *str;
+ int uclass_id, devnum;
+
+ str = dev_read_string(dev, "device-type");
+ if (!str)
+ return -ENOSYS;
+
+ uclass_id = uclass_get_by_name(str);
+ if (uclass_id == UCLASS_INVALID)
+ return -ENOSYS;
+
+ devnum = dev_read_s32_default(dev, "devnum", 0);
+ if (devnum < 0)
+ return -ENOSYS;
+
+ str = dev_read_string(dev, "partition-name");
+ if (!str)
+ return -ENOSYS;
+
+ priv->uclass_id = uclass_id;
+ priv->devnum = devnum;
+ priv->partition_name = str;
+
+ return 0;
+}
+
+static const struct bootcount_ops bootcount_gpt_ops = {
+ .get = bootcount_gpt_get,
+ .set = bootcount_gpt_set,
+};
+
+static const struct udevice_id bootcount_gpt_ids[] = {
+ { .compatible = "u-boot,bootcount-gpt" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_gpt) = {
+ .name = "bootcount-gpt",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_gpt_priv),
+ .probe = bootcount_gpt_probe,
+ .of_match = bootcount_gpt_ids,
+ .ops = &bootcount_gpt_ops,
+};
--
2.54.0
More information about the U-Boot
mailing list