mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-31 04:53:01 +02:00
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")
This commit is contained in:
committed by
Joachim Wiberg
parent
07dd863fb9
commit
d4432b72dd
+32
@@ -0,0 +1,32 @@
|
||||
From 4aef55d1b8cc24187f12f83a2f4d9bfc41ba12ee Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
Reviewed-by: Simon Glass <sjg@chromium.org>
|
||||
---
|
||||
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
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
From 74f121de98a1614a4068960445b8355cb3e5fa04 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
Reviewed-by: Simon Glass <sjg@chromium.org>
|
||||
---
|
||||
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 <common.h>
|
||||
#include <blk.h>
|
||||
#include <command.h>
|
||||
+#include <mapmem.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
From 104a2ab39ac72c402d7463bec05aae4a6d09cfbf Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <alpernebiyasak@gmail.com>
|
||||
S: Maintained
|
||||
F: tools/binman/
|
||||
|
||||
+BLKMAP
|
||||
+M: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+S: Maintained
|
||||
+F: drivers/block/blkmap.c
|
||||
+F: include/blkmap.h
|
||||
+
|
||||
BOOTDEVICE
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
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 <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <common.h>
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <dm.h>
|
||||
+#include <malloc.h>
|
||||
+#include <mapmem.h>
|
||||
+#include <part.h>
|
||||
+#include <dm/device-internal.h>
|
||||
+#include <dm/lists.h>
|
||||
+#include <dm/root.h>
|
||||
+
|
||||
+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 <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#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
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
From 77fd2a74a5f7a14f42b5c7acd175a9c1519c4f16 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
From 29ed14e1a427c4e308413bccdc75084c1c1ec75a Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
From c20dd0f17a128e65c1f376bf0e1cad9cec1d0336 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
---
|
||||
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 <tobias@waldekranz.com>
|
||||
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 <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <common.h>
|
||||
+#include <command.h>
|
||||
+#include <malloc.h>
|
||||
+#include <dm/device.h>
|
||||
+
|
||||
+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 [<dev>] - show or set current blkmap device\n"
|
||||
+ "blkmap read <addr> <blk#> <cnt>\n"
|
||||
+ "blkmap write <addr> <blk#> <cnt>\n"
|
||||
+ "blkmap get <label> dev [<var>] - store device number in variable\n"
|
||||
+ "blkmap create <label> - create device\n"
|
||||
+ "blkmap destroy <label> - destroy device\n"
|
||||
+ "blkmap map <label> <blk#> <cnt> linear <interface> <dev> <blk#> - device mapping\n"
|
||||
+ "blkmap map <label> <blk#> <cnt> mem <addr> - memory mapping\n",
|
||||
+ U_BOOT_SUBCMD_MKENT(info, 2, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(part, 2, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(dev, 4, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(read, 5, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(write, 5, 1, do_blkmap_common),
|
||||
+ U_BOOT_SUBCMD_MKENT(get, 5, 1, do_blkmap_get),
|
||||
+ U_BOOT_SUBCMD_MKENT(create, 2, 1, do_blkmap_create),
|
||||
+ U_BOOT_SUBCMD_MKENT(destroy, 2, 1, do_blkmap_destroy),
|
||||
+ U_BOOT_SUBCMD_MKENT(map, 32, 1, do_blkmap_map));
|
||||
diff --git a/disk/part.c b/disk/part.c
|
||||
index d449635254..35300df590 100644
|
||||
--- a/disk/part.c
|
||||
+++ b/disk/part.c
|
||||
@@ -140,6 +140,7 @@ void dev_print(struct blk_desc *dev_desc)
|
||||
case UCLASS_NVME:
|
||||
case UCLASS_PVBLOCK:
|
||||
case UCLASS_HOST:
|
||||
+ case UCLASS_BLKMAP:
|
||||
printf ("Vendor: %s Rev: %s Prod: %s\n",
|
||||
dev_desc->vendor,
|
||||
dev_desc->revision,
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
From e9a394da1d75b2b3bea81e53ec2899d240a98861 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:13:33 +0100
|
||||
Subject: [PATCH v2 7/9] test: blkmap: Add test suite
|
||||
|
||||
Verify that:
|
||||
|
||||
- Block maps can be created and destroyed
|
||||
- Mappings aren't allowed to overlap
|
||||
- Multiple mappings can be attached and be read/written from/to
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
configs/sandbox_defconfig | 1 +
|
||||
test/dm/Makefile | 1 +
|
||||
test/dm/blkmap.c | 201 ++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 204 insertions(+)
|
||||
create mode 100644 test/dm/blkmap.c
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 316b85fed7..bbcb5117fe 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -799,6 +799,7 @@ S: Maintained
|
||||
F: cmd/blkmap.c
|
||||
F: drivers/block/blkmap.c
|
||||
F: include/blkmap.h
|
||||
+F: test/dm/blkmap.c
|
||||
|
||||
BOOTDEVICE
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
|
||||
index 34c342b6f5..06021e4902 100644
|
||||
--- a/configs/sandbox_defconfig
|
||||
+++ b/configs/sandbox_defconfig
|
||||
@@ -145,6 +145,7 @@ CONFIG_ADC=y
|
||||
CONFIG_ADC_SANDBOX=y
|
||||
CONFIG_AXI=y
|
||||
CONFIG_AXI_SANDBOX=y
|
||||
+CONFIG_BLKMAP=y
|
||||
CONFIG_SYS_IDE_MAXBUS=1
|
||||
CONFIG_SYS_ATA_BASE_ADDR=0x100
|
||||
CONFIG_SYS_ATA_STRIDE=4
|
||||
diff --git a/test/dm/Makefile b/test/dm/Makefile
|
||||
index 7a79b6e1a2..e15bdbf04b 100644
|
||||
--- a/test/dm/Makefile
|
||||
+++ b/test/dm/Makefile
|
||||
@@ -29,6 +29,7 @@ obj-$(CONFIG_ADC) += adc.o
|
||||
obj-$(CONFIG_SOUND) += audio.o
|
||||
obj-$(CONFIG_AXI) += axi.o
|
||||
obj-$(CONFIG_BLK) += blk.o
|
||||
+obj-$(CONFIG_BLKMAP) += blkmap.o
|
||||
obj-$(CONFIG_BUTTON) += button.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
|
||||
obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode.o
|
||||
diff --git a/test/dm/blkmap.c b/test/dm/blkmap.c
|
||||
new file mode 100644
|
||||
index 0000000000..7a163d6eae
|
||||
--- /dev/null
|
||||
+++ b/test/dm/blkmap.c
|
||||
@@ -0,0 +1,201 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Addiva Elektronik
|
||||
+ * Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+ */
|
||||
+
|
||||
+#include <common.h>
|
||||
+#include <blk.h>
|
||||
+#include <blkmap.h>
|
||||
+#include <dm.h>
|
||||
+#include <asm/test.h>
|
||||
+#include <dm/test.h>
|
||||
+#include <test/test.h>
|
||||
+#include <test/ut.h>
|
||||
+
|
||||
+#define BLKSZ 0x200
|
||||
+
|
||||
+struct mapping {
|
||||
+ int src;
|
||||
+ int cnt;
|
||||
+ int dst;
|
||||
+};
|
||||
+
|
||||
+const struct mapping unordered_mapping[] = {
|
||||
+ { 0, 1, 3 },
|
||||
+ { 1, 3, 0 },
|
||||
+ { 4, 2, 6 },
|
||||
+ { 6, 2, 4 },
|
||||
+
|
||||
+ { 0, 0, 0 }
|
||||
+};
|
||||
+
|
||||
+const struct mapping identity_mapping[] = {
|
||||
+ { 0, 8, 0 },
|
||||
+
|
||||
+ { 0, 0, 0 }
|
||||
+};
|
||||
+
|
||||
+static char identity[8 * BLKSZ];
|
||||
+static char unordered[8 * BLKSZ];
|
||||
+static char buffer[8 * BLKSZ];
|
||||
+
|
||||
+static void mkblob(void *base, const struct mapping *m)
|
||||
+{
|
||||
+ int nr;
|
||||
+
|
||||
+ for (; m->cnt; m++) {
|
||||
+ for (nr = 0; nr < m->cnt; nr++) {
|
||||
+ memset(base + (m->dst + nr) * BLKSZ,
|
||||
+ m->src + nr, BLKSZ);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int dm_test_blkmap_read(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev, *blk;
|
||||
+ const struct mapping *m;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("rdtest", &dev));
|
||||
+ ut_assertok(blk_get_from_parent(dev, &blk));
|
||||
+
|
||||
+ /* Generate an ordered and an unordered pattern in memory */
|
||||
+ mkblob(unordered, unordered_mapping);
|
||||
+ mkblob(identity, identity_mapping);
|
||||
+
|
||||
+ /* Create a blkmap that cancels out the disorder */
|
||||
+ for (m = unordered_mapping; m->cnt; m++) {
|
||||
+ ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
|
||||
+ unordered + m->dst * BLKSZ));
|
||||
+ }
|
||||
+
|
||||
+ /* Read out the data via the blkmap device to another area,
|
||||
+ * and verify that it matches the ordered pattern.
|
||||
+ */
|
||||
+ ut_asserteq(8, blk_read(blk, 0, 8, buffer));
|
||||
+ ut_assertok(memcmp(buffer, identity, sizeof(buffer)));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_read, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_write(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev, *blk;
|
||||
+ const struct mapping *m;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("wrtest", &dev));
|
||||
+ ut_assertok(blk_get_from_parent(dev, &blk));
|
||||
+
|
||||
+ /* Generate an ordered and an unordered pattern in memory */
|
||||
+ mkblob(unordered, unordered_mapping);
|
||||
+ mkblob(identity, identity_mapping);
|
||||
+
|
||||
+ /* Create a blkmap that mimics the disorder */
|
||||
+ for (m = unordered_mapping; m->cnt; m++) {
|
||||
+ ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
|
||||
+ buffer + m->dst * BLKSZ));
|
||||
+ }
|
||||
+
|
||||
+ /* Write the ordered data via the blkmap device to another
|
||||
+ * area, and verify that the result matches the unordered
|
||||
+ * pattern.
|
||||
+ */
|
||||
+ ut_asserteq(8, blk_write(blk, 0, 8, identity));
|
||||
+ ut_assertok(memcmp(buffer, unordered, sizeof(buffer)));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_write, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_slicing(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *dev;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("slicetest", &dev));
|
||||
+
|
||||
+ ut_assertok(blkmap_map_mem(dev, 8, 8, NULL));
|
||||
+
|
||||
+ /* Can't overlap on the low end */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 4, 5, NULL));
|
||||
+ /* Can't be inside */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 10, 2, NULL));
|
||||
+ /* Can't overlap on the high end */
|
||||
+ ut_asserteq(-EBUSY, blkmap_map_mem(dev, 15, 4, NULL));
|
||||
+
|
||||
+ /* But we should be able to add slices right before and
|
||||
+ * after
|
||||
+ */
|
||||
+ ut_assertok(blkmap_map_mem(dev, 4, 4, NULL));
|
||||
+ ut_assertok(blkmap_map_mem(dev, 16, 4, NULL));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(dev));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_slicing, 0);
|
||||
+
|
||||
+static int dm_test_blkmap_creation(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct udevice *first, *second;
|
||||
+
|
||||
+ ut_assertok(blkmap_create("first", &first));
|
||||
+
|
||||
+ /* Can't have two "first"s */
|
||||
+ ut_asserteq(-EBUSY, blkmap_create("first", &second));
|
||||
+
|
||||
+ /* But "second" should be fine */
|
||||
+ ut_assertok(blkmap_create("second", &second));
|
||||
+
|
||||
+ /* Once "first" is destroyed, we should be able to create it
|
||||
+ * again
|
||||
+ */
|
||||
+ ut_assertok(blkmap_destroy(first));
|
||||
+ ut_assertok(blkmap_create("first", &first));
|
||||
+
|
||||
+ ut_assertok(blkmap_destroy(first));
|
||||
+ ut_assertok(blkmap_destroy(second));
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_blkmap_creation, 0);
|
||||
+
|
||||
+static int dm_test_cmd_blkmap(struct unit_test_state *uts)
|
||||
+{
|
||||
+ ulong loadaddr = env_get_hex("loadaddr", 0);
|
||||
+ struct udevice *dev;
|
||||
+
|
||||
+ console_record_reset();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap create ramdisk", 0));
|
||||
+ ut_assert_nextline("Created \"ramdisk\"");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertnonnull((dev = blkmap_from_label("ramdisk")));
|
||||
+
|
||||
+ ut_assertok(run_commandf("blkmap map ramdisk 0 800 mem 0x%lx", loadaddr));
|
||||
+ ut_assert_nextline("Block 0x0+0x800 mapped to 0x%lx", loadaddr);
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_nextline("Device 0: Vendor: U-Boot Rev: 1.0 Prod: blkmap");
|
||||
+ ut_assert_nextline(" Type: Hard Disk");
|
||||
+ ut_assert_nextline(" Capacity: 1.0 MB = 0.0 GB (2048 x 512)");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap get ramdisk dev devnum", 0));
|
||||
+ ut_asserteq(dev_seq(dev), env_get_hex("devnum", 0xdeadbeef));
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap destroy ramdisk", 0));
|
||||
+ ut_assert_nextline("Destroyed \"ramdisk\"");
|
||||
+ ut_assert_console_end();
|
||||
+
|
||||
+ ut_assertok(run_command("blkmap info", 0));
|
||||
+ ut_assert_console_end();
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_cmd_blkmap, 0);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
From 53e157184110e66144e805e733e5f0a7a4a031a8 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:14:27 +0100
|
||||
Subject: [PATCH v2 8/9] doc: blkmap: Add introduction and examples
|
||||
|
||||
Explain block maps by going through two common use-cases.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
doc/usage/blkmap.rst | 111 +++++++++++++++++++++++++++++++++++++++++++
|
||||
doc/usage/index.rst | 1 +
|
||||
3 files changed, 113 insertions(+)
|
||||
create mode 100644 doc/usage/blkmap.rst
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index bbcb5117fe..e02dacc20a 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -797,6 +797,7 @@ BLKMAP
|
||||
M: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
S: Maintained
|
||||
F: cmd/blkmap.c
|
||||
+F: doc/usage/blkmap.rst
|
||||
F: drivers/block/blkmap.c
|
||||
F: include/blkmap.h
|
||||
F: test/dm/blkmap.c
|
||||
diff --git a/doc/usage/blkmap.rst b/doc/usage/blkmap.rst
|
||||
new file mode 100644
|
||||
index 0000000000..dbfa8e5aad
|
||||
--- /dev/null
|
||||
+++ b/doc/usage/blkmap.rst
|
||||
@@ -0,0 +1,111 @@
|
||||
+.. SPDX-License-Identifier: GPL-2.0+
|
||||
+..
|
||||
+.. Copyright (c) 2023 Addiva Elektronik
|
||||
+.. Author: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
+
|
||||
+Block Maps (blkmap)
|
||||
+===================
|
||||
+
|
||||
+Block maps are a way of looking at various sources of data through the
|
||||
+lens of a regular block device. It lets you treat devices that are not
|
||||
+block devices, like RAM, as if they were. It also lets you export a
|
||||
+slice of an existing block device, which does not have to correspond
|
||||
+to a partition boundary, as a new block device.
|
||||
+
|
||||
+This is primarily useful because U-Boot's filesystem drivers only
|
||||
+operate on block devices, so a block map lets you access filesystems
|
||||
+wherever they might be located.
|
||||
+
|
||||
+The implementation is loosely modeled on Linux's "Device Mapper"
|
||||
+subsystem, see `kernel documentation`_ for more information.
|
||||
+
|
||||
+.. _kernel documentation: https://docs.kernel.org/admin-guide/device-mapper/index.html
|
||||
+
|
||||
+
|
||||
+Example: Netbooting an Ext4 Image
|
||||
+---------------------------------
|
||||
+
|
||||
+Say that our system is using an Ext4 filesystem as its rootfs, where
|
||||
+the kernel is stored in ``/boot``. This image is then typically stored
|
||||
+in an eMMC partition. In this configuration, we can use something like
|
||||
+``load mmc 0 ${kernel_addr_r} /boot/Image`` to load the kernel image
|
||||
+into the expected location, and then boot the system. No problems.
|
||||
+
|
||||
+Now imagine that during development, or as a recovery mechanism, we
|
||||
+want to boot the same type of image by downloading it over the
|
||||
+network. Getting the image to the target is easy enough:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ dhcp ${ramdisk_addr_r} rootfs.ext4
|
||||
+
|
||||
+But now we are faced with a predicament: how to we extract the kernel
|
||||
+image? Block maps to the rescue!
|
||||
+
|
||||
+We start by creating a new device:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap create netboot
|
||||
+
|
||||
+Before setting up the mapping, we figure out the size of the
|
||||
+downloaded file, in blocks:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ setexpr fileblks ${filesize} + 0x1ff
|
||||
+ setexpr fileblks ${filesize} / 0x200
|
||||
+
|
||||
+Then we can add a mapping to the start of our device, backed by the
|
||||
+memory at `${loadaddr}`:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap map netboot 0 ${fileblks} mem ${fileaddr}
|
||||
+
|
||||
+Now we can access the filesystem via the virtual device:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap get netboot dev devnum
|
||||
+ load blkmap ${devnum} ${kernel_addr_r} /boot/Image
|
||||
+
|
||||
+
|
||||
+Example: Accessing a filesystem inside an FIT image
|
||||
+---------------------------------------------------
|
||||
+
|
||||
+In this example, an FIT image is stored in an eMMC partition. We would
|
||||
+like to read the file ``/etc/version``, stored inside a Squashfs image
|
||||
+in the FIT. Since the Squashfs image is not stored on a partition
|
||||
+boundary, there is no way of accessing it via ``load mmc ...``.
|
||||
+
|
||||
+What we can to instead is to first figure out the offset and size of
|
||||
+the filesystem:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ mmc dev 0
|
||||
+ mmc read ${loadaddr} 0 0x100
|
||||
+
|
||||
+ fdt addr ${loadaddr}
|
||||
+ fdt get value squashaddr /images/ramdisk data-position
|
||||
+ fdt get value squashsize /images/ramdisk data-size
|
||||
+
|
||||
+ setexpr squashblk ${squashaddr} / 0x200
|
||||
+ setexpr squashsize ${squashsize} + 0x1ff
|
||||
+ setexpr squashsize ${squashsize} / 0x200
|
||||
+
|
||||
+Then we can create a block map that maps to that slice of the full
|
||||
+partition:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap create sq
|
||||
+ blkmap map sq 0 ${squashsize} linear mmc 0 ${squashblk}
|
||||
+
|
||||
+Now we can access the filesystem:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ blkmap get sq dev devnum
|
||||
+ load blkmap ${devnum} ${loadaddr} /etc/version
|
||||
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
|
||||
index cde7dcb14a..2dfcd4b2b2 100644
|
||||
--- a/doc/usage/index.rst
|
||||
+++ b/doc/usage/index.rst
|
||||
@@ -4,6 +4,7 @@ Use U-Boot
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
+ blkmap
|
||||
dfu
|
||||
environment
|
||||
fdt_overlays
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
From 0a0ceadab82a1e76d0d21b14b75510d3bd9228ff Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Thu, 16 Feb 2023 15:15:59 +0100
|
||||
Subject: [PATCH v2 9/9] efi_loader: device_path: support blkmap devices
|
||||
|
||||
Create a distinct EFI device path for each blkmap device.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
include/efi_loader.h | 4 ++++
|
||||
lib/efi_loader/efi_device_path.c | 30 ++++++++++++++++++++++++++++++
|
||||
2 files changed, 34 insertions(+)
|
||||
|
||||
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
||||
index c664d6cdf2..eb3818b457 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 3b267b713e..4b4c96bc2e 100644
|
||||
--- a/lib/efi_loader/efi_device_path.c
|
||||
+++ b/lib/efi_loader/efi_device_path.c
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <asm-generic/unaligned.h>
|
||||
#include <linux/compat.h> /* 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
|
||||
@@ -573,6 +576,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);
|
||||
@@ -631,6 +644,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: */
|
||||
--
|
||||
2.34.1
|
||||
|
||||
Reference in New Issue
Block a user