[PATCHv2 1/5] lmb: add LMB_FDT for fdt reserved regions

rs
2026-04-02T20:51:29Z

Add an LMB_FDT bit for fdt reserved regions, so we can reclaim them when
parsing a new device tree and properly warn people when a reservation
overlaps with an existing allocation.

If we don't at least warn the user of these reservation failures,
there's a chance that this region could be freed and reallocated for
something important later.

This useful warning mechanism was broken in:
5a6aa7d5913 ("boot: fdt: Handle already reserved memory in boot_fdt_reserve_region()")

Signed-off-by: Randolph Sapp <rs@ti.com>
---
boot/image-fdt.c | 5 ++++-
include/lmb.h | 7 +++++++
lib/lmb.c | 25 +++++++++++++++++++++++++
3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index a3a4fb8b558..0f5857f24d2 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -73,6 +73,7 @@ static void boot_fdt_reserve_region(u64 addr, u64 size, u32 flags)
{
long ret;
phys_addr_t rsv_addr;
+ flags |= LMB_FDT;

rsv_addr = (phys_addr_t)addr;
ret = lmb_alloc_mem(LMB_MEM_ALLOC_ADDR, 0, &rsv_addr, size, flags);
@@ -80,7 +81,7 @@ static void boot_fdt_reserve_region(u64 addr, u64 size, u32 flags)
debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n",
(unsigned long long)addr,
(unsigned long long)size, flags);
- } else if (ret != -EEXIST && ret != -EINVAL) {
+ } else if (ret != -EINVAL) {
puts("ERROR: reserving fdt memory region failed ");
printf("(addr=%llx size=%llx flags=%x)\n",
(unsigned long long)addr,
@@ -108,6 +109,8 @@ void boot_fdt_add_mem_rsv_regions(void *fdt_blob)
if (fdt_check_header(fdt_blob) != 0)
return;

+ lmb_free_fdt_regions();
+
/* process memreserve sections */
total = fdt_num_mem_rsv(fdt_blob);
for (i = 0; i < total; i++) {
diff --git a/include/lmb.h b/include/lmb.h
index 5d5f037ccb9..1b59a63f61d 100644
--- a/include/lmb.h
+++ b/include/lmb.h
@@ -25,11 +25,13 @@
* %LMB_NOMAP: Don't add to MMU configuration
* %LMB_NOOVERWRITE: The memory region cannot be overwritten/re-reserved
* %LMB_NONOTIFY: Do not notify other modules of changes to this memory region
+ * %LMB_FDT: A FDT reserved region that can be reclaimed if the FDT changes
*/
#define LMB_NONE 0
#define LMB_NOMAP BIT(1)
#define LMB_NOOVERWRITE BIT(2)
#define LMB_NONOTIFY BIT(3)
+#define LMB_FDT BIT(4)

/**
* enum lmb_mem_type - type of memory allocation request
@@ -215,6 +217,11 @@ phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
*/
long io_lmb_free(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);

+/**
+ * lmb_free_fdt_regions() - Reclaim all LMB_FDT tagged reserved regions
+ */
+void lmb_free_fdt_regions(void);
+
#endif /* __KERNEL__ */

#endif /* _LINUX_LMB_H */
diff --git a/lib/lmb.c b/lib/lmb.c
index e2d9fe86c14..18703212afb 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -669,6 +669,31 @@ long lmb_free(phys_addr_t base, phys_size_t size, u32 flags)
return lmb_map_update_notify(base, size, LMB_MAP_OP_FREE, flags);
}

+void lmb_free_fdt_regions(void)
+{
+ struct alist *lmb_rgn_lst = &lmb.used_mem;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+ long ret;
+ int i = 0;
+
+ while (i < lmb_rgn_lst->count) {
+ phys_addr_t base = rgn[i].base;
+ phys_size_t size = rgn[i].size;
+ u32 flags = rgn[i].flags;
+
+ if (flags & LMB_FDT) {
+ ret = lmb_free(base, size, flags);
+ if (ret < 0) {
+ printf("Unable to free FDT memory at 0x%08lx",
+ (ulong)base);
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+}
+
static int _lmb_alloc_base(phys_size_t size, ulong align,
phys_addr_t *addr, u32 flags)
{
--
2.53.0