Re: [PATCH 09/15] blk: blkmap: Support mapping to device of any block size

2023-09-26 Thread Tobias Waldekranz
On tis, sep 26, 2023 at 16:43, Bin Meng  wrote:
> At present if a device to map has a block size other than 512,
> the blkmap map process just fails. There is no reason why we
> can't just use the block size of the mapped device.

Won't this be very confusing to the user?

The blkmap device uses a fixed block size of 512:

https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/block/blkmap.c?ref_type=heads#L393

So if I map a slice of a 4k device into a blkmap, then

blkmap read 0x8000 0 1

would copy 4k instead of 512 bytes from the lower device to 0x8000,
even though the blkmap reports a block size of 512.

It seems to me that the expected behavior would be that only the first
512 bytes would be copied in the command above.

>
> Signed-off-by: Bin Meng 
> ---
>
>  drivers/block/blkmap.c | 10 +-
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
> index f6acfa8927..149a4cac3e 100644
> --- a/drivers/block/blkmap.c
> +++ b/drivers/block/blkmap.c
> @@ -171,11 +171,11 @@ int blkmap_map_linear(struct udevice *dev, lbaint_t 
> blknr, lbaint_t blkcnt,
>  
>   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.
> -  */

Hence this comment ^

> - return -EINVAL;
> + if (lbd->blksz != bd->blksz) {
> + /* update to match the mapped device */
> + bd->blksz = lbd->blksz;
> + bd->log2blksz = LOG2(bd->blksz);
> + }
>  
>   linear = malloc(sizeof(*linear));
>   if (!linear)
> -- 
> 2.25.1


Re: [PATCH v2 0/6] introduce EFI_RAM_DISK_PROTOCOL

2023-07-14 Thread Tobias Waldekranz


Hi Masahisa,

On fre, jul 14, 2023 at 14:44, Masahisa Kojima  
wrote:
> This series introduces the EFI_RAM_DISK_PROTOCOL implementation.
> The major purpose of this series is a preparation for EFI HTTP(S) boot.
>
> Now U-Boot can download the distro installer ISO image
> via wget or tftpboot commands, but U-Boot can not mount
> the downloaded ISO image.

A while back, I added the blkmap command and backend to U-Boot, which
is, among other things, capable of creating ramdisks. What exactly does
this series add that can't be supported by a block map? There is some
documentation available here:

https://u-boot.readthedocs.io/en/latest/usage/blkmap.html


[PATCH v2 6/9] cmd: blkmap: Add blkmap command

2023-02-16 Thread Tobias Waldekranz
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 00..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 

[PATCH v2 9/9] efi_loader: device_path: support blkmap devices

2023-02-16 Thread Tobias Waldekranz
Create a distinct EFI device path for each blkmap device.

Signed-off-by: Tobias Waldekranz 
---
 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 
 #include  /* U16_MAX */
 
+#ifdef CONFIG_BLKMAP
+const efi_guid_t efi_guid_blkmap_dev = U_BOOT_BLKMAP_DEV_GUID;
+#endif
 #ifdef CONFIG_SANDBOX
 const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
 #endif
@@ -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(>guid, _guid_blkmap_dev,
+  sizeof(efi_guid_t));
+   dp->vendor_data[0] = desc->devnum;
+   return >vendor_data[1];
+   }
+#endif
 #ifdef CONFIG_SANDBOX
