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

