From c41e209ea67ee9be04519a3c7afda80a32253317 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 16 Feb 2023 16:33:49 +0100 Subject: blk: blkmap: Add basic infrastructure blkmaps are loosely modeled on Linux's device mapper subsystem. The basic idea is that you can create virtual block devices whose blocks can be backed by a plethora of sources that are user configurable. This change just adds the basic infrastructure for creating and removing blkmap devices. Subsequent changes will extend this to add support for actual mappings. Signed-off-by: Tobias Waldekranz Reviewed-by: Simon Glass --- include/blkmap.h | 35 +++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 2 files changed, 36 insertions(+) create mode 100644 include/blkmap.h (limited to 'include') diff --git a/include/blkmap.h b/include/blkmap.h new file mode 100644 index 00000000000..3c7e36efabc --- /dev/null +++ b/include/blkmap.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 Addiva Elektronik + * Author: Tobias Waldekranz + */ + +#ifndef _BLKMAP_H +#define _BLKMAP_H + +/** + * blkmap_from_label() - Find blkmap from label + * + * @label: Label of the requested blkmap + * Returns: A pointer to the blkmap on success, NULL on failure + */ +struct udevice *blkmap_from_label(const char *label); + +/** + * blkmap_create() - Create new blkmap + * + * @label: Label of the new blkmap + * @devp: If not NULL, updated with the address of the resulting device + * Returns: 0 on success, negative error code on failure + */ +int blkmap_create(const char *label, struct udevice **devp); + +/** + * blkmap_destroy() - Destroy blkmap + * + * @dev: The blkmap to be destroyed + * Returns: 0 on success, negative error code on failure + */ +int blkmap_destroy(struct udevice *dev); + +#endif /* _BLKMAP_H */ diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 33e43c20db6..576237b9548 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -37,6 +37,7 @@ enum uclass_id { UCLASS_AUDIO_CODEC, /* Audio codec with control and data path */ UCLASS_AXI, /* AXI bus */ UCLASS_BLK, /* Block device */ + UCLASS_BLKMAP, /* Composable virtual block device */ UCLASS_BOOTCOUNT, /* Bootcount backing store */ UCLASS_BOOTDEV, /* Boot device for locating an OS to boot */ UCLASS_BOOTMETH, /* Bootmethod for booting an OS */ -- cgit v1.3.1 From 15d9e99a274df5d9b260f75f42f7c394e5fe0e42 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 16 Feb 2023 16:33:50 +0100 Subject: blk: blkmap: Add memory mapping support Allow a slice of RAM to be mapped to a blkmap. This means that RAM can now be accessed as if it was a block device, meaning that existing filesystem drivers can now be used to access ramdisks. Signed-off-by: Tobias Waldekranz Reviewed-by: Simon Glass --- drivers/block/blkmap.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ include/blkmap.h | 29 ++++++++++++++ 2 files changed, 134 insertions(+) (limited to 'include') diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c index acfc002ceba..6d6eed889e3 100644 --- a/drivers/block/blkmap.c +++ b/drivers/block/blkmap.c @@ -130,6 +130,111 @@ static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new) return 0; } +/** + * struct blkmap_mem - Memory mapping + * + * @slice: Common map data + * @addr: Target memory region of this mapping + * @remapped: True if @addr is backed by a physical to virtual memory + * mapping that must be torn down at the end of this mapping's + * lifetime. + */ +struct blkmap_mem { + struct blkmap_slice slice; + void *addr; + bool remapped; +}; + +static ulong blkmap_mem_read(struct blkmap *bm, struct blkmap_slice *bms, + lbaint_t blknr, lbaint_t blkcnt, void *buffer) +{ + struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice); + struct blk_desc *bd = dev_get_uclass_plat(bm->blk); + char *src; + + src = bmm->addr + (blknr << bd->log2blksz); + memcpy(buffer, src, blkcnt << bd->log2blksz); + return blkcnt; +} + +static ulong blkmap_mem_write(struct blkmap *bm, struct blkmap_slice *bms, + lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice); + struct blk_desc *bd = dev_get_uclass_plat(bm->blk); + char *dst; + + dst = bmm->addr + (blknr << bd->log2blksz); + memcpy(dst, buffer, blkcnt << bd->log2blksz); + return blkcnt; +} + +static void blkmap_mem_destroy(struct blkmap *bm, struct blkmap_slice *bms) +{ + struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice); + + if (bmm->remapped) + unmap_sysmem(bmm->addr); +} + +int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *addr, bool remapped) +{ + struct blkmap *bm = dev_get_plat(dev); + struct blkmap_mem *bmm; + int err; + + bmm = malloc(sizeof(*bmm)); + if (!bmm) + return -ENOMEM; + + *bmm = (struct blkmap_mem) { + .slice = { + .blknr = blknr, + .blkcnt = blkcnt, + + .read = blkmap_mem_read, + .write = blkmap_mem_write, + .destroy = blkmap_mem_destroy, + }, + + .addr = addr, + .remapped = remapped, + }; + + err = blkmap_slice_add(bm, &bmm->slice); + if (err) + free(bmm); + + return err; +} + +int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *addr) +{ + return __blkmap_map_mem(dev, blknr, blkcnt, addr, false); +} + +int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + phys_addr_t paddr) +{ + struct blkmap *bm = dev_get_plat(dev); + struct blk_desc *bd = dev_get_uclass_plat(bm->blk); + void *addr; + int err; + + addr = map_sysmem(paddr, blkcnt << bd->log2blksz); + if (!addr) + return -ENOMEM; + + err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true); + if (err) + unmap_sysmem(addr); + + return err; +} + static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms, lbaint_t blknr, lbaint_t blkcnt, void *buffer) diff --git a/include/blkmap.h b/include/blkmap.h index 3c7e36efabc..74baeb19f81 100644 --- a/include/blkmap.h +++ b/include/blkmap.h @@ -7,6 +7,35 @@ #ifndef _BLKMAP_H #define _BLKMAP_H +/** + * blkmap_map_mem() - Map region of memory + * + * @dev: Blkmap to create the mapping on + * @blknr: Start block number of the mapping + * @blkcnt: Number of blocks to map + * @addr: The target memory address of the mapping + * Returns: 0 on success, negative error code on failure + */ +int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *addr); + +/** + * blkmap_map_pmem() - Map region of physical memory + * + * Ensures that a valid physical to virtual memory mapping for the + * requested region is valid for the lifetime of the mapping, on + * architectures that require it (sandbox). + * + * @dev: Blkmap to create the mapping on + * @blknr: Start block number of the mapping + * @blkcnt: Number of blocks to map + * @paddr: The target physical memory address of the mapping + * Returns: 0 on success, negative error code on failure + */ +int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + phys_addr_t paddr); + + /** * blkmap_from_label() - Find blkmap from label * -- cgit v1.3.1 From 762dc78bdea3468e8cd35c01f91def13974948f1 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 16 Feb 2023 16:33:51 +0100 Subject: blk: blkmap: Add linear device mapping support Allow a slice of an existing block device to be mapped to a blkmap. This means that filesystems that are not stored at exact partition boundaries can be accessed by remapping a slice of the existing device to a blkmap device. Signed-off-by: Tobias Waldekranz Reviewed-by: Simon Glass --- drivers/block/blkmap.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/blkmap.h | 13 +++++++++ 2 files changed, 84 insertions(+) (limited to 'include') diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c index 6d6eed889e3..2bb0acc20f2 100644 --- a/drivers/block/blkmap.c +++ b/drivers/block/blkmap.c @@ -130,6 +130,77 @@ static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new) return 0; } +/** + * struct blkmap_linear - Linear mapping to other block device + * + * @slice: Common map data + * @blk: Target block device of this mapping + * @blknr: Start block number of the target device + */ +struct blkmap_linear { + struct blkmap_slice slice; + + struct udevice *blk; + lbaint_t blknr; +}; + +static ulong blkmap_linear_read(struct blkmap *bm, struct blkmap_slice *bms, + lbaint_t blknr, lbaint_t blkcnt, void *buffer) +{ + struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice); + + return blk_read(bml->blk, bml->blknr + blknr, blkcnt, buffer); +} + +static ulong blkmap_linear_write(struct blkmap *bm, struct blkmap_slice *bms, + lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice); + + return blk_write(bml->blk, bml->blknr + blknr, blkcnt, buffer); +} + +int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + struct udevice *lblk, lbaint_t lblknr) +{ + struct blkmap *bm = dev_get_plat(dev); + struct blkmap_linear *linear; + struct blk_desc *bd, *lbd; + int err; + + bd = dev_get_uclass_plat(bm->blk); + lbd = dev_get_uclass_plat(lblk); + if (lbd->blksz != bd->blksz) + /* We could support block size translation, but we + * don't yet. + */ + return -EINVAL; + + linear = malloc(sizeof(*linear)); + if (!linear) + return -ENOMEM; + + *linear = (struct blkmap_linear) { + .slice = { + .blknr = blknr, + .blkcnt = blkcnt, + + .read = blkmap_linear_read, + .write = blkmap_linear_write, + }, + + .blk = lblk, + .blknr = lblknr, + }; + + err = blkmap_slice_add(bm, &linear->slice); + if (err) + free(linear); + + return err; +} + /** * struct blkmap_mem - Memory mapping * diff --git a/include/blkmap.h b/include/blkmap.h index 74baeb19f81..af54583c7dd 100644 --- a/include/blkmap.h +++ b/include/blkmap.h @@ -7,6 +7,19 @@ #ifndef _BLKMAP_H #define _BLKMAP_H +/** + * blkmap_map_linear() - Map region of other block device + * + * @dev: Blkmap to create the mapping on + * @blknr: Start block number of the mapping + * @blkcnt: Number of blocks to map + * @lblk: The target block device of the mapping + * @lblknr: The start block number of the target device + * Returns: 0 on success, negative error code on failure + */ +int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + struct udevice *lblk, lbaint_t lblknr); + /** * blkmap_map_mem() - Map region of memory * -- cgit v1.3.1 From 272ec6b453049beaf0de6654dabf9bbd5f617022 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 16 Feb 2023 16:33:55 +0100 Subject: efi_loader: device_path: support blkmap devices Create a distinct EFI device path for each blkmap device. Signed-off-by: Tobias Waldekranz Reviewed-by: Simon Glass --- include/efi_loader.h | 4 ++++ lib/efi_loader/efi_device_path.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index cee04cbb9dc..4b89b9816d4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -134,6 +134,10 @@ static inline efi_status_t efi_launch_capsules(void) #define U_BOOT_GUID \ EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) +/* GUID used as root for blkmap devices */ +#define U_BOOT_BLKMAP_DEV_GUID \ + EFI_GUID(0x4cad859d, 0xd644, 0x42ff, \ + 0x87, 0x0b, 0xc0, 0x2e, 0xac, 0x05, 0x58, 0x63) /* GUID used as host device on sandbox */ #define U_BOOT_HOST_DEV_GUID \ EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \ diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index ea097839dbe..e2e98a39be1 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -21,6 +21,9 @@ #include #include /* U16_MAX */ +#ifdef CONFIG_BLKMAP +const efi_guid_t efi_guid_blkmap_dev = U_BOOT_BLKMAP_DEV_GUID; +#endif #ifdef CONFIG_SANDBOX const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID; #endif @@ -555,6 +558,16 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) */ return dp_size(dev->parent) + sizeof(struct efi_device_path_vendor) + 1; +#endif +#ifdef CONFIG_BLKMAP + case UCLASS_BLKMAP: + /* + * blkmap devices will be represented as a vendor + * device node with an extra byte for the device + * number. + */ + return dp_size(dev->parent) + + sizeof(struct efi_device_path_vendor) + 1; #endif default: return dp_size(dev->parent); @@ -613,6 +626,23 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) #endif case UCLASS_BLK: switch (dev->parent->uclass->uc_drv->id) { +#ifdef CONFIG_BLKMAP + case UCLASS_BLKMAP: { + struct efi_device_path_vendor *dp; + struct blk_desc *desc = dev_get_uclass_plat(dev); + + dp_fill(buf, dev->parent); + dp = buf; + ++dp; + dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + dp->dp.length = sizeof(*dp) + 1; + memcpy(&dp->guid, &efi_guid_blkmap_dev, + sizeof(efi_guid_t)); + dp->vendor_data[0] = desc->devnum; + return &dp->vendor_data[1]; + } +#endif #ifdef CONFIG_SANDBOX case UCLASS_HOST: { /* stop traversing parents at this point: */ -- cgit v1.3.1