[RFC PATCH 15/31] efi_memory: add an event handler to update memory map
Heinrich Schuchardt
xypron.glpk at gmx.de
Tue Jun 11 12:17:16 CEST 2024
On 07.06.24 20:52, Sughosh Ganu wrote:
> 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 EFI memory module to update the EFI memory map
> accordingly when such changes happen. As a consequence, any subsequent
> memory request would honour the updated memory map and only available
> memory would be allocated from.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
> ---
> lib/efi_loader/efi_memory.c | 70 ++++++++++++++++++++++++++++++-------
> 1 file changed, 58 insertions(+), 12 deletions(-)
>
> diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
> index 435e580fb3..93244161b0 100644
> --- a/lib/efi_loader/efi_memory.c
> +++ b/lib/efi_loader/efi_memory.c
> @@ -73,6 +73,10 @@ struct efi_pool_allocation {
> #if CONFIG_IS_ENABLED(MEM_MAP_UPDATE_NOTIFY)
> extern bool is_addr_in_ram(uintptr_t addr);
>
> +static efi_status_t __efi_add_memory_map_pg(u64 start, u64 pages,
> + int memory_type,
> + bool overlap_only_ram);
> +
> static void efi_map_update_notify(u64 addr, u64 size, u8 op)
> {
> struct event_efi_mem_map_update efi_map = {0};
> @@ -84,6 +88,34 @@ static void efi_map_update_notify(u64 addr, u64 size, u8 op)
> if (is_addr_in_ram((uintptr_t)addr))
> event_notify(EVT_EFI_MEM_MAP_UPDATE, &efi_map, sizeof(efi_map));
> }
> +
> +static int lmb_mem_map_update_sync(void *ctx, struct event *event)
> +{
> + u8 op;
> + u64 addr;
> + u64 pages;
> + efi_status_t status;
> + struct event_lmb_map_update *lmb_map = &event->data.lmb_map;
> +
> + addr = (uintptr_t)map_sysmem(lmb_map->base, 0);
> + pages = efi_size_in_pages(lmb_map->size + (addr & EFI_PAGE_MASK));
> + op = lmb_map->op;
> + addr &= ~EFI_PAGE_MASK;
> +
> + if (op != MAP_OP_RESERVE && op != MAP_OP_FREE) {
> + log_debug("Invalid map update op received (%d)\n", op);
> + return -1;
> + }
> +
> + status = __efi_add_memory_map_pg(addr, pages,
> + op == MAP_OP_FREE ?
> + EFI_CONVENTIONAL_MEMORY :
This is dangerous. LMB might turn memory that is marked as
EfiReservedMemory which the OS must respect into EfiBootServicesData
which the OS may discard.
E.g. initr_lmb() is being called after efi_memory_init().
Getting all cases of synchronization properly tested seems very hard to
me. Everything would be much easier if we had only a single memory
management system.
Best regards
Heinrich
> + EFI_BOOT_SERVICES_DATA,
> + true);
> +
> + return status == EFI_SUCCESS ? 0 : -1;
> +}
> +EVENT_SPY_FULL(EVT_LMB_MAP_UPDATE, lmb_mem_map_update_sync);
> #endif /* MEM_MAP_UPDATE_NOTIFY */
>
> /**
> @@ -275,18 +307,9 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
> return EFI_CARVE_LOOP_AGAIN;
> }
>
> -/**
> - * 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
> - */
> -static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
> - int memory_type,
> - bool overlap_only_ram)
> +static efi_status_t __efi_add_memory_map_pg(u64 start, u64 pages,
> + int memory_type,
> + bool overlap_only_ram)
> {
> struct list_head *lhandle;
> struct efi_mem_list *newlist;
> @@ -395,6 +418,29 @@ static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
> }
> }
>
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + * 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
> + */
> +static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
> + int memory_type,
> + bool overlap_only_ram)
> +{
> + efi_status_t status;
> +
> + status = __efi_add_memory_map_pg(start, pages, memory_type,
> + overlap_only_ram);
> + if (status != EFI_SUCCESS)
> + return status;
> +
> if (CONFIG_IS_ENABLED(MEM_MAP_UPDATE_NOTIFY))
> efi_map_update_notify(start, pages << EFI_PAGE_SHIFT,
> memory_type == EFI_CONVENTIONAL_MEMORY ?
More information about the U-Boot
mailing list