[PATCH 1/1] drivers: add memory disk support

Heinrich Schuchardt heinrich.schuchardt at canonical.com
Tue Apr 19 23:16:41 CEST 2022


In some scenarios it is desirable to package U-Boot with other files into
a single blob. This patch allows to embed a memory disk into the U-Boot
binary. This memory disk can be accessed like any other block
device as 'mem 0'.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt at canonical.com>
---
 MAINTAINERS                      |   6 ++
 common/board_r.c                 |   4 +
 drivers/Kconfig                  |   2 +
 drivers/Makefile                 |   1 +
 drivers/block/blk-uclass.c       |   2 +
 drivers/memdisk/Kconfig          |  13 ++++
 drivers/memdisk/Makefile         |  11 +++
 drivers/memdisk/memdisk-uclass.c |  22 ++++++
 drivers/memdisk/memdisk.c        | 128 +++++++++++++++++++++++++++++++
 drivers/memdisk/memdisk_file.S   |  17 ++++
 include/asm-generic/sections.h   |   2 +
 include/blk.h                    |   1 +
 include/dm/uclass-id.h           |   1 +
 include/memdisk.h                |  28 +++++++
 14 files changed, 238 insertions(+)
 create mode 100644 drivers/memdisk/Kconfig
 create mode 100644 drivers/memdisk/Makefile
 create mode 100644 drivers/memdisk/memdisk-uclass.c
 create mode 100644 drivers/memdisk/memdisk.c
 create mode 100644 drivers/memdisk/memdisk_file.S
 create mode 100644 include/memdisk.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 34446127d4..be71f8d9b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -930,6 +930,12 @@ T:	git git://github.com/ARM-software/u-boot.git
 F:	drivers/video/mali_dp.c
 F:	drivers/i2c/i2c-versatile.c
 
+MEMDISK
+M:	Heinrich Schuchardt <xypron.glpk at gmx.de>
+S:	Supported
+F:	drivers/memdisk/
+F:	include/memdisk.h
+
 MICROBLAZE
 M:	Michal Simek <monstr at monstr.eu>
 S:	Maintained
diff --git a/common/board_r.c b/common/board_r.c
index 8dc87ed2be..f416dbd17e 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -37,6 +37,7 @@
 #include <irq_func.h>
 #include <malloc.h>
 #include <mapmem.h>
+#include <memdisk.h>
 #include <miiphy.h>
 #include <mmc.h>
 #include <mux.h>
@@ -700,6 +701,9 @@ static init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_CMD_ONENAND
 	initr_onenand,
 #endif
+#ifdef CONFIG_MEMDISK
+	initr_memdisk,
+#endif
 #ifdef CONFIG_MMC
 	initr_mmc,
 #endif
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b26ca8cf70..bf475c25e7 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -56,6 +56,8 @@ source "drivers/led/Kconfig"
 
 source "drivers/mailbox/Kconfig"
 
+source "drivers/memdisk/Kconfig"
+
 source "drivers/memory/Kconfig"
 
 source "drivers/misc/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4e7cf28440..3c2906b9c5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_TPL_)FIRMWARE) +=firmware/
 obj-$(CONFIG_$(SPL_TPL_)I2C) += i2c/
 obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/
 obj-$(CONFIG_$(SPL_TPL_)LED) += led/
+obj-$(CONFIG_$(SPL_TPL_)MEMDISK) += memdisk/
 obj-$(CONFIG_$(SPL_TPL_)MMC) += mmc/
 obj-y += mtd/
 obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux/
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index f1e4a85646..4beec38f71 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -23,6 +23,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
 	[IF_TYPE_ATAPI]		= "atapi",
 	[IF_TYPE_USB]		= "usb",
 	[IF_TYPE_DOC]		= "doc",
+	[IF_TYPE_MEMDISK]	= "mem",
 	[IF_TYPE_MMC]		= "mmc",
 	[IF_TYPE_SD]		= "sd",
 	[IF_TYPE_SATA]		= "sata",
@@ -40,6 +41,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
 	[IF_TYPE_ATAPI]		= UCLASS_INVALID,
 	[IF_TYPE_USB]		= UCLASS_MASS_STORAGE,
 	[IF_TYPE_DOC]		= UCLASS_INVALID,
+	[IF_TYPE_MEMDISK]	= UCLASS_MEMDISK,
 	[IF_TYPE_MMC]		= UCLASS_MMC,
 	[IF_TYPE_SD]		= UCLASS_INVALID,
 	[IF_TYPE_SATA]		= UCLASS_AHCI,
diff --git a/drivers/memdisk/Kconfig b/drivers/memdisk/Kconfig
new file mode 100644
index 0000000000..03f646539c
--- /dev/null
+++ b/drivers/memdisk/Kconfig
@@ -0,0 +1,13 @@
+config MEMDISK
+	bool "Support embedded memory disk"
+	select HAVE_BLOCK_DEVICE
+	help
+	 This option allows to embed a memory disk.
+
+config MEMDISK_FILE
+	string "Memory disk file"
+	depends on MEMDISK
+	default "memdisk.img"
+	help
+	 File to be embedded as memory disk.
+	 It can be accessed as block device 'mem 0'.
diff --git a/drivers/memdisk/Makefile b/drivers/memdisk/Makefile
new file mode 100644
index 0000000000..09d6de22d2
--- /dev/null
+++ b/drivers/memdisk/Makefile
@@ -0,0 +1,11 @@
+ifeq ($(CONFIG_MEMDISK),y)
+
+obj-y += \
+	memdisk.o \
+	memdisk-uclass.o \
+	memdisk_file.o
+
+MEMDISK_FILE := $(subst $\",,$(CONFIG_MEMDISK_FILE))
+$(obj)/memdisk_file.o: $(srctree)/$(MEMDISK_FILE)
+
+endif
diff --git a/drivers/memdisk/memdisk-uclass.c b/drivers/memdisk/memdisk-uclass.c
new file mode 100644
index 0000000000..b7b96f91a4
--- /dev/null
+++ b/drivers/memdisk/memdisk-uclass.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Embedded disk image
+ *
+ * Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk at gmx.de>
+ */
+
+#define LOG_CATEGORY UCLASS_MEMDISK
+
+#include <common.h>
+#include <dm.h>
+#include <memdisk.h>
+
+UCLASS_DRIVER(memdsk) = {
+	.id		= UCLASS_MEMDISK,
+	.name		= "memdsk",
+};
+
+U_BOOT_DRIVER(memdsk) = {
+	.name		= "memdsk",
+	.id		= UCLASS_MEMDISK,
+};
diff --git a/drivers/memdisk/memdisk.c b/drivers/memdisk/memdisk.c
new file mode 100644
index 0000000000..2c5521a3b6
--- /dev/null
+++ b/drivers/memdisk/memdisk.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Memory disk image
+ *
+ * Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk at gmx.de>
+ */
+
+#include <common.h>
+#include <blk.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <malloc.h>
+#include <memdisk.h>
+#include <asm/sections.h>
+
+#define LOG_BLK_SIZE 9
+#define BLK_SIZE (1 << LOG_BLK_SIZE)
+
+/**
+ * initr_memdisk() - Initialize embedded memory disk
+ */
+int initr_memdisk(void)
+{
+	memdisk_create(__memdisk_file_begin,
+		       __memdisk_file_end - __memdisk_file_begin);
+
+	return 0;
+}
+
+/**
+ * mem_bl_read() - read from block device
+ *
+ * @dev:	device
+ * @blknr:	first block to be read
+ * @blkcnt:	number of blocks to read
+ * @buffer:	output buffer
+ * Return:	number of blocks transferred
+ */
+static ulong mem_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+			 void *buffer)
+{
+	struct memdisk_plat *plat = dev_get_plat(dev);
+	char *start = plat->start;
+
+	if (blknr + blkcnt > ((lbaint_t)plat->size >> LOG_BLK_SIZE))
+		return 0;
+	start += blknr << LOG_BLK_SIZE;
+	memcpy(buffer, start, blkcnt << LOG_BLK_SIZE);
+
+	return blkcnt;
+}
+
+/**
+ * memdisk_create() - create memory disk
+ *
+ * The block device will be read-only.
+ * Write support will require security checks using lmb.
+ *
+ * @start:	start address
+ * @size	size
+ * Return:	0 on success
+ */
+int memdisk_create(void *start, size_t size)
+{
+	struct udevice *dev, *parent = NULL;
+	struct memdisk_plat *plat;
+	char dev_name[20], *strblk, *strdsk;
+	int devnum;
+	int ret;
+
+	devnum = blk_next_free_devnum(IF_TYPE_MEMDISK);
+	snprintf(dev_name, sizeof(dev_name), "memdsk%d", devnum);
+	strdsk = strdup(dev_name);
+	if (!strdsk)
+		return -ENOMEM;
+	/*
+	 * This dummy device is only needed due to the broken
+	 * blk_get_devnum_by_typename() function which looks at the
+	 * parent's uclass instead of the interface type. See
+	 * https://lore.kernel.org/all/20211023140647.7661-1-heinrich.schuchardt@canonical.com/
+	 */
+	ret = device_bind_driver(gd->dm_root, "memdsk", strdsk, &parent);
+	if (ret) {
+		free(strdsk);
+		return ret;
+	}
+
+	snprintf(dev_name, sizeof(dev_name), "memblk%d", devnum);
+	strblk = strdup(dev_name);
+	if (!strblk) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	ret = blk_create_device(parent, "memblk", strblk,
+				IF_TYPE_MEMDISK, -1, BLK_SIZE,
+				size / BLK_SIZE, &dev);
+	if (ret)
+		goto err;
+
+	plat = dev_get_plat(dev);
+	plat->start = start;
+	plat->size = size;
+
+	ret = blk_probe_or_unbind(dev);
+	if (!ret)
+		return 0;
+
+err:
+	if (parent)
+		device_remove(parent, DM_REMOVE_NORMAL);
+
+	return ret;
+}
+
+/* Block device driver operators */
+static const struct blk_ops mem_blk_ops = {
+	.read	= mem_bl_read,
+};
+
+/* Identify as block device driver */
+U_BOOT_DRIVER(memblk) = {
+	.name		= "memblk",
+	.id		= UCLASS_BLK,
+	.ops		= &mem_blk_ops,
+	.plat_auto	= sizeof(struct memdisk_plat),
+
+};
diff --git a/drivers/memdisk/memdisk_file.S b/drivers/memdisk/memdisk_file.S
new file mode 100644
index 0000000000..b535ea313e
--- /dev/null
+++ b/drivers/memdisk/memdisk_file.S
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Embedded disk image
+ *
+ * Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk at gmx.de>
+ */
+
+#include <config.h>
+
+.section .rodata.memdisk.init,"a"
+.balign 16
+.global __memdisk_file_begin
+__memdisk_file_begin:
+.incbin CONFIG_MEMDISK_FILE
+.global __memdisk_file_end
+__memdisk_file_end:
+.balign 16
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 267f1db73f..e3aa823870 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -27,6 +27,8 @@ extern char __efi_helloworld_begin[];
 extern char __efi_helloworld_end[];
 extern char __efi_var_file_begin[];
 extern char __efi_var_file_end[];
+extern char __memdisk_file_begin[];
+extern char __memdisk_file_end[];
 
 /* Private data used by of-platdata devices/uclasses */
 extern char __priv_data_start[], __priv_data_end[];
diff --git a/include/blk.h b/include/blk.h
index dbe9ae219d..c616ad2e29 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -29,6 +29,7 @@ enum if_type {
 	IF_TYPE_ATAPI,
 	IF_TYPE_USB,
 	IF_TYPE_DOC,
+	IF_TYPE_MEMDISK,
 	IF_TYPE_MMC,
 	IF_TYPE_SD,
 	IF_TYPE_SATA,
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0e26e1d138..7ef49ec829 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -69,6 +69,7 @@ enum uclass_id {
 	UCLASS_LED,		/* Light-emitting diode (LED) */
 	UCLASS_LPC,		/* x86 'low pin count' interface */
 	UCLASS_MAILBOX,		/* Mailbox controller */
+	UCLASS_MEMDISK,		/* Memory disk */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
 	UCLASS_MDIO,		/* MDIO bus */
 	UCLASS_MDIO_MUX,	/* MDIO MUX/switch */
diff --git a/include/memdisk.h b/include/memdisk.h
new file mode 100644
index 0000000000..a36ffa77d0
--- /dev/null
+++ b/include/memdisk.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Embedded disk image
+ *
+ * Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk at gmx.de>
+ */
+
+/**
+ * initr_memdisk() - Initialize embedded memory disk
+ */
+int initr_memdisk(void);
+
+/**
+ * memdisk_create() - create memory disk
+ *
+ * The block device will be read-only.
+ * Write support will require security checks using lmb.
+ *
+ * @start:	start address
+ * @size	size
+ * Return:	0 on success
+ */
+int memdisk_create(void *start, size_t size);
+
+struct memdisk_plat {
+	char *start;
+	size_t size;
+};
-- 
2.34.1



More information about the U-Boot mailing list