From d4432b72ddbed27af1edf77e6705d7210df289cf Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 21 Feb 2023 14:06:58 +0100 Subject: [PATCH] common: uboot: Add missing blkmap patches The blkmap patches were not included in the original U-Boot Secure Boot changeset. Fixes: d243c80 ("aarch64: Convenience target to configure a QEMU compatible U-Boot") --- ...-execution-from-FIT-images-with-exte.patch | 32 ++ ...neric-read-write-operations-to-work-.patch | 73 +++ ...-blk-blkmap-Add-basic-infrastructure.patch | 501 ++++++++++++++++++ ...lk-blkmap-Add-memory-mapping-support.patch | 174 ++++++ ...ap-Add-linear-device-mapping-support.patch | 125 +++++ .../0006-cmd-blkmap-Add-blkmap-command.patch | 337 ++++++++++++ .../0007-test-blkmap-Add-test-suite.patch | 266 ++++++++++ ...blkmap-Add-introduction-and-examples.patch | 159 ++++++ ...r-device_path-support-blkmap-devices.patch | 86 +++ 9 files changed, 1753 insertions(+) create mode 100644 board/common/uboot/patches/0001-image-Fix-script-execution-from-FIT-images-with-exte.patch create mode 100644 board/common/uboot/patches/0002-cmd-blk-Allow-generic-read-write-operations-to-work-.patch create mode 100644 board/common/uboot/patches/0003-blk-blkmap-Add-basic-infrastructure.patch create mode 100644 board/common/uboot/patches/0004-blk-blkmap-Add-memory-mapping-support.patch create mode 100644 board/common/uboot/patches/0005-blk-blkmap-Add-linear-device-mapping-support.patch create mode 100644 board/common/uboot/patches/0006-cmd-blkmap-Add-blkmap-command.patch create mode 100644 board/common/uboot/patches/0007-test-blkmap-Add-test-suite.patch create mode 100644 board/common/uboot/patches/0008-doc-blkmap-Add-introduction-and-examples.patch create mode 100644 board/common/uboot/patches/0009-efi_loader-device_path-support-blkmap-devices.patch diff --git a/board/common/uboot/patches/0001-image-Fix-script-execution-from-FIT-images-with-exte.patch b/board/common/uboot/patches/0001-image-Fix-script-execution-from-FIT-images-with-exte.patch new file mode 100644 index 00000000..3582e13b --- /dev/null +++ b/board/common/uboot/patches/0001-image-Fix-script-execution-from-FIT-images-with-exte.patch @@ -0,0 +1,32 @@ +From 4aef55d1b8cc24187f12f83a2f4d9bfc41ba12ee Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Mon, 30 Jan 2023 15:54:56 +0100 +Subject: [PATCH v2 1/9] image: Fix script execution from FIT images with + external data + +Update the script loading code to recognize when script data is stored +externally from the FIT metadata (i.e., built with `mkimage -E`). + +Signed-off-by: Tobias Waldekranz +Reviewed-by: Simon Glass +--- + boot/image-board.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/boot/image-board.c b/boot/image-board.c +index 25b60ec30b..af693c9c08 100644 +--- a/boot/image-board.c ++++ b/boot/image-board.c +@@ -1111,7 +1111,8 @@ fallback: + } + + /* get script subimage data address and length */ +- if (fit_image_get_data(fit_hdr, noffset, &fit_data, &fit_len)) { ++ if (fit_image_get_data_and_size(fit_hdr, noffset, ++ &fit_data, &fit_len)) { + puts("Could not find script subimage data\n"); + return 1; + } +-- +2.34.1 + diff --git a/board/common/uboot/patches/0002-cmd-blk-Allow-generic-read-write-operations-to-work-.patch b/board/common/uboot/patches/0002-cmd-blk-Allow-generic-read-write-operations-to-work-.patch new file mode 100644 index 00000000..a21291ba --- /dev/null +++ b/board/common/uboot/patches/0002-cmd-blk-Allow-generic-read-write-operations-to-work-.patch @@ -0,0 +1,73 @@ +From 74f121de98a1614a4068960445b8355cb3e5fa04 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Tue, 24 Jan 2023 14:00:04 +0100 +Subject: [PATCH v2 2/9] cmd: blk: Allow generic read/write operations to work + in sandbox + +Ensure that the memory destination/source addresses of block +read/write operations are mapped in before access. Currently, this is +only needed on sandbox builds. + +Signed-off-by: Tobias Waldekranz +Reviewed-by: Simon Glass +--- + cmd/blk_common.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/cmd/blk_common.c b/cmd/blk_common.c +index 75a072caf5..9f9d4327a9 100644 +--- a/cmd/blk_common.c ++++ b/cmd/blk_common.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id, + int *cur_devnump) +@@ -63,31 +64,37 @@ int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id, + + default: /* at least 4 args */ + if (strcmp(argv[1], "read") == 0) { +- ulong addr = hextoul(argv[2], NULL); ++ phys_addr_t paddr = hextoul(argv[2], NULL); + lbaint_t blk = hextoul(argv[3], NULL); + ulong cnt = hextoul(argv[4], NULL); ++ void *vaddr; + ulong n; + + printf("\n%s read: device %d block # "LBAFU", count %lu ... ", + if_name, *cur_devnump, blk, cnt); + ++ vaddr = map_sysmem(paddr, 512 * cnt); + n = blk_read_devnum(uclass_id, *cur_devnump, blk, cnt, +- (ulong *)addr); ++ vaddr); ++ unmap_sysmem(vaddr); + + printf("%ld blocks read: %s\n", n, + n == cnt ? "OK" : "ERROR"); + return n == cnt ? 0 : 1; + } else if (strcmp(argv[1], "write") == 0) { +- ulong addr = hextoul(argv[2], NULL); ++ phys_addr_t paddr = hextoul(argv[2], NULL); + lbaint_t blk = hextoul(argv[3], NULL); + ulong cnt = hextoul(argv[4], NULL); ++ void *vaddr; + ulong n; + + printf("\n%s write: device %d block # "LBAFU", count %lu ... ", + if_name, *cur_devnump, blk, cnt); + ++ vaddr = map_sysmem(paddr, 512 * cnt); + n = blk_write_devnum(uclass_id, *cur_devnump, blk, cnt, +- (ulong *)addr); ++ vaddr); ++ unmap_sysmem(vaddr); + + printf("%ld blocks written: %s\n", n, + n == cnt ? "OK" : "ERROR"); +-- +2.34.1 + diff --git a/board/common/uboot/patches/0003-blk-blkmap-Add-basic-infrastructure.patch b/board/common/uboot/patches/0003-blk-blkmap-Add-basic-infrastructure.patch new file mode 100644 index 00000000..ac96f621 --- /dev/null +++ b/board/common/uboot/patches/0003-blk-blkmap-Add-basic-infrastructure.patch @@ -0,0 +1,501 @@ +From 104a2ab39ac72c402d7463bec05aae4a6d09cfbf Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Feb 2023 15:06:12 +0100 +Subject: [PATCH v2 3/9] 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 +--- + MAINTAINERS | 6 + + drivers/block/Kconfig | 18 ++ + drivers/block/Makefile | 1 + + drivers/block/blk-uclass.c | 1 + + drivers/block/blkmap.c | 343 +++++++++++++++++++++++++++++++++++++ + include/blkmap.h | 35 ++++ + include/dm/uclass-id.h | 1 + + 7 files changed, 405 insertions(+) + create mode 100644 drivers/block/blkmap.c + create mode 100644 include/blkmap.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 6f53f9c2f6..3e47c9b34c 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -793,6 +793,12 @@ M: Alper Nebi Yasak + S: Maintained + F: tools/binman/ + ++BLKMAP ++M: Tobias Waldekranz ++S: Maintained ++F: drivers/block/blkmap.c ++F: include/blkmap.h ++ + BOOTDEVICE + M: Simon Glass + S: Maintained +diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig +index e95da48bdc..5a1aeb3d2b 100644 +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -67,6 +67,24 @@ config BLOCK_CACHE + it will prevent repeated reads from directory structures and other + filesystem data structures. + ++config BLKMAP ++ bool "Composable virtual block devices (blkmap)" ++ depends on BLK ++ help ++ Create virtual block devices that are backed by various sources, ++ e.g. RAM, or parts of an existing block device. Though much more ++ rudimentary, it borrows a lot of ideas from Linux's device mapper ++ subsystem. ++ ++ Example use-cases: ++ - Treat a region of RAM as a block device, i.e. a RAM disk. This let's ++ you extract files from filesystem images stored in RAM (perhaps as a ++ result of a TFTP transfer). ++ - Create a virtual partition on an existing device. This let's you ++ access filesystems that aren't stored at an exact partition ++ boundary. A common example is a filesystem image embedded in an FIT ++ image. ++ + config SPL_BLOCK_CACHE + bool "Use block device cache in SPL" + depends on SPL_BLK +diff --git a/drivers/block/Makefile b/drivers/block/Makefile +index f12447d78d..a161d145fd 100644 +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -14,6 +14,7 @@ obj-$(CONFIG_IDE) += ide.o + endif + obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o + obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o ++obj-$(CONFIG_BLKMAP) += blkmap.o + + obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o + obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o +diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c +index c69fc4d518..cb73faaeda 100644 +--- a/drivers/block/blk-uclass.c ++++ b/drivers/block/blk-uclass.c +@@ -32,6 +32,7 @@ static struct { + { UCLASS_EFI_LOADER, "efiloader" }, + { UCLASS_VIRTIO, "virtio" }, + { UCLASS_PVBLOCK, "pvblock" }, ++ { UCLASS_BLKMAP, "blkmap" }, + }; + + static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) +diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c +new file mode 100644 +index 0000000000..acfc002ceb +--- /dev/null ++++ b/drivers/block/blkmap.c +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2023 Addiva Elektronik ++ * Author: Tobias Waldekranz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct blkmap; ++ ++/** ++ * struct blkmap_slice - Region mapped to a blkmap ++ * ++ * Common data for a region mapped to a blkmap, specialized by each ++ * map type. ++ * ++ * @node: List node used to associate this slice with a blkmap ++ * @blknr: Start block number of the mapping ++ * @blkcnt: Number of blocks covered by this mapping ++ */ ++struct blkmap_slice { ++ struct list_head node; ++ ++ lbaint_t blknr; ++ lbaint_t blkcnt; ++ ++ /** ++ * @read: - Read from slice ++ * ++ * @read.bm: Blkmap to which this slice belongs ++ * @read.bms: This slice ++ * @read.blknr: Start block number to read from ++ * @read.blkcnt: Number of blocks to read ++ * @read.buffer: Buffer to store read data to ++ */ ++ ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms, ++ lbaint_t blknr, lbaint_t blkcnt, void *buffer); ++ ++ /** ++ * @write: - Write to slice ++ * ++ * @write.bm: Blkmap to which this slice belongs ++ * @write.bms: This slice ++ * @write.blknr: Start block number to write to ++ * @write.blkcnt: Number of blocks to write ++ * @write.buffer: Data to be written ++ */ ++ ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms, ++ lbaint_t blknr, lbaint_t blkcnt, const void *buffer); ++ ++ /** ++ * @destroy: - Tear down slice ++ * ++ * @read.bm: Blkmap to which this slice belongs ++ * @read.bms: This slice ++ */ ++ void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms); ++}; ++ ++/** ++ * struct blkmap - Block map ++ * ++ * Data associated with a blkmap. ++ * ++ * @label: Human readable name of this blkmap ++ * @blk: Underlying block device ++ * @slices: List of slices associated with this blkmap ++ */ ++struct blkmap { ++ char *label; ++ struct udevice *blk; ++ struct list_head slices; ++}; ++ ++static bool blkmap_slice_contains(struct blkmap_slice *bms, lbaint_t blknr) ++{ ++ return (blknr >= bms->blknr) && (blknr < (bms->blknr + bms->blkcnt)); ++} ++ ++static bool blkmap_slice_available(struct blkmap *bm, struct blkmap_slice *new) ++{ ++ struct blkmap_slice *bms; ++ lbaint_t first, last; ++ ++ first = new->blknr; ++ last = new->blknr + new->blkcnt - 1; ++ ++ list_for_each_entry(bms, &bm->slices, node) { ++ if (blkmap_slice_contains(bms, first) || ++ blkmap_slice_contains(bms, last) || ++ blkmap_slice_contains(new, bms->blknr) || ++ blkmap_slice_contains(new, bms->blknr + bms->blkcnt - 1)) ++ return false; ++ } ++ ++ return true; ++} ++ ++static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new) ++{ ++ struct blk_desc *bd = dev_get_uclass_plat(bm->blk); ++ struct list_head *insert = &bm->slices; ++ struct blkmap_slice *bms; ++ ++ if (!blkmap_slice_available(bm, new)) ++ return -EBUSY; ++ ++ list_for_each_entry(bms, &bm->slices, node) { ++ if (bms->blknr < new->blknr) ++ continue; ++ ++ insert = &bms->node; ++ break; ++ } ++ ++ list_add_tail(&new->node, insert); ++ ++ /* Disk might have grown, update the size */ ++ bms = list_last_entry(&bm->slices, struct blkmap_slice, node); ++ bd->lba = bms->blknr + bms->blkcnt; ++ return 0; ++} ++ ++static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms, ++ lbaint_t blknr, lbaint_t blkcnt, ++ void *buffer) ++{ ++ lbaint_t nr, cnt; ++ ++ nr = blknr - bms->blknr; ++ cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt; ++ return bms->read(bm, bms, nr, cnt, buffer); ++} ++ ++static ulong blkmap_blk_read(struct udevice *dev, lbaint_t blknr, ++ lbaint_t blkcnt, void *buffer) ++{ ++ struct blk_desc *bd = dev_get_uclass_plat(dev); ++ struct blkmap *bm = dev_get_plat(dev->parent); ++ struct blkmap_slice *bms; ++ lbaint_t cnt, total = 0; ++ ++ list_for_each_entry(bms, &bm->slices, node) { ++ if (!blkmap_slice_contains(bms, blknr)) ++ continue; ++ ++ cnt = blkmap_blk_read_slice(bm, bms, blknr, blkcnt, buffer); ++ blknr += cnt; ++ blkcnt -= cnt; ++ buffer += cnt << bd->log2blksz; ++ total += cnt; ++ } ++ ++ return total; ++} ++ ++static ulong blkmap_blk_write_slice(struct blkmap *bm, struct blkmap_slice *bms, ++ lbaint_t blknr, lbaint_t blkcnt, ++ const void *buffer) ++{ ++ lbaint_t nr, cnt; ++ ++ nr = blknr - bms->blknr; ++ cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt; ++ return bms->write(bm, bms, nr, cnt, buffer); ++} ++ ++static ulong blkmap_blk_write(struct udevice *dev, lbaint_t blknr, ++ lbaint_t blkcnt, const void *buffer) ++{ ++ struct blk_desc *bd = dev_get_uclass_plat(dev); ++ struct blkmap *bm = dev_get_plat(dev->parent); ++ struct blkmap_slice *bms; ++ lbaint_t cnt, total = 0; ++ ++ list_for_each_entry(bms, &bm->slices, node) { ++ if (!blkmap_slice_contains(bms, blknr)) ++ continue; ++ ++ cnt = blkmap_blk_write_slice(bm, bms, blknr, blkcnt, buffer); ++ blknr += cnt; ++ blkcnt -= cnt; ++ buffer += cnt << bd->log2blksz; ++ total += cnt; ++ } ++ ++ return total; ++} ++ ++static const struct blk_ops blkmap_blk_ops = { ++ .read = blkmap_blk_read, ++ .write = blkmap_blk_write, ++}; ++ ++U_BOOT_DRIVER(blkmap_blk) = { ++ .name = "blkmap_blk", ++ .id = UCLASS_BLK, ++ .ops = &blkmap_blk_ops, ++}; ++ ++int blkmap_dev_bind(struct udevice *dev) ++{ ++ struct blkmap *bm = dev_get_plat(dev); ++ struct blk_desc *bd; ++ int err; ++ ++ err = blk_create_devicef(dev, "blkmap_blk", "blk", UCLASS_BLKMAP, ++ dev_seq(dev), 512, 0, &bm->blk); ++ if (err) ++ return log_msg_ret("blk", err); ++ ++ INIT_LIST_HEAD(&bm->slices); ++ ++ bd = dev_get_uclass_plat(bm->blk); ++ snprintf(bd->vendor, BLK_VEN_SIZE, "U-Boot"); ++ snprintf(bd->product, BLK_PRD_SIZE, "blkmap"); ++ snprintf(bd->revision, BLK_REV_SIZE, "1.0"); ++ ++ /* EFI core isn't keen on zero-sized disks, so we lie. This is ++ * updated with the correct size once the user adds a ++ * mapping. ++ */ ++ bd->lba = 1; ++ ++ return 0; ++} ++ ++int blkmap_dev_unbind(struct udevice *dev) ++{ ++ struct blkmap *bm = dev_get_plat(dev); ++ struct blkmap_slice *bms, *tmp; ++ int err; ++ ++ list_for_each_entry_safe(bms, tmp, &bm->slices, node) { ++ list_del(&bms->node); ++ free(bms); ++ } ++ ++ err = device_remove(bm->blk, DM_REMOVE_NORMAL); ++ if (err) ++ return err; ++ ++ return device_unbind(bm->blk); ++} ++ ++U_BOOT_DRIVER(blkmap_root) = { ++ .name = "blkmap_dev", ++ .id = UCLASS_BLKMAP, ++ .bind = blkmap_dev_bind, ++ .unbind = blkmap_dev_unbind, ++ .plat_auto = sizeof(struct blkmap), ++}; ++ ++struct udevice *blkmap_from_label(const char *label) ++{ ++ struct udevice *dev; ++ struct uclass *uc; ++ struct blkmap *bm; ++ ++ uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) { ++ bm = dev_get_plat(dev); ++ if (bm->label && !strcmp(label, bm->label)) ++ return dev; ++ } ++ ++ return NULL; ++} ++ ++int blkmap_create(const char *label, struct udevice **devp) ++{ ++ char *hname, *hlabel; ++ struct udevice *dev; ++ struct blkmap *bm; ++ size_t namelen; ++ int err; ++ ++ dev = blkmap_from_label(label); ++ if (dev) { ++ err = -EBUSY; ++ goto err; ++ } ++ ++ hlabel = strdup(label); ++ if (!hlabel) { ++ err = -ENOMEM; ++ goto err; ++ } ++ ++ namelen = strlen("blkmap-") + strlen(label) + 1; ++ hname = malloc(namelen); ++ if (!hname) { ++ err = -ENOMEM; ++ goto err_free_hlabel; ++ } ++ ++ strlcpy(hname, "blkmap-", namelen); ++ strlcat(hname, label, namelen); ++ ++ err = device_bind_driver(dm_root(), "blkmap_dev", hname, &dev); ++ if (err) ++ goto err_free_hname; ++ ++ device_set_name_alloced(dev); ++ bm = dev_get_plat(dev); ++ bm->label = hlabel; ++ ++ if (devp) ++ *devp = dev; ++ ++ return 0; ++ ++err_free_hname: ++ free(hname); ++err_free_hlabel: ++ free(hlabel); ++err: ++ return err; ++} ++ ++int blkmap_destroy(struct udevice *dev) ++{ ++ int err; ++ ++ err = device_remove(dev, DM_REMOVE_NORMAL); ++ if (err) ++ return err; ++ ++ return device_unbind(dev); ++} ++ ++UCLASS_DRIVER(blkmap) = { ++ .id = UCLASS_BLKMAP, ++ .name = "blkmap", ++}; +diff --git a/include/blkmap.h b/include/blkmap.h +new file mode 100644 +index 0000000000..3c7e36efab +--- /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 33e43c20db..576237b954 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 */ +-- +2.34.1 + diff --git a/board/common/uboot/patches/0004-blk-blkmap-Add-memory-mapping-support.patch b/board/common/uboot/patches/0004-blk-blkmap-Add-memory-mapping-support.patch new file mode 100644 index 00000000..d221113a --- /dev/null +++ b/board/common/uboot/patches/0004-blk-blkmap-Add-memory-mapping-support.patch @@ -0,0 +1,174 @@ +From 77fd2a74a5f7a14f42b5c7acd175a9c1519c4f16 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Feb 2023 15:08:00 +0100 +Subject: [PATCH v2 4/9] 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 +--- + drivers/block/blkmap.c | 105 +++++++++++++++++++++++++++++++++++++++++ + include/blkmap.h | 29 ++++++++++++ + 2 files changed, 134 insertions(+) + +diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c +index acfc002ceb..6d6eed889e 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 3c7e36efab..74baeb19f8 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 + * +-- +2.34.1 + diff --git a/board/common/uboot/patches/0005-blk-blkmap-Add-linear-device-mapping-support.patch b/board/common/uboot/patches/0005-blk-blkmap-Add-linear-device-mapping-support.patch new file mode 100644 index 00000000..2a0929c7 --- /dev/null +++ b/board/common/uboot/patches/0005-blk-blkmap-Add-linear-device-mapping-support.patch @@ -0,0 +1,125 @@ +From 29ed14e1a427c4e308413bccdc75084c1c1ec75a Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Feb 2023 15:09:21 +0100 +Subject: [PATCH v2 5/9] 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 +--- + drivers/block/blkmap.c | 71 ++++++++++++++++++++++++++++++++++++++++++ + include/blkmap.h | 13 ++++++++ + 2 files changed, 84 insertions(+) + +diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c +index 6d6eed889e..2bb0acc20f 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 74baeb19f8..af54583c7d 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 + * +-- +2.34.1 + diff --git a/board/common/uboot/patches/0006-cmd-blkmap-Add-blkmap-command.patch b/board/common/uboot/patches/0006-cmd-blkmap-Add-blkmap-command.patch new file mode 100644 index 00000000..5c02e96b --- /dev/null +++ b/board/common/uboot/patches/0006-cmd-blkmap-Add-blkmap-command.patch @@ -0,0 +1,337 @@ +From c20dd0f17a128e65c1f376bf0e1cad9cec1d0336 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Thu, 16 Feb 2023 15:10:49 +0100 +Subject: [PATCH v2 6/9] cmd: blkmap: Add blkmap command + +Add a frontend for the blkmap subsystem. In addition to the common +block device operations, this allows users to create and destroy +devices, and map in memory and slices of other block devices. + +With that we support two primary use-cases: + +- Being able to "distro boot" from a RAM disk. I.e., from an image + where the kernel is stored in /boot of some filesystem supported + by U-Boot. + +- Accessing filesystems not located on exact partition boundaries, + e.g. when a filesystem image is wrapped in an FIT image and stored + in a disk partition. + +Signed-off-by: Tobias Waldekranz +--- + MAINTAINERS | 1 + + cmd/Kconfig | 19 +++++ + cmd/Makefile | 1 + + cmd/blkmap.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++ + disk/part.c | 1 + + 5 files changed, 255 insertions(+) + create mode 100644 cmd/blkmap.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 3e47c9b34c..316b85fed7 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -796,6 +796,7 @@ F: tools/binman/ + BLKMAP + M: Tobias Waldekranz + S: Maintained ++F: cmd/blkmap.c + F: drivers/block/blkmap.c + F: include/blkmap.h + +diff --git a/cmd/Kconfig b/cmd/Kconfig +index 2caa4af71c..3dd3cdc656 100644 +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -1959,6 +1959,25 @@ config CMD_BLOCK_CACHE + during development, but also allows the cache to be disabled when + it might hurt performance (e.g. when using the ums command). + ++config CMD_BLKMAP ++ bool "blkmap - Composable virtual block devices" ++ depends on BLKMAP ++ default y if BLKMAP ++ help ++ Create virtual block devices that are backed by various sources, ++ e.g. RAM, or parts of an existing block device. Though much more ++ rudimentary, it borrows a lot of ideas from Linux's device mapper ++ subsystem. ++ ++ Example use-cases: ++ - Treat a region of RAM as a block device, i.e. a RAM disk. This let's ++ you extract files from filesystem images stored in RAM (perhaps as a ++ result of a TFTP transfer). ++ - Create a virtual partition on an existing device. This let's you ++ access filesystems that aren't stored at an exact partition ++ boundary. A common example is a filesystem image embedded in an FIT ++ image. ++ + config CMD_BUTTON + bool "button" + depends on BUTTON +diff --git a/cmd/Makefile b/cmd/Makefile +index 36d2daf22a..837eee39b1 100644 +--- a/cmd/Makefile ++++ b/cmd/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_CMD_BCB) += bcb.o + obj-$(CONFIG_CMD_BDI) += bdinfo.o + obj-$(CONFIG_CMD_BIND) += bind.o + obj-$(CONFIG_CMD_BINOP) += binop.o ++obj-$(CONFIG_CMD_BLKMAP) += blkmap.o + obj-$(CONFIG_CMD_BLOBLIST) += bloblist.o + obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o + obj-$(CONFIG_CMD_BMP) += bmp.o +diff --git a/cmd/blkmap.c b/cmd/blkmap.c +new file mode 100644 +index 0000000000..b34c013072 +--- /dev/null ++++ b/cmd/blkmap.c +@@ -0,0 +1,233 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2023 Addiva Elektronik ++ * Author: Tobias Waldekranz ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int blkmap_curr_dev; ++ ++struct map_ctx { ++ struct udevice *dev; ++ lbaint_t blknr, blkcnt; ++}; ++ ++typedef int (*map_parser_fn)(struct map_ctx *ctx, int argc, char *const argv[]); ++ ++struct map_handler { ++ const char *name; ++ map_parser_fn fn; ++}; ++ ++int do_blkmap_map_linear(struct map_ctx *ctx, int argc, char *const argv[]) ++{ ++ struct blk_desc *lbd; ++ int err, ldevnum; ++ lbaint_t lblknr; ++ ++ if (argc < 4) ++ return CMD_RET_USAGE; ++ ++ ldevnum = dectoul(argv[2], NULL); ++ lblknr = dectoul(argv[3], NULL); ++ ++ lbd = blk_get_devnum_by_uclass_idname(argv[1], ldevnum); ++ if (!lbd) { ++ printf("Found no device matching \"%s %d\"\n", ++ argv[1], ldevnum); ++ return CMD_RET_FAILURE; ++ } ++ ++ err = blkmap_map_linear(ctx->dev, ctx->blknr, ctx->blkcnt, ++ lbd->bdev, lblknr); ++ if (err) { ++ printf("Unable to map \"%s %d\" at block 0x" LBAF ": %d\n", ++ argv[1], ldevnum, ctx->blknr, err); ++ ++ return CMD_RET_FAILURE; ++ } ++ ++ printf("Block 0x" LBAF "+0x" LBAF " mapped to block 0x" LBAF " of \"%s %d\"\n", ++ ctx->blknr, ctx->blkcnt, lblknr, argv[1], ldevnum); ++ return CMD_RET_SUCCESS; ++} ++ ++int do_blkmap_map_mem(struct map_ctx *ctx, int argc, char *const argv[]) ++{ ++ phys_addr_t addr; ++ int err; ++ ++ if (argc < 2) ++ return CMD_RET_USAGE; ++ ++ addr = hextoul(argv[1], NULL); ++ ++ err = blkmap_map_pmem(ctx->dev, ctx->blknr, ctx->blkcnt, addr); ++ if (err) { ++ printf("Unable to map %#llx at block 0x" LBAF ": %d\n", ++ (unsigned long long)addr, ctx->blknr, err); ++ return CMD_RET_FAILURE; ++ } ++ ++ printf("Block 0x" LBAF "+0x" LBAF " mapped to %#llx\n", ++ ctx->blknr, ctx->blkcnt, (unsigned long long)addr); ++ return CMD_RET_SUCCESS; ++} ++ ++struct map_handler map_handlers[] = { ++ { .name = "linear", .fn = do_blkmap_map_linear }, ++ { .name = "mem", .fn = do_blkmap_map_mem }, ++ ++ { .name = NULL } ++}; ++ ++static int do_blkmap_map(struct cmd_tbl *cmdtp, int flag, ++ int argc, char *const argv[]) ++{ ++ struct map_handler *handler; ++ struct map_ctx ctx; ++ ++ if (argc < 5) ++ return CMD_RET_USAGE; ++ ++ ctx.dev = blkmap_from_label(argv[1]); ++ if (!ctx.dev) { ++ printf("\"%s\" is not the name of any known blkmap\n", argv[1]); ++ return CMD_RET_FAILURE; ++ } ++ ++ ctx.blknr = hextoul(argv[2], NULL); ++ ctx.blkcnt = hextoul(argv[3], NULL); ++ argc -= 4; ++ argv += 4; ++ ++ for (handler = map_handlers; handler->name; handler++) { ++ if (!strcmp(handler->name, argv[0])) ++ return handler->fn(&ctx, argc, argv); ++ } ++ ++ printf("Unknown map type \"%s\"\n", argv[0]); ++ return CMD_RET_USAGE; ++} ++ ++static int do_blkmap_create(struct cmd_tbl *cmdtp, int flag, ++ int argc, char *const argv[]) ++{ ++ const char *label; ++ int err; ++ ++ if (argc != 2) ++ return CMD_RET_USAGE; ++ ++ label = argv[1]; ++ ++ err = blkmap_create(label, NULL); ++ if (err) { ++ printf("Unable to create \"%s\": %d\n", label, err); ++ return CMD_RET_FAILURE; ++ } ++ ++ printf("Created \"%s\"\n", label); ++ return CMD_RET_SUCCESS; ++} ++ ++static int do_blkmap_destroy(struct cmd_tbl *cmdtp, int flag, ++ int argc, char *const argv[]) ++{ ++ struct udevice *dev; ++ const char *label; ++ int err; ++ ++ if (argc != 2) ++ return CMD_RET_USAGE; ++ ++ label = argv[1]; ++ ++ dev = blkmap_from_label(label); ++ if (!dev) { ++ printf("\"%s\" is not the name of any known blkmap\n", label); ++ return CMD_RET_FAILURE; ++ } ++ ++ err = blkmap_destroy(dev); ++ if (err) { ++ printf("Unable to destroy \"%s\": %d\n", label, err); ++ return CMD_RET_FAILURE; ++ } ++ ++ printf("Destroyed \"%s\"\n", label); ++ return CMD_RET_SUCCESS; ++} ++ ++static int do_blkmap_get(struct cmd_tbl *cmdtp, int flag, ++ int argc, char *const argv[]) ++{ ++ struct udevice *dev; ++ const char *label; ++ int err; ++ ++ if (argc < 3) ++ return CMD_RET_USAGE; ++ ++ label = argv[1]; ++ ++ dev = blkmap_from_label(label); ++ if (!dev) { ++ printf("\"%s\" is not the name of any known blkmap\n", label); ++ return CMD_RET_FAILURE; ++ } ++ ++ if (!strcmp(argv[2], "dev")) { ++ if (argc == 3) { ++ printf("%d\n", dev_seq(dev)); ++ } else { ++ err = env_set_hex(argv[3], dev_seq(dev)); ++ if (err) ++ return CMD_RET_FAILURE; ++ } ++ } else { ++ return CMD_RET_USAGE; ++ } ++ ++ return CMD_RET_SUCCESS; ++} ++ ++static int do_blkmap_common(struct cmd_tbl *cmdtp, int flag, ++ int argc, char *const argv[]) ++{ ++ /* The subcommand parsing pops the original argv[0] ("blkmap") ++ * which blk_common_cmd expects. Push it back again. ++ */ ++ argc++; ++ argv--; ++ ++ return blk_common_cmd(argc, argv, UCLASS_BLKMAP, &blkmap_curr_dev); ++} ++ ++U_BOOT_CMD_WITH_SUBCMDS( ++ blkmap, "Composeable virtual block devices", ++ "info - list configured devices\n" ++ "blkmap part - list available partitions on current blkmap device\n" ++ "blkmap dev [] - show or set current blkmap device\n" ++ "blkmap read \n" ++ "blkmap write \n" ++ "blkmap get