case UCLASS_HOST: {
/* stop traversing parents at this point: */
-- 
2.34.1



[PATCH v2 3/9] blk: blkmap: Add basic infrastructure

2023-02-16 Thread Tobias Waldekranz
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 00..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
+*/
+

[PATCH v2 8/9] doc: blkmap: Add introduction and examples

2023-02-16 Thread Tobias Waldekranz
Explain block maps by going through two common use-cases.

Signed-off-by: Tobias Waldekranz 
---
 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 
 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 00..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 
+
+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



[PATCH v2 4/9] blk: blkmap: Add memory mapping support

2023-02-16 Thread Tobias Waldekranz
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, >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 me

[PATCH v2 7/9] test: blkmap: Add test suite

2023-02-16 Thread Tobias Waldekranz
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 
---
 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 
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 00..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 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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", ));
+   ut_assertok(blk_get_from_parent(dev, ));
+
+   /* 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", ));
+   ut_assertok(blk_get_from_parent(dev, ));
+
+   /* 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", ));
+
+   ut_assertok(blkmap_map_mem(dev, 8, 8, NULL));
+
+   /* Can't overlap on the l

[PATCH v2 2/9] cmd: blk: Allow generic read/write operations to work in sandbox

2023-02-16 Thread Tobias Waldekranz
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



[PATCH v2 5/9] blk: blkmap: Add linear device mapping support

2023-02-16 Thread Tobias Waldekranz
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, >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



[PATCH v2 0/9] blk: blkmap: Composable virtual block devices

2023-02-16 Thread Tobias Waldekranz
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 the kernel documentation [1] for more information.

The primary use-cases are to access filesystem images stored in RAM, and
within FIT images stored on disk. See doc/usage/blkmap.rst for more
details.

The architecture is pluggable, so adding other types of mappings should
be quite easy.

[1]: https://docs.kernel.org/admin-guide/device-mapper/index.html

v1 -> v2:
 - Change internal API to use device pointers
 - Convert test suite from Python to C
 - Various cosmetic fixes

Tobias Waldekranz (9):
  image: Fix script execution from FIT images with external data
  cmd: blk: Allow generic read/write operations to work in sandbox
  blk: blkmap: Add basic infrastructure
  blk: blkmap: Add memory mapping support
  blk: blkmap: Add linear device mapping support
  cmd: blkmap: Add blkmap command
  test: blkmap: Add test suite
  doc: blkmap: Add introduction and examples
  efi_loader: device_path: support blkmap devices

 MAINTAINERS  |   9 +
 boot/image-board.c   |   3 +-
 cmd/Kconfig  |  19 ++
 cmd/Makefile |   1 +
 cmd/blk_common.c |  15 +-
 cmd/blkmap.c | 233 ++
 configs/sandbox_defconfig|   1 +
 disk/part.c  |   1 +
 doc/usage/blkmap.rst | 111 +++
 doc/usage/index.rst  |   1 +
 drivers/block/Kconfig|  18 ++
 drivers/block/Makefile   |   1 +
 drivers/block/blk-uclass.c   |   1 +
 drivers/block/blkmap.c   | 519 +++
 include/blkmap.h |  77 +
 include/dm/uclass-id.h   |   1 +
 include/efi_loader.h |   4 +
 lib/efi_loader/efi_device_path.c |  30 ++
 test/dm/Makefile |   1 +
 test/dm/blkmap.c | 201 
 20 files changed, 1242 insertions(+), 5 deletions(-)
 create mode 100644 cmd/blkmap.c
 create mode 100644 doc/usage/blkmap.rst
 create mode 100644 drivers/block/blkmap.c
 create mode 100644 include/blkmap.h
 create mode 100644 test/dm/blkmap.c

-- 
2.34.1



[PATCH v2 1/9] image: Fix script execution from FIT images with external data

2023-02-16 Thread Tobias Waldekranz
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
@@ -,7 +,8 @@ fallback:
}
 
/* get script subimage data address and length */
-   if (fit_image_get_data(fit_hdr, noffset, _data, 
_len)) {
+   if (fit_image_get_data_and_size(fit_hdr, noffset,
+   _data, _len)) {
puts("Could not find script subimage data\n");
return 1;
}
-- 
2.34.1



Re: [PATCH 3/8] blk: blkmap: Add basic infrastructure

2023-02-07 Thread Tobias Waldekranz
On mån, feb 06, 2023 at 21:02, Simon Glass  wrote:
> Hi Tobias,
>
> On Mon, 6 Feb 2023 at 01:30, Tobias Waldekranz  wrote:
>>
>> On fre, feb 03, 2023 at 17:20, Simon Glass  wrote:
>> > Hi Tobias,
>> >
>> > On Fri, 3 Feb 2023 at 02:38, Tobias Waldekranz  
>> > wrote:
>> >>
>> >> On ons, feb 01, 2023 at 13:20, Simon Glass  wrote:
>> >> > Hi Tobias,
>> >>
>> >> Hi Simon,
>> >>
>> >> Thanks for the review!
>> >>
>> >> > On Wed, 1 Feb 2023 at 11:10, Tobias Waldekranz  
>> >> > wrote:
>> >> >>
>> >> >> 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 +
>> >> >>  disk/part.c  |   1 +
>> >> >>  drivers/block/Kconfig|  18 ++
>> >> >>  drivers/block/Makefile   |   1 +
>> >> >>  drivers/block/blk-uclass.c   |   1 +
>> >> >>  drivers/block/blkmap.c   | 275 +++
>> >> >>  include/blkmap.h |  15 ++
>> >> >>  include/dm/uclass-id.h   |   1 +
>> >> >>  include/efi_loader.h |   4 +
>> >> >>  lib/efi_loader/efi_device_path.c |  30 
>> >> >>  10 files changed, 352 insertions(+)
>> >> >>  create mode 100644 drivers/block/blkmap.c
>> >> >>  create mode 100644 include/blkmap.h
>> >> >>
>> >
>> > [..]
>> >
>> >> > This needs to be created as part of DM.  See how host_create_device()
>> >> > works. It attaches something to the uclass and then creates child
>> >> > devices from there. It also operations (struct host_ops) but you don't
>> >> > need to do that.
>> >> >
>> >> > Note that the host commands support either an label or a devnum, which
>> >> > I think is useful, so you might copy that?
>> >> >
>> >>
>> >> I took a look at the hostfs implementation. I agree that labels are much
>> >> nicer than bare integers. However, for block maps the idea is to fit in
>> >> to the existing filesystem infrastructure. Addressing block devices
>> >> using the " [:]" pattern seems very well
>> >> established...
>> >
>> > You can still do that, so long as the labels are "0" and "1", etc. But
>> > it lets us move to a more flexible system in future.
>> >
>> >>
>> >> >> +{
>> >> >> +   static struct udevice *dev;
>> >> >> +   int err;
>> >> >> +
>> >> >> +   if (dev)
>> >> >> +   return dev;
>> >> >> +
>> >> >> +   err = device_bind_driver(dm_root(), "blkmap_root", "blkmap", 
>> >> >> );
>> >> >> +   if (err)
>> >> >> +   return NULL;
>> >> >> +
>> >> >> +   err = device_probe(dev);
>> >> >> +   if (err) {
>> >> >> +   device_unbind(dev);
>> >> >> +   return NULL;
>> >> >> +   }
>> >> >
>> >> > Should not be needed as probing children will cause this to be probed.
>> >> >
>> >> > So this function just becomes
>> >> >
>> >> > uclass_first_device(UCLASS_BLKDEV, &
>> >> >
>> >> >> +
>> >> >> +   return dev;
>> >> >> +}
>> >> >> +
>> >> >> +int blkmap_create(int devnum)
>> >> >
>> >> > Again, please drop the use of devnum and use devices. Here you could
>> >> > use a label, perhaps?
>> >

Re: [PATCH 3/8] blk: blkmap: Add basic infrastructure

2023-02-06 Thread Tobias Waldekranz
On fre, feb 03, 2023 at 17:20, Simon Glass  wrote:
> Hi Tobias,
>
> On Fri, 3 Feb 2023 at 02:38, Tobias Waldekranz  wrote:
>>
>> On ons, feb 01, 2023 at 13:20, Simon Glass  wrote:
>> > Hi Tobias,
>>
>> Hi Simon,
>>
>> Thanks for the review!
>>
>> > On Wed, 1 Feb 2023 at 11:10, Tobias Waldekranz  
>> > wrote:
>> >>
>> >> 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 +
>> >>  disk/part.c  |   1 +
>> >>  drivers/block/Kconfig|  18 ++
>> >>  drivers/block/Makefile   |   1 +
>> >>  drivers/block/blk-uclass.c   |   1 +
>> >>  drivers/block/blkmap.c   | 275 +++
>> >>  include/blkmap.h |  15 ++
>> >>  include/dm/uclass-id.h   |   1 +
>> >>  include/efi_loader.h |   4 +
>> >>  lib/efi_loader/efi_device_path.c |  30 
>> >>  10 files changed, 352 insertions(+)
>> >>  create mode 100644 drivers/block/blkmap.c
>> >>  create mode 100644 include/blkmap.h
>> >>
>
> [..]
>
>> > This needs to be created as part of DM.  See how host_create_device()
>> > works. It attaches something to the uclass and then creates child
>> > devices from there. It also operations (struct host_ops) but you don't
>> > need to do that.
>> >
>> > Note that the host commands support either an label or a devnum, which
>> > I think is useful, so you might copy that?
>> >
>>
>> I took a look at the hostfs implementation. I agree that labels are much
>> nicer than bare integers. However, for block maps the idea is to fit in
>> to the existing filesystem infrastructure. Addressing block devices
>> using the " [:]" pattern seems very well
>> established...
>
> You can still do that, so long as the labels are "0" and "1", etc. But
> it lets us move to a more flexible system in future.
>
>>
>> >> +{
>> >> +   static struct udevice *dev;
>> >> +   int err;
>> >> +
>> >> +   if (dev)
>> >> +   return dev;
>> >> +
>> >> +   err = device_bind_driver(dm_root(), "blkmap_root", "blkmap", 
>> >> );
>> >> +   if (err)
>> >> +   return NULL;
>> >> +
>> >> +   err = device_probe(dev);
>> >> +   if (err) {
>> >> +   device_unbind(dev);
>> >> +   return NULL;
>> >> +   }
>> >
>> > Should not be needed as probing children will cause this to be probed.
>> >
>> > So this function just becomes
>> >
>> > uclass_first_device(UCLASS_BLKDEV, &
>> >
>> >> +
>> >> +   return dev;
>> >> +}
>> >> +
>> >> +int blkmap_create(int devnum)
>> >
>> > Again, please drop the use of devnum and use devices. Here you could
>> > use a label, perhaps?
>>
>> ...which is why I don't think a label is going to fly here. Let's say I
>> create a new ramdisk with a label instead, e.g.:
>>
>> blkmap create rd
>> blkmap map rd 0 0x100 mem ${loadaddr}
>>
>> How do I know which  to supply to, e.g.:
>>
>> ls blkmap  /boot
>>
>> It seems like labels are a hostfs-specific feature, or am I missing
>> something?
>
> We have the same problem with hostfs, since we have not implemented
> labels in block devices. For now you must use integer labels. But we
> will get there.

But there is no connection to the devnum that is allocated internally by
U-Boot. Here's an experiment I just ran:

I created two squashfs images containing a single directory:

zero.squashfs:
 i_am_zero

one.squashfs:
 i_am_one

Then I added a binding to them:

=> host bind 1 one.squashfs
=> host bind 0 zero.squashfs

When accessing them, we see that the e

Re: [PATCH 3/8] blk: blkmap: Add basic infrastructure

2023-02-03 Thread Tobias Waldekranz
On ons, feb 01, 2023 at 13:20, Simon Glass  wrote:
> Hi Tobias,

Hi Simon,

Thanks for the review!

> On Wed, 1 Feb 2023 at 11:10, Tobias Waldekranz  wrote:
>>
>> 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 +
>>  disk/part.c  |   1 +
>>  drivers/block/Kconfig|  18 ++
>>  drivers/block/Makefile   |   1 +
>>  drivers/block/blk-uclass.c   |   1 +
>>  drivers/block/blkmap.c   | 275 +++
>>  include/blkmap.h |  15 ++
>>  include/dm/uclass-id.h   |   1 +
>>  include/efi_loader.h |   4 +
>>  lib/efi_loader/efi_device_path.c |  30 
>>  10 files changed, 352 insertions(+)
>>  create mode 100644 drivers/block/blkmap.c
>>  create mode 100644 include/blkmap.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 3e8e193ecc..28a34231bf 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -786,6 +786,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/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,
>> 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_BLKMA

[PATCH 8/8] doc: blkmap: Add introduction and examples

2023-02-01 Thread Tobias Waldekranz
Explain block maps by going through two common use-cases.

Signed-off-by: Tobias Waldekranz 
---
 MAINTAINERS  |   1 +
 doc/usage/blkmap.rst | 109 +++
 doc/usage/index.rst  |   1 +
 3 files changed, 111 insertions(+)
 create mode 100644 doc/usage/blkmap.rst

diff --git a/MAINTAINERS b/MAINTAINERS
index c420c8e1f9..de0e41487d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -790,6 +790,7 @@ BLKMAP
 M: Tobias Waldekranz 
 S: Maintained
 F: cmd/blkmap.c
+F: doc/usage/blkmap.rst
 F: drivers/block/blkmap.c
 F: include/blkmap.h
 F: test/py/tests/test_blkmap.py
diff --git a/doc/usage/blkmap.rst b/doc/usage/blkmap.rst
new file mode 100644
index 00..1cf6d97c1b
--- /dev/null
+++ b/doc/usage/blkmap.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0+
+..
+.. Copyright (c) 2023 Addiva Elektronik
+.. Author: Tobias Waldekranz 
+
+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 0
+
+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 0 0 ${fileblks} mem ${fileaddr}
+
+Now we can access the filesystem via the virtual device:
+
+::
+
+   load blkmap 0 ${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 0
+   blkmap map 0 0 ${squashsize} linear mmc 0 ${squashblk}
+
+Now we can access the filesystem:
+
+::
+
+   load blkmap 0 ${loadaddr} /etc/version
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 3804046835..856a3da28e 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



[PATCH 7/8] test: blkmap: Add test suite

2023-02-01 Thread Tobias Waldekranz
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 
---
 MAINTAINERS  |   1 +
 configs/sandbox_defconfig|   1 +
 test/py/tests/test_blkmap.py | 164 +++
 3 files changed, 166 insertions(+)
 create mode 100644 test/py/tests/test_blkmap.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 83c0f90a53..c420c8e1f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -792,6 +792,7 @@ S:  Maintained
 F: cmd/blkmap.c
 F: drivers/block/blkmap.c
 F: include/blkmap.h
+F: test/py/tests/test_blkmap.py
 
 BOOTDEVICE
 M: Simon Glass 
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/py/tests/test_blkmap.py b/test/py/tests/test_blkmap.py
new file mode 100644
index 00..5a4c770c81
--- /dev/null
+++ b/test/py/tests/test_blkmap.py
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier:  GPL-2.0+
+#
+# Copyright (c) 2023 Addiva Elektronik
+# Author: Tobias Waldekranz 
+
+""" Unit test for blkmap command
+"""
+
+import pytest
+
+BLKSZ = 0x200
+
+MAPPING = [
+((0, 1), 3),
+((1, 3), 0),
+((4, 2), 6),
+((6, 2), 4),
+]
+
+ORDERED   = 0x
+UNORDERED = 0x1000
+BUFFER= 0x2000
+
+def mkblob(base, mapping):
+cmds = []
+
+for ((blksrc, blkcnt), blkdst) in mapping:
+for blknr in range(blkcnt):
+cmds.append(f"mw.b 0x{base + (blkdst + blknr) * BLKSZ:x}" +
+f" 0x{blksrc + blknr:x} 0x{BLKSZ:x}")
+return cmds
+
+class Blkmap(object):
+def __init__(self, console, num):
+self.console, self.num = console, num
+
+def __enter__(self):
+r = self.console.run_command(f"blkmap create {self.num}")
+assert(f"Created device {self.num}" in r)
+
+r = self.console.run_command(f"blkmap dev {self.num}")
+assert("is now current device" in r)
+
+return self
+
+def __exit__(self, typ, value, traceback):
+r = self.console.run_command(f"blkmap destroy {self.num}")
+assert(f"Destroyed device {self.num}" in r)
+
+def map_mem(self, blknr, blkcnt, addr):
+r = self.console.run_command(
+f"blkmap map {self.num} {blknr:#x} {blkcnt:#x} mem {addr:#x}"
+)
+assert(" mapped to " in r)
+
+def read(self, addr, blknr, blkcnt):
+r = self.console.run_command(
+f"blkmap read {addr:#x} {blknr:#x} {blkcnt:#x}"
+)
+assert(" OK" in r)
+
+def write(self, addr, blknr, blkcnt):
+r = self.console.run_command(
+f"blkmap write {addr:#x} {blknr:#x} {blkcnt:#x}"
+)
+assert(" OK" in r)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_blkmap')
+def test_blkmap_creation(u_boot_console):
+""" Verify that blkmaps can be created and destroyed
+
+Args:
+u_boot_console -- U-Boot console
+"""
+with Blkmap(u_boot_console, 0):
+# Can't have 2 blkmap 0's
+with pytest.raises(AssertionError):
+with Blkmap(u_boot_console, 0):
+pass
+
+# But blkmap 1 should be fine
+with Blkmap(u_boot_console, 1):
+pass
+
+# Once blkmap 0 is destroyed, we should be able to create it again
+with Blkmap(u_boot_console, 0):
+pass
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_blkmap')
+def test_blkmap_slicing(u_boot_console):
+""" Verify that slices aren't allowed to overlap
+
+Args:
+u_boot_console -- U-Boot console
+"""
+with Blkmap(u_boot_console, 0) as bm:
+bm.map_mem(8, 8, 0)
+
+# Can't overlap on the low end
+with pytest.raises(AssertionError):
+bm.map_mem(4, 5, 0)
+
+# Can't be inside
+with pytest.raises(AssertionError):
+bm.map_mem(10, 2, 0)
+
+# Can't overlap on the high end
+with pytest.raises(AssertionError):
+bm.map_mem(15, 4, 0)
+
+# But we should be able to add slices right before and after
+bm.map_mem( 4, 4, 0)
+bm.map_mem(16, 4, 0)
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('cmd_blkmap')
+def test_blkmap_mem_read(u_boot_console):
+""" Test reading from a memory backed blkmap
+
+Args:
+u_boot_console -- U-Boot console
+"""
+
+# G

[PATCH 6/8] cmd: blkmap: Add blkmap command

2023-02-01 Thread Tobias Waldekranz
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 | 181 +++
 4 files changed, 202 insertions(+)
 create mode 100644 cmd/blkmap.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 28a34231bf..83c0f90a53 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -789,6 +789,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 dc0446e02e..cd35b8318d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1953,6 +1953,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 7b6ff73186..1d51fddec1 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 00..f1d4a4bab0
--- /dev/null
+++ b/cmd/blkmap.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Addiva Elektronik
+ * Author: Tobias Waldekranz 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int blkmap_curr_dev;
+
+struct map_ctx {
+   int devnum;
+   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->devnum, ctx->blknr, ctx->blkcnt,
+   lbd->uclass_id, ldevnum, 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->devnum, ctx->blknr, ctx->blkcnt, addr);
+   if (err) {
+   printf("Unable to map %#llx at block 0x"

[PATCH 5/8] blk: blkmap: Add linear device mapping support

2023-02-01 Thread Tobias Waldekranz
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   |  2 ++
 2 files changed, 73 insertions(+)

diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index c8c2dcac11..14d2ec3f78 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -94,6 +94,77 @@ static int blkmap_add(struct blkmap *bm, struct blkmap_slice 
*new)
return 0;
 }
 
+struct blkmap_linear {
+   struct blkmap_slice slice;
+
+   struct blk_desc *bd;
+   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_dread(bml->bd, 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_dwrite(bml->bd, bml->blknr + blknr, blkcnt, buffer);
+}
+
+int blkmap_map_linear(int devnum, lbaint_t blknr, lbaint_t blkcnt,
+ enum uclass_id lcls, int ldevnum, lbaint_t lblknr)
+{
+   struct blkmap_linear *linear;
+   struct blk_desc *bd, *lbd;
+   struct blkmap *bm;
+   int err;
+
+   bm = blkmap_from_devnum(devnum);
+   if (!bm)
+   return -ENODEV;
+
+   bd = dev_get_uclass_plat(bm->dev);
+   lbd = blk_get_devnum_by_uclass_id(lcls, ldevnum);
+   if (!lbd)
+   return -ENODEV;
+
+   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,
+   },
+
+   .bd = lbd,
+   .blknr = lblknr,
+   };
+
+   err = blkmap_add(bm, >slice);
+   if (err)
+   free(linear);
+
+   return err;
+}
+
 struct blkmap_mem {
struct blkmap_slice slice;
void *addr;
diff --git a/include/blkmap.h b/include/blkmap.h
index a93611ff62..dca6e3fe6a 100644
--- a/include/blkmap.h
+++ b/include/blkmap.h
@@ -9,6 +9,8 @@
 
 #include 
 
+int blkmap_map_linear(int devnum, lbaint_t blknr, lbaint_t blkcnt,
+ enum uclass_id lcls, int ldevnum, lbaint_t lblknr);
 int blkmap_map_mem(int devnum, lbaint_t blknr, lbaint_t blkcnt, void *addr);
 int blkmap_map_pmem(int devnum, lbaint_t blknr, lbaint_t blkcnt,
phys_addr_t paddr);
-- 
2.34.1



[PATCH 4/8] blk: blkmap: Add memory mapping support

2023-02-01 Thread Tobias Waldekranz
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 | 106 +
 include/blkmap.h   |   4 ++
 2 files changed, 110 insertions(+)

diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index a6ba07404c..c8c2dcac11 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 struct blkmap;
@@ -93,6 +94,111 @@ static int blkmap_add(struct blkmap *bm, struct 
blkmap_slice *new)
return 0;
 }
 
+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->dev);
+   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->dev);
+   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(int devnum, lbaint_t blknr, lbaint_t blkcnt, void *addr,
+bool remapped)
+{
+   struct blkmap_mem *bmm;
+   struct blkmap *bm;
+   int err;
+
+   bm = blkmap_from_devnum(devnum);
+   if (!bm)
+   return -ENODEV;
+
+   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_add(bm, >slice);
+   if (err)
+   free(bmm);
+
+   return err;
+}
+
+int blkmap_map_mem(int devnum, lbaint_t blknr, lbaint_t blkcnt, void *addr)
+{
+   return __blkmap_map_mem(devnum, blknr, blkcnt, addr, false);
+}
+
+int blkmap_map_pmem(int devnum, lbaint_t blknr, lbaint_t blkcnt,
+   phys_addr_t paddr)
+{
+   struct blk_desc *bd;
+   struct blkmap *bm;
+   void *addr;
+   int err;
+
+   bm = blkmap_from_devnum(devnum);
+   if (!bm)
+   return -ENODEV;
+
+   bd = dev_get_uclass_plat(bm->dev);
+
+   addr = map_sysmem(paddr, blkcnt << bd->log2blksz);
+   if (!addr)
+   return -ENOMEM;
+
+   err = __blkmap_map_mem(devnum, blknr, blkcnt, addr, true);
+   if (err)
+   unmap_sysmem(addr);
+
+   return err;
+}
+
 static struct udevice *blkmap_root(void)
 {
static struct udevice *dev;
diff --git a/include/blkmap.h b/include/blkmap.h
index 37c0c31c3f..a93611ff62 100644
--- a/include/blkmap.h
+++ b/include/blkmap.h
@@ -9,6 +9,10 @@
 
 #include 
 
+int blkmap_map_mem(int devnum, lbaint_t blknr, lbaint_t blkcnt, void *addr);
+int blkmap_map_pmem(int devnum, lbaint_t blknr, lbaint_t blkcnt,
+   phys_addr_t paddr);
+
 int blkmap_create(int devnum);
 int blkmap_destroy(int devnum);
 
-- 
2.34.1



[PATCH 3/8] blk: blkmap: Add basic infrastructure

2023-02-01 Thread Tobias Waldekranz
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 +
 disk/part.c  |   1 +
 drivers/block/Kconfig|  18 ++
 drivers/block/Makefile   |   1 +
 drivers/block/blk-uclass.c   |   1 +
 drivers/block/blkmap.c   | 275 +++
 include/blkmap.h |  15 ++
 include/dm/uclass-id.h   |   1 +
 include/efi_loader.h |   4 +
 lib/efi_loader/efi_device_path.c |  30 
 10 files changed, 352 insertions(+)
 create mode 100644 drivers/block/blkmap.c
 create mode 100644 include/blkmap.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 3e8e193ecc..28a34231bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -786,6 +786,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/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,
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 00..a6ba07404c
--- /dev/null
+++ b/drivers/block/blkmap.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Addiva Elektronik
+ * Author: Tobias Waldekranz 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct blkmap;
+
+struct blkmap_slice {
+   struct list_head node;
+
+   lbaint_t blknr;
+   lbaint_t blkcnt;
+
+   ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms,
+ lbaint_t blknr, lbaint_t blkcnt, void *buffer);
+   ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms,
+  lbaint_t blknr, lbaint_t blkcnt, const void *buffer);
+   void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
+};
+
+struct blkmap {
+   struct udevice *dev;
+   struct list_head slices;
+};
+
+static bool blkmap_slice_contains(struct blkmap_slice *b

[PATCH 2/8] cmd: blk: Allow generic read/write operations to work in sandbox

2023-02-01 Thread Tobias Waldekranz
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 
---
 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



[PATCH 1/8] image: Fix script execution from FIT images with external data

2023-02-01 Thread Tobias Waldekranz
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 
---
 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 e5d71a3d54..74b2ad3580 100644
--- a/boot/image-board.c
+++ b/boot/image-board.c
@@ -,7 +,8 @@ fallback:
}
 
/* get script subimage data address and length */
-   if (fit_image_get_data(fit_hdr, noffset, _data, 
_len)) {
+   if (fit_image_get_data_and_size(fit_hdr, noffset,
+   _data, _len)) {
puts("Could not find script subimage data\n");
return 1;
}
-- 
2.34.1



[PATCH 0/8] blk: blkmap: Composable virtual block devices

2023-02-01 Thread Tobias Waldekranz
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 the kernel documentation [1] for more information.

The primary use-cases are to access filesystem images stored in RAM, and
within FIT images stored on disk. See doc/usage/blkmap.rst for more
details.

The architecture is pluggable, so adding other types of mappings should
be quite easy.

[1]: https://docs.kernel.org/admin-guide/device-mapper/index.html

Tobias Waldekranz (8):
  image: Fix script execution from FIT images with external data
  cmd: blk: Allow generic read/write operations to work in sandbox
  blk: blkmap: Add basic infrastructure
  blk: blkmap: Add memory mapping support
  blk: blkmap: Add linear device mapping support
  cmd: blkmap: Add blkmap command
  test: blkmap: Add test suite
  doc: blkmap: Add introduction and examples

 MAINTAINERS  |   9 +
 boot/image-board.c   |   3 +-
 cmd/Kconfig  |  19 ++
 cmd/Makefile |   1 +
 cmd/blk_common.c |  15 +-
 cmd/blkmap.c | 181 +
 configs/sandbox_defconfig|   1 +
 disk/part.c  |   1 +
 doc/usage/blkmap.rst | 109 
 doc/usage/index.rst  |   1 +
 drivers/block/Kconfig|  18 ++
 drivers/block/Makefile   |   1 +
 drivers/block/blk-uclass.c   |   1 +
 drivers/block/blkmap.c   | 452 +++
 include/blkmap.h |  21 ++
 include/dm/uclass-id.h   |   1 +
 include/efi_loader.h |   4 +
 lib/efi_loader/efi_device_path.c |  30 ++
 test/py/tests/test_blkmap.py | 164 +++
 19 files changed, 1027 insertions(+), 5 deletions(-)
 create mode 100644 cmd/blkmap.c
 create mode 100644 doc/usage/blkmap.rst
 create mode 100644 drivers/block/blkmap.c
 create mode 100644 include/blkmap.h
 create mode 100644 test/py/tests/test_blkmap.py

-- 
2.34.1



Re: [U-Boot] Hi

2010-09-03 Thread Tobias Waldekranz (Knutsson)
Did you download the version from hawkboard.org?

In that case, you should be able to follow the instructions on:

http://elinux.org/Hawkboard#Compiling_u-boot_.28bootloader.29

If you are using the git version of u-boot replace
omapl_hawkboard_config with da850evm_config and try to boot that
first. Then as a second step, you can add custom board support for the
Hawkboard.

On Thu, Sep 2, 2010 at 15:45, Vaishali Dhakate
vaishali.dhak...@sukrutsystems.com wrote:
 Hi
 Tobias thank you for the reply ...
 I am using Fedora so I downloaded this ARM Toolchain.

 http://fedoraproject.org/wiki/Architectures/ARM/CrossToolchain

 Installed this toolchain successfully and able to cross compile code for 
 ARM...

 I downloaded u-boot source code ,extracted it... Now want to compile
 this source code using this ARM Toolchain that I installed 

 http://www.linuxfordevices.com/c/a/Linux-For-Devices-Articles/Introduction-to-Das-UBoot-the-universal-open-source-bootloader/

 Now trying to figure out this using the above document... Not very
 clear... as to how to do this ... will read the README of u-boot ..
 Let me know !
 Thanks and Regards
 Vaishali

 On 9/1/10, Tobias Waldekranz (Knutsson) tobias.knuts...@gmail.com wrote:
 You can find the official port of u-boot for the Hawkboard over at
 hawkboard.org, but if you want to build the latest version of u-boot
 that can be done as well.

 The Hawkboard is very similar to the DA850 EVM so as a first step, you
 could simply build u-boot for that board and it should boot just fine.


 On Tue, Aug 31, 2010 at 13:19, Vaishali Dhakate
 vaishali.dhak...@sukrutsystems.com wrote:
 Hi ,
 I am trying to cross compile some libraries for ARM board
 I will port a Linux OS to the hawkboard.
 Want to study u-boot specific to this board so I ll be able to do
 this. The first chore is to port u-boot on this board.
 PLz help me , I was going through the uboot readme which directed me
 to straight away mail and share my concern.
 Thanks for the help
 Regards
 Vaishali
 ___
 U-Boot mailing list
 U-Boot@lists.denx.de
 http://lists.denx.de/mailman/listinfo/u-boot




 --

 Hälsningar/Regards
 Tobias Waldekranz





-- 

Hälsningar/Regards
Tobias Waldekranz
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot