[PATCH] lmb: Fix the allocation of overlapping memory areas with !LMB_NONE

Heinrich Schuchardt xypron.glpk at gmx.de
Mon Dec 2 14:31:15 CET 2024


On 28.11.24 12:49, Ilias Apalodimas wrote:
> At the moment the LMB allocator will return 'success' immediately on two
> consecutive allocations if the second one is smaller and the flags match
> without resizing the reserved area.
>
> This is problematic for two reasons, first of all the new updated
> allocation won't update the size and we end up holding more memory than
> needed, but most importantly it breaks the EFI SCT tests since EFI
> now allocates via LMB.
>
> More specifically when EFI requests a specific address twice with the
> EFI_ALLOCATE_ADDRESS flag set, the first allocation will succeed and
> update the EFI memory map. Due to the LMB behavior the second allocation
> will also succeed but the address ranges are already in the EFI memory
> map due the first allocation. EFI will then fail to update the memory map,
> returning EFI_OUT_OF_RESOURCES instead of EFI_NOT_FOUND which break EFI
> conformance.
>
> So let's remove the fast check with is problematic anyway and leave LMB
> resize and calculate address properly. LMB will now
> - try to resize the reservations for LMB_NONE
> - return -1 if the memory is not LMB_NONE and already reserved
>
> The LMB code needs some cleanup in that part, but since we are close to
> 2025.01 do the easy fix and plan to refactor it later.
> Also update the dm tests with the new behavior.
>
> Fixes: commit 22f2c9ed9f53 ("efi: memory: use the LMB API's for allocating and freeing memory")
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
>   lib/lmb.c      |  9 ---------
>   test/lib/lmb.c | 22 +++++++++++++++++++++-
>   2 files changed, 21 insertions(+), 10 deletions(-)
>
> diff --git a/lib/lmb.c b/lib/lmb.c
> index 14b9b8466ff2..3a765c11bee6 100644
> --- a/lib/lmb.c
> +++ b/lib/lmb.c
> @@ -201,15 +201,6 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base,
>   		phys_addr_t rgnbase = rgn[i].base;
>   		phys_size_t rgnsize = rgn[i].size;
>   		phys_size_t rgnflags = rgn[i].flags;
> -		phys_addr_t end = base + size - 1;
> -		phys_addr_t rgnend = rgnbase + rgnsize - 1;
> -		if (rgnbase <= base && end <= rgnend) {
> -			if (flags == rgnflags)
> -				/* Already have this region, so we're done */
> -				return 0;
> -			else
> -				return -1; /* regions with new flags */
> -		}
>
>   		ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
>   		if (ret > 0) {
> diff --git a/test/lib/lmb.c b/test/lib/lmb.c
> index c917115b7b66..bc44dd21192f 100644
> --- a/test/lib/lmb.c
> +++ b/test/lib/lmb.c
> @@ -529,6 +529,26 @@ static int test_alloc_addr(struct unit_test_state *uts, const phys_addr_t ram)
>   	ret = lmb_add(ram, ram_size);
>   	ut_asserteq(ret, 0);
>
> +	/* Try to allocate a page twice */
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NONE);
> +	ut_asserteq(b, alloc_addr_a);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NOOVERWRITE);
> +	ut_asserteq(b, 0);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NONE);
> +	ut_asserteq(b, alloc_addr_a);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x2000, LMB_NONE);
> +	ut_asserteq(b, alloc_addr_a);
> +	ret = lmb_free(alloc_addr_a, 0x2000);
> +	ut_asserteq(ret, 0);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NOOVERWRITE);
> +	ut_asserteq(b, alloc_addr_a);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NONE);
> +	ut_asserteq(b, 0);
> +	b = lmb_alloc_addr_flags(alloc_addr_a, 0x1000, LMB_NOOVERWRITE);
> +	ut_asserteq(b, 0);
> +	ret = lmb_free(alloc_addr_a, 0x1000);
> +	ut_asserteq(ret, 0);
> +
>   	/*  reserve 3 blocks */
>   	ret = lmb_reserve(alloc_addr_a, 0x10000);
>   	ut_asserteq(ret, 0);
> @@ -734,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
>
>   	/* reserve again, same flag */
>   	ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP);
> -	ut_asserteq(ret, 0);
> +	ut_asserteq(ret, 0xffffffff);

lmb_reserve_flags() should return a long value < 0 on failure. Why do
you expect 0xffffffff?

Best regards

Heinrich

>   	ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000,
>   		   0, 0, 0, 0);
>



More information about the U-Boot mailing list