[openwrt/openwrt] kernel: ubootenv-nvram: driver for RAM backed environments

LEDE Commits lede-commits at lists.infradead.org
Sat Aug 19 16:16:18 PDT 2023


hauke pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/b2e810f49588d1bbc90f657826e94b32474b482c

commit b2e810f49588d1bbc90f657826e94b32474b482c
Author: Bjørn Mork <bjorn at mork.no>
AuthorDate: Tue Mar 28 13:32:29 2023 +0200

    kernel: ubootenv-nvram: driver for RAM backed environments
    
    The vendor U-Boot implementaion on Telenor branded ZyXEL EX5700
    devices does not store its environment on flash. It is instead
    kept in a memory region.  This is persistent over reboots, but
    not over power cycling.
    
    The dual partition failsafe system used by the vendor U-Boot
    requires the OS to modify a variable in this memory environment.
    This driver allows the ordinary uboot-envtools to access a
    memory region like it was a partition on NOR flash.
    
    The specific vendor U-Boot adds a "no-map" /reserved-memory
    section and a top level /ubootenv node pointing to the memory
    environment.  The driver uses this device specific fact to
    locate the region.  The matching and probing code will likely
    have to be adjusted for any other devices to be supported.
    
    Example partial device tree:
    
     / {
        ..
        ubootenv {
            memory-region = <&uenv>;
            compatible = "ubootenv";
        };
        ..
        reserved-memory {
            ..
            uenv: ubootenv at 7ffe8000 {
                no-map;
                reg = <0 0x7ffe8000 0 0x4000>;
            };
    
    Signed-off-by: Bjørn Mork <bjorn at mork.no>
---
 package/kernel/ubootenv-nvram/Makefile             |  30 ++++
 package/kernel/ubootenv-nvram/src/Makefile         |   1 +
 package/kernel/ubootenv-nvram/src/ubootenv-nvram.c | 158 +++++++++++++++++++++
 3 files changed, 189 insertions(+)

diff --git a/package/kernel/ubootenv-nvram/Makefile b/package/kernel/ubootenv-nvram/Makefile
new file mode 100644
index 0000000000..0574ea61d7
--- /dev/null
+++ b/package/kernel/ubootenv-nvram/Makefile
@@ -0,0 +1,30 @@
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=ubootenv-nvram
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/ubootenv-nvram
+  SUBMENU:=Other modules
+  TITLE:=NVRAM environment for uboot-envtools
+  FILES:=$(PKG_BUILD_DIR)/ubootenv-nvram.ko
+  AUTOLOAD:=$(call AutoLoad,30,ubootenv-nvram,1)
+  KCONFIG:=
+endef
+
+define KernelPackage/ubootenv-nvram/description
+  Support vendor modified U-Boot storing the environment
+  in RAM.  This driver exports the environment memory
+  region as a misc device named "ubootenv", pretending
+  it is a NOR mtd device to let existing userspace tools
+  work without modifications.
+endef
+
+define Build/Compile
+	$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
+endef
+
+$(eval $(call KernelPackage,ubootenv-nvram))
diff --git a/package/kernel/ubootenv-nvram/src/Makefile b/package/kernel/ubootenv-nvram/src/Makefile
new file mode 100644
index 0000000000..469cb801f3
--- /dev/null
+++ b/package/kernel/ubootenv-nvram/src/Makefile
@@ -0,0 +1 @@
+obj-m += ubootenv-nvram.o
diff --git a/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c b/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c
new file mode 100644
index 0000000000..f624414216
--- /dev/null
+++ b/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *   Copyright (C) 2022  Bjørn Mork <bjorn at mork.no>
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+
+#define NAME "ubootenv"
+
+struct ubootenv_drvdata {
+	void *env;
+	struct reserved_mem *rmem;
+	struct miscdevice misc;
+};
+
+static inline struct ubootenv_drvdata *to_ubootenv_drvdata(struct file *file)
+{
+	return container_of(file->private_data, struct ubootenv_drvdata, misc);
+}
+
+static ssize_t ubootenv_write(struct file *file, const char __user *buffer, size_t count,
+			      loff_t *ppos)
+{
+	struct ubootenv_drvdata *data = to_ubootenv_drvdata(file);
+
+	if (!data->env)
+		return -EIO;
+	return simple_write_to_buffer(data->env, data->rmem->size, ppos, buffer, count);
+}
+
+static ssize_t ubootenv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct ubootenv_drvdata *data = to_ubootenv_drvdata(file);
+
+	if (!data->env)
+		return 0;
+	return simple_read_from_buffer(buffer, count, ppos, data->env, data->rmem->size);
+}
+
+static loff_t ubootenv_llseek(struct file *file, loff_t off, int whence)
+{
+	struct ubootenv_drvdata *data = to_ubootenv_drvdata(file);
+
+	return fixed_size_llseek(file, off, whence, data->rmem->size);
+}
+
+/* Faking the minimal mtd ioctl subset required by the fw_env.c */
+static long ubootenv_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	struct ubootenv_drvdata *data = to_ubootenv_drvdata(file);
+	void __user *argp = (void __user *)arg;
+	struct mtd_info_user info = {
+		.type = MTD_NORFLASH,
+		.size = data->rmem->size,
+	};
+
+	switch (cmd) {
+	case MEMISLOCKED:
+	case MEMERASE:
+		break;
+	case MEMGETINFO:
+		if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
+			return -EFAULT;
+		break;
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static const struct file_operations ubootenv_fops = {
+	.owner          = THIS_MODULE,
+	.read           = ubootenv_read,
+	.write          = ubootenv_write,
+	.llseek         = ubootenv_llseek,
+	.unlocked_ioctl = ubootenv_ioctl,
+};
+
+/* We can only map a single reserved-memory range */
+static struct ubootenv_drvdata drvdata = {
+	.misc = {
+		.fops  = &ubootenv_fops,
+		.minor = MISC_DYNAMIC_MINOR,
+		.name  = NAME,
+	},
+};
+
+const struct of_device_id of_ubootenv_match[] = {
+	{ .compatible = "ubootenv" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_ubootenv_match);
+
+static int ubootenv_probe(struct platform_device *pdev)
+{
+	struct ubootenv_drvdata *data = &drvdata;
+	struct device *dev = &pdev->dev;
+	struct device_node *np;
+
+	/* enforce single instance */
+	if (data->env)
+		return -EINVAL;
+
+	np = of_parse_phandle(dev->of_node, "memory-region", 0);
+	if (!np)
+		return -ENODEV;
+
+	data->rmem = of_reserved_mem_lookup(np);
+	of_node_put(np);
+	if (!data->rmem)
+		return -ENODEV;
+
+	if (!data->rmem->size || (data->rmem->size > ULONG_MAX))
+		return -EINVAL;
+
+	if (!PAGE_ALIGNED(data->rmem->base) || !PAGE_ALIGNED(data->rmem->size))
+		return -EINVAL;
+
+	data->env = devm_memremap(&pdev->dev, data->rmem->base, data->rmem->size, MEMREMAP_WB);
+	platform_set_drvdata(pdev, data);
+
+	data->misc.parent = &pdev->dev;
+	return misc_register(&data->misc);
+}
+
+static int ubootenv_remove(struct platform_device *pdev)
+{
+	struct ubootenv_drvdata *data = platform_get_drvdata(pdev);
+
+	data->env = NULL;
+	misc_deregister(&data->misc);
+	return 0;
+}
+
+static struct platform_driver ubootenv_driver = {
+	.probe = ubootenv_probe,
+	.remove = ubootenv_remove,
+	.driver = {
+		.name           = NAME,
+		.owner          = THIS_MODULE,
+		.of_match_table = of_ubootenv_match,
+	},
+};
+
+module_platform_driver(ubootenv_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bjørn Mork <bjorn at mork.no>");
+MODULE_DESCRIPTION("Access u-boot environment in RAM");




More information about the lede-commits mailing list