
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@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@gmx.de +S: Supported +F: drivers/memdisk/ +F: include/memdisk.h + MICROBLAZE M: Michal Simek monstr@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@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@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@canoni... + */ + 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@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@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; +};