From: Denis Mukhin <[email protected]> 

Introduce bootcount device backed by GPT PTE attributes (bits 48:63).

Signed-off-by: Denis Mukhin <[email protected]>
---
 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

Reply via email to