summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-03-26 14:07:09 -0600
committerTom Rini <[email protected]>2025-03-26 14:07:09 -0600
commitdf11ac859d366d96f749f2b9c3d2d5c564b325bc (patch)
tree7f22d24b51d695d43fce63b6a2ebcda582399a16 /drivers
parentb052de94fa14577cb5d9e724edeb09fee674d582 (diff)
parent61e0a20aecf4af6cdc223bd8cd1bd82fe5e3d9f6 (diff)
Merge tag 'efi-next-26032025' of https://source.denx.de/u-boot/custodians/u-boot-tpm into next
When trying to boot an OS installer or a live image via EFI HTTP the following happens - U-Boot downloads the image and mounts it in memory - The EFI subsystem is invoked and the image is started - The OS calls ExitBootServices and the memory that holds the mounted image might get overwritten This results in installers complaining that they can't find installer medium or live images complaining they can't find the root filesystem. ACPI already deals with it by having NFIT and NVDIMM to provide ramdisks that need to be preserved by the OS. Linux and device trees have support for persistent memory devices (pmem). We can use them and inject a pmem node in the DT to preserve memory across the entire boot sequence. Linux will just create a block device over the reserved memory and installers/images can re-discover it. This is what it looks like from the OS perspective: nd_pmem namespace0.0: unable to guarantee persistence of writes pmem0: p1 p2 p3 EXT4-fs (pmem0p3): mounted filesystem f40f64a4-5b41-4828-856e-caaae2c1c2a0 r/w with ordered data mode. Quota mode: disabled. EXT4-fs (pmem0p3): re-mounted f40f64a4-5b41-4828-856e-caaae2c1c2a0 r/w. Quota mode: disabled. Adding 45052k swap on /dev/pmem0p2. Priority:-2 extents:1 across:45052k SS root@genericarm64:~# mount | grep pmem /dev/pmem0p3 on / type ext4 (rw,relatime) /dev/pmem0p1 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro) It's worth noting that Linux behaves differently with reserved memory (at least on arm64) and that depends on kernel config options. CONFIG_ZONE_DEVICES and CONFIG_ARM64_PMEM are such options. It boils down to how the kernel tries to map pages. If devm_memremap_pages() gets called instead of devm_memremap() mapping the memory fails. The only safe way is to remove the memory from the EFI memory map, rather than defining it as /reserved no-map;/ in the DT.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/blkmap.c82
-rw-r--r--drivers/block/blkmap_helper.c2
2 files changed, 79 insertions, 5 deletions
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index 34eed1380dc..473c65b5911 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -17,6 +17,30 @@
struct blkmap;
/**
+ * define BLKMAP_SLICE_LINEAR - Linear mapping to another block device
+ *
+ * This blkmap slice type is used for mapping to other existing block
+ * devices.
+ */
+#define BLKMAP_SLICE_LINEAR BIT(0)
+
+/**
+ * define BLKMAP_SLICE_MEM - Linear mapping to memory based block device
+ *
+ * This blkmap slice type is used for mapping to memory based block
+ * devices, like ramdisks.
+ */
+#define BLKMAP_SLICE_MEM BIT(1)
+
+/**
+ * define BLKMAP_SLICE_PRESERVE - Preserved blkmap slice
+ *
+ * This blkmap slice is intended to be preserved, and it's
+ * information passed on to a later stage, like OS.
+ */
+#define BLKMAP_SLICE_PRESERVE BIT(2)
+
+/**
* struct blkmap_slice - Region mapped to a blkmap
*
* Common data for a region mapped to a blkmap, specialized by each
@@ -25,12 +49,14 @@ struct blkmap;
* @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
+ * @attr: Attributes of blkmap slice
*/
struct blkmap_slice {
struct list_head node;
lbaint_t blknr;
lbaint_t blkcnt;
+ uint attr;
/**
* @read: - Read from slice
@@ -169,6 +195,7 @@ int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.slice = {
.blknr = blknr,
.blkcnt = blkcnt,
+ .attr = BLKMAP_SLICE_LINEAR,
.read = blkmap_linear_read,
.write = blkmap_linear_write,
@@ -234,7 +261,7 @@ static void blkmap_mem_destroy(struct blkmap *bm, struct blkmap_slice *bms)
}
int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
- void *addr, bool remapped)
+ void *addr, bool remapped, bool preserve)
{
struct blkmap *bm = dev_get_plat(dev);
struct blkmap_mem *bmm;
@@ -248,6 +275,7 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.slice = {
.blknr = blknr,
.blkcnt = blkcnt,
+ .attr = BLKMAP_SLICE_MEM,
.read = blkmap_mem_read,
.write = blkmap_mem_write,
@@ -258,6 +286,9 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.remapped = remapped,
};
+ if (preserve)
+ bmm->slice.attr |= BLKMAP_SLICE_PRESERVE;
+
err = blkmap_slice_add(bm, &bmm->slice);
if (err)
free(bmm);
@@ -268,11 +299,11 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *addr)
{
- return __blkmap_map_mem(dev, blknr, blkcnt, addr, false);
+ return __blkmap_map_mem(dev, blknr, blkcnt, addr, false, false);
}
int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
- phys_addr_t paddr)
+ phys_addr_t paddr, bool preserve)
{
struct blkmap *bm = dev_get_plat(dev);
struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
@@ -283,7 +314,7 @@ int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
if (!addr)
return -ENOMEM;
- err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true);
+ err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true, preserve);
if (err)
unmap_sysmem(addr);
@@ -486,6 +517,49 @@ err:
return err;
}
+static bool blkmap_mem_preserve_slice(struct blkmap_slice *bms)
+{
+ return (bms->attr & (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE)) ==
+ (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE);
+}
+
+int blkmap_get_preserved_pmem_slices(int (*cb)(void *ctx, u64 addr,
+ u64 size), void *ctx)
+{
+ int ret;
+ u64 addr, size;
+ struct udevice *dev;
+ struct uclass *uc;
+ struct blkmap *bm;
+ struct blkmap_mem *bmm;
+ struct blkmap_slice *bms;
+ struct blk_desc *bd;
+
+ if (!cb) {
+ log_debug("%s: No callback passed to the function\n", __func__);
+ return 0;
+ }
+
+ uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) {
+ bm = dev_get_plat(dev);
+ bd = dev_get_uclass_plat(bm->blk);
+
+ list_for_each_entry(bms, &bm->slices, node) {
+ if (!blkmap_mem_preserve_slice(bms))
+ continue;
+
+ bmm = container_of(bms, struct blkmap_mem, slice);
+ addr = (u64)(uintptr_t)bmm->addr;
+ size = (u64)bms->blkcnt << bd->log2blksz;
+ ret = cb(ctx, addr, size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int blkmap_destroy(struct udevice *dev)
{
int err;
diff --git a/drivers/block/blkmap_helper.c b/drivers/block/blkmap_helper.c
index bfba14110d2..2f1bc28ee5d 100644
--- a/drivers/block/blkmap_helper.c
+++ b/drivers/block/blkmap_helper.c
@@ -28,7 +28,7 @@ int blkmap_create_ramdisk(const char *label, ulong image_addr, ulong image_size,
bm = dev_get_plat(bm_dev);
desc = dev_get_uclass_plat(bm->blk);
blknum = image_size >> desc->log2blksz;
- ret = blkmap_map_pmem(bm_dev, 0, blknum, image_addr);
+ ret = blkmap_map_pmem(bm_dev, 0, blknum, image_addr, true);
if (ret) {
log_err("Unable to map %#llx at block %d : %d\n",
(unsigned long long)image_addr, 0, ret);