There are events that would be used to notify other interested modules
of any changes in available and occupied memory. This would happen
when a module allocates or reserves memory, or frees up memory. These
changes in memory map should be notified to other interested modules
so that the allocated memory does not get overwritten. Add an event
handler in the LMB module to update it's memory map accordingly when
such changes happen. As a consequence, any subsequent memory request
would honour the updated memory map and allocations would only happen
from available memory.

Signed-off-by: Sughosh Ganu <sughosh.g...@linaro.org>
---
 lib/Kconfig |  1 +
 lib/lmb.c   | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/lib/Kconfig b/lib/Kconfig
index 9ea02ae006..9e465a748b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -1111,6 +1111,7 @@ config LMB
        bool "Enable the logical memory blocks library (lmb)"
        default y if ARC || ARM || M68K || MICROBLAZE || MIPS || \
                     NIOS2 || PPC || RISCV || SANDBOX || SH || X86 || XTENSA
+       select EVENT
        help
          Support the library logical memory blocks.
 
diff --git a/lib/lmb.c b/lib/lmb.c
index 313735dbe3..3059609aea 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -16,6 +16,7 @@
 
 #include <asm/global_data.h>
 #include <asm/sections.h>
+#include <asm-generic/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -719,3 +720,36 @@ __weak void arch_lmb_reserve(void)
 {
        /* please define platform specific arch_lmb_reserve() */
 }
+
+#if CONFIG_IS_ENABLED(MEM_MAP_UPDATE_NOTIFY)
+static long lmb_reserve_nooverwrite(phys_addr_t base, phys_size_t size)
+{
+       struct lmb_region *_rgn = &lmb.reserved;
+
+       return lmb_add_region_flags(_rgn, base, size, LMB_NOOVERWRITE);
+}
+
+static int efi_mem_map_update_sync(void *ctx, struct event *event)
+{
+       u8 op;
+       long ret;
+       phys_addr_t addr;
+       phys_size_t size;
+       struct event_efi_mem_map_update *efi_map = &event->data.efi_mem_map;
+
+       addr = virt_to_phys((void *)(uintptr_t)efi_map->base);
+       size = efi_map->size;
+       op = efi_map->op;
+
+       if (op != MAP_OP_RESERVE && op != MAP_OP_FREE) {
+               log_debug("Invalid map update op received (%d)\n", op);
+               return -1;
+       }
+
+       ret = op == MAP_OP_RESERVE ? lmb_reserve_nooverwrite(addr, size) :
+               __lmb_free(addr, size);
+
+       return !ret ? 0 : -1;
+}
+EVENT_SPY_FULL(EVT_EFI_MEM_MAP_UPDATE, efi_mem_map_update_sync);
+#endif /* MEM_MAP_UPDATE_NOTIFY */
-- 
2.34.1

Reply via email to