[PATCH 3/6] efi: Allow monitoring of page allocations

Heinrich Schuchardt xypron.glpk at gmx.de
Thu Jul 25 18:20:53 CEST 2024


On 25.07.24 15:56, Simon Glass wrote:
> Some confusion has set in over which memory-allocation method to use in
> EFI-related code, particularly for the pool allocator. Most of the time,
> malloc() is used, which is correct.
>
> However in some cases the page allocator is used. This means that some
> EFI information is sitting 'in space', outside of the malloc() and not
> allocated by lmb. This can cause problems if an image happens to be
> loaded at the same address.

We already agreed to resolve this problem by integrating LMB and UEFI
memory allocation.

Please, contribute to reviewing
[RFC PATCH v2 00/48] Make U-Boot memory reservations coherent
https://lists.denx.de/pipermail/u-boot/2024-July/557962.html

>
>  From what I can tell, there is currently no checking of this, but it
> seems to be a real bug.
>
> Add a way to control whether allocations are permitted, to help debug
> these sorts of issues.

Calling AllocatePages() and AllocatedPool() cannot be forbidden as we
want to comply to the UEFI specification.

Best regards

Heinrich

>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
>   include/efi_loader.h         | 24 +++++++++++++++++++
>   lib/efi_loader/efi_bootbin.c |  2 ++
>   lib/efi_loader/efi_memory.c  | 46 ++++++++++++++++++++++++++++++++++++
>   lib/efi_loader/efi_setup.c   |  7 ++++++
>   4 files changed, 79 insertions(+)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index f2e5063a970..187078adf55 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -797,6 +797,30 @@ int efi_disk_probe(void *ctx, struct event *event);
>   int efi_disk_remove(void *ctx, struct event *event);
>   /* Called by board init to initialize the EFI memory map */
>   int efi_memory_init(void);
> +
> +/**
> + * enum efi_alloc_action - action to take when EFI does a page allocation
> + *
> + * @EFIAA_FAIL: Fail the allocation and print an error
> + * @EFIAA_WARN: Allow the allocation but print a warning
> + * @EFIAA_ALLOW: Allow the allocation with no message
> + */
> +enum efi_alloc_action {
> +	EFIAA_FAIL,
> +	EFIAA_WARN,
> +	EFIAA_ALLOW,
> +};
> +
> +/**
> + * efi_set_alloc() - Set behaviour on page allocation
> + *
> + * This is useful for debugging use of the page allocator when malloc() should
> + * be used instead
> + *
> + * @allow: true to allow EFI to allocate pages, false to fail the allocation
> + */
> +void efi_set_alloc(enum efi_alloc_action action);
> +
>   /* Adds new or overrides configuration table entry to the system table */
>   efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
>   /* Sets up a loaded image */
> diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c
> index a87006b3c0e..07c8fca68cc 100644
> --- a/lib/efi_loader/efi_bootbin.c
> +++ b/lib/efi_loader/efi_bootbin.c
> @@ -201,6 +201,8 @@ efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
>   {
>   	efi_status_t ret;
>
> +	efi_set_alloc(EFIAA_ALLOW);
> +
>   	/* Initialize EFI drivers */
>   	ret = efi_init_obj_list();
>   	if (ret != EFI_SUCCESS) {
> diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
> index 12cf23fa3fa..087f4c88cdf 100644
> --- a/lib/efi_loader/efi_memory.c
> +++ b/lib/efi_loader/efi_memory.c
> @@ -24,6 +24,43 @@ DECLARE_GLOBAL_DATA_PTR;
>   /* Magic number identifying memory allocated from pool */
>   #define EFI_ALLOC_POOL_MAGIC 0x1fe67ddf6491caa2
>
> +/*
> + * This is true if EFI is permitted to allocate pages in memory. When false,
> + * such allocations will fail. This is useful for debugging page allocations
> + * which should in fact use malloc().
> + *
> + * This defaults to EFIAA_FAIL until set.
> + */
> +static enum efi_alloc_action alloc_action;
> +
> +void efi_set_alloc(enum efi_alloc_action action)
> +{
> +	alloc_action = action;
> +}
> +
> +/**
> + * efi_bad_alloc() - Indicate that an allocation is not allowed
> + *
> + * Set a breakpoint on this function to locate the bad allocation in the call
> + * stack
> + */
> +static void efi_bad_alloc(void)
> +{
> +	log_err("EFI: alloc not allowed\n");
> +}
> +
> +static bool check_allowed(void)
> +{
> +	if (alloc_action == EFIAA_FAIL) {
> +		efi_bad_alloc();
> +		return false;
> +	} else if (alloc_action == EFIAA_WARN) {
> +		log_warning("EFI: suspicious alloc detected\n");
> +	}
> +
> +	return true;
> +}
> +
>   efi_uintn_t efi_memory_map_key;
>
>   struct efi_mem_list {
> @@ -501,6 +538,9 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type,
>   	efi_status_t ret;
>   	uint64_t addr;
>
> +	if (!check_allowed())
> +		return EFI_UNSUPPORTED;
> +
>   	/* Check import parameters */
>   	if (memory_type >= EFI_PERSISTENT_MEMORY_TYPE &&
>   	    memory_type <= 0x6FFFFFFF)
> @@ -649,6 +689,9 @@ efi_status_t efi_allocate_pool(enum efi_memory_type pool_type, efi_uintn_t size,
>   	u64 num_pages = efi_size_in_pages(size +
>   					  sizeof(struct efi_pool_allocation));
>
> +	if (!check_allowed())
> +		return EFI_UNSUPPORTED;
> +
>   	if (!buffer)
>   		return EFI_INVALID_PARAMETER;
>
> @@ -952,6 +995,9 @@ int efi_memory_init(void)
>   	/* Request a 32bit 64MB bounce buffer region */
>   	uint64_t efi_bounce_buffer_addr = 0xffffffff;
>
> +	/* this is the earliest page allocation, so allow it */
> +	efi_set_alloc(EFIAA_ALLOW);
> +
>   	if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_BOOT_SERVICES_DATA,
>   			       (64 * 1024 * 1024) >> EFI_PAGE_SHIFT,
>   			       &efi_bounce_buffer_addr) != EFI_SUCCESS)
> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
> index a610e032d2f..27e24c2f223 100644
> --- a/lib/efi_loader/efi_setup.c
> +++ b/lib/efi_loader/efi_setup.c
> @@ -193,6 +193,13 @@ int efi_init_early(void)
>   	/* Allow unaligned memory access */
>   	allow_unaligned();
>
> +	/*
> +	 * For now, allow EFI to allocate memory outside the malloc() region.
> +	 * Once these bugs are fixed, this can be changed to EFIAA_FAIL, with
> +	 * the allocations being allowed only when the EFI system is booting.
> +	 */
> +	efi_set_alloc(EFIAA_ALLOW);
> +
>   	/* Initialize root node */
>   	ret = efi_root_node_register();
>   	if (ret != EFI_SUCCESS)



More information about the U-Boot mailing list