uint32_t *descriptor_version);
/* Adds a range into the EFI memory map */
efi_status_t efi_add_memory_map(u64 start, u64 size, int memory_type);
+
+/**
+ * efi_add_memory_map_pg() - add pages to the memory map
+ *
+ * @start: start address, must be a multiple of EFI_PAGE_SIZE
+ * @pages: number of pages to add
+ * @memory_type: type of memory added
+ * @overlap_only_ram: region may only overlap RAM
+ * Return: status code
+ */
+efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
+ int memory_type,
+ bool overlap_only_ram);
+
/* Adds a conventional range into the EFI memory map */
efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
u64 ram_top);
#include <alist.h>
#include <efi_loader.h>
+#include <event.h>
#include <image.h>
#include <mapmem.h>
#include <lmb.h>
DECLARE_GLOBAL_DATA_PTR;
+#define MAP_OP_RESERVE (u8)0x1
+#define MAP_OP_FREE (u8)0x2
+#define MAP_OP_ADD (u8)0x3
+
#define LMB_ALLOC_ANYWHERE 0
#define LMB_ALIST_INITIAL_SIZE 4
static struct lmb lmb;
+static bool lmb_should_notify(enum lmb_flags flags)
+{
+ return !lmb.test && !(flags & LMB_NONOTIFY) &&
+ CONFIG_IS_ENABLED(EFI_LOADER);
+}
+
+static int __maybe_unused lmb_map_update_notify(phys_addr_t addr,
+ phys_size_t size,
+ u8 op)
+{
+ u64 efi_addr;
+ u64 pages;
+ efi_status_t status;
+
+ if (op != MAP_OP_RESERVE && op != MAP_OP_FREE && op != MAP_OP_ADD) {
+ log_err("Invalid map update op received (%d)\n", op);
+ return -1;
+ }
+
+ efi_addr = (uintptr_t)map_sysmem(addr, 0);
+ pages = efi_size_in_pages(size + (efi_addr & EFI_PAGE_MASK));
+ efi_addr &= ~EFI_PAGE_MASK;
+
+ status = efi_add_memory_map_pg(efi_addr, pages,
+ op == MAP_OP_RESERVE ?
+ EFI_BOOT_SERVICES_DATA :
+ EFI_CONVENTIONAL_MEMORY,
+ false);
+ if (status != EFI_SUCCESS) {
+ log_err("%s: LMB Map notify failure %lu\n", __func__,
+ status & ~EFI_ERROR_MASK);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
static void lmb_print_region_flags(enum lmb_flags flags)
{
u64 bitpos;
/* This routine may be called with relocation disabled. */
long lmb_add(phys_addr_t base, phys_size_t size)
{
+ long ret;
struct alist *lmb_rgn_lst = &lmb.free_mem;
- return lmb_add_region(lmb_rgn_lst, base, size);
+ ret = lmb_add_region(lmb_rgn_lst, base, size);
+ if (ret)
+ return ret;
+
+ if (lmb_should_notify(LMB_NONE))
+ return lmb_map_update_notify(base, size, MAP_OP_ADD);
+
+ return 0;
}
static long __lmb_free(phys_addr_t base, phys_size_t size)
rgn[i].flags);
}
-long lmb_free(phys_addr_t base, phys_size_t size)
-{
- return __lmb_free(base, size);
-}
-
/**
* lmb_free_flags() - Free up a region of memory
* @base: Base Address of region to be freed
* Return: 0 if successful, -1 on failure
*/
long lmb_free_flags(phys_addr_t base, phys_size_t size,
- __always_unused uint flags)
+ uint flags)
{
- return __lmb_free(base, size);
+ long ret;
+
+ ret = __lmb_free(base, size);
+ if (ret < 0)
+ return ret;
+
+ if (lmb_should_notify(flags))
+ return lmb_map_update_notify(base, size, MAP_OP_FREE);
+
+ return ret;
+}
+
+long lmb_free(phys_addr_t base, phys_size_t size)
+{
+ return lmb_free_flags(base, size, LMB_NONE);
}
long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags)
{
+ long ret = 0;
struct alist *lmb_rgn_lst = &lmb.used_mem;
- return lmb_add_region_flags(lmb_rgn_lst, base, size, flags);
+ ret = lmb_add_region_flags(lmb_rgn_lst, base, size, flags);
+ if (ret < 0)
+ return -1;
+
+ if (lmb_should_notify(flags))
+ return lmb_map_update_notify(base, size, MAP_OP_RESERVE);
+
+ return ret;
}
long lmb_reserve(phys_addr_t base, phys_size_t size)
static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align,
phys_addr_t max_addr, enum lmb_flags flags)
{
+ u8 op;
+ int ret;
long i, rgn;
phys_addr_t base = 0;
phys_addr_t res_base;
if (lmb_add_region_flags(&lmb.used_mem, base,
size, flags) < 0)
return 0;
+
+ if (lmb_should_notify(flags)) {
+ op = MAP_OP_RESERVE;
+ ret = lmb_map_update_notify(base, size,
+ op);
+ if (ret)
+ return ret;
+ }
+
return base;
}
return 0;
}
-static int lmb_setup(void)
+static int lmb_setup(bool test)
{
bool ret;
return -ENOMEM;
}
+ lmb.test = test;
+
return 0;
}
{
int ret;
- ret = lmb_setup();
+ ret = lmb_setup(false);
if (ret) {
log_info("Unable to init LMB\n");
return ret;
int ret;
*store = lmb;
- ret = lmb_setup();
+ ret = lmb_setup(true);
if (ret)
return ret;