[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