[PATCH v2 2/2] lmb: Fix adjacent region merge in lmb_add_region_flags()

Patrice CHOTARD patrice.chotard at foss.st.com
Sat Apr 13 10:24:40 CEST 2024



On 4/12/24 17:53, Patrice Chotard wrote:
> In case a new region is adjacent to a previous region with
> similar flag, this region is merged with its predecessor, but no
> check are done if this new added region is overlapping another region
> present in lmb (see reserved[3] which overlaps reserved[4]).
> 
> This occurs when the LMB [0xdaafd000-0xddb18000] is added and overlaps
> the LMB [0xdbaf4380-0xddffffff].
> 
> Call lmb_overlaps_region() before merging the new region with the
> adjacent region already present in lmb.
> 
> In case of adjacent region found, code is 90% similar in case
> adjacent region is located before/after the new region.
> Factorize adjacent region management in lmb_add_region_flags().
> 
> Issue reproduced on STM32MP157-DK2 with SCMI DT, bdinfo command's output
> shows:
> 
> before this patch:
> ...
> lmb_dump_all:
>  memory.cnt = 0x1 / max = 0x2
>  memory[0]      [0xc0000000-0xdfffffff], 0x20000000 bytes flags: 0
>  reserved.cnt = 0x5 / max = 0x10
>  reserved[0]    [0x10000000-0x10045fff], 0x00046000 bytes flags: 4
>  reserved[1]    [0x30000000-0x3003ffff], 0x00040000 bytes flags: 4
>  reserved[2]    [0x38000000-0x3800ffff], 0x00010000 bytes flags: 4
>  reserved[3]    [0xdaae1000-0xdfffffff], 0x0551f000 bytes flags: 0
>  reserved[4]    [0xde000000-0xdfffffff], 0x02000000 bytes flags: 4
> ...
> 
> after this patch:
> 
> ...
> lmb_dump_all:
>  memory.cnt = 0x1 / max = 0x2
>  memory[0]      [0xc0000000-0xdfffffff], 0x20000000 bytes flags: 0
>  reserved.cnt = 0x5 / max = 0x10
>  reserved[0]    [0x10000000-0x10045fff], 0x00046000 bytes flags: 4
>  reserved[1]    [0x30000000-0x3003ffff], 0x00040000 bytes flags: 4
>  reserved[2]    [0x38000000-0x3800ffff], 0x00010000 bytes flags: 4
>  reserved[3]    [0xdaae1000-0xddffffff], 0x0351f000 bytes flags: 0
>  reserved[4]    [0xde000000-0xdfffffff], 0x02000000 bytes flags: 4
> ...
> 
> Fixes: 4ed6552f7159 ("[new uImage] Introduce lmb from linux kernel for memory mgmt of boot images")
> 
> Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
> ---
> 
> Changes in v2:
>   _ Fix lmb_add_region_flags() by updating test which leads to
>     extend an existing region
> 
>  lib/lmb.c | 57 +++++++++++++++++++++++++++++--------------------------
>  1 file changed, 30 insertions(+), 27 deletions(-)
> 
> diff --git a/lib/lmb.c b/lib/lmb.c
> index b6afb731440..4ed60f4a843 100644
> --- a/lib/lmb.c
> +++ b/lib/lmb.c
> @@ -130,6 +130,22 @@ static void lmb_fix_over_lap_regions(struct lmb_region *rgn, unsigned long r1,
>  	lmb_remove_region(rgn, r2);
>  }
>  
> +static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
> +				phys_size_t size)
> +{
> +	unsigned long i;
> +
> +	for (i = 0; i < rgn->cnt; i++) {
> +		phys_addr_t rgnbase = rgn->region[i].base;
> +		phys_size_t rgnsize = rgn->region[i].size;
> +
> +		if (lmb_addrs_overlap(base, size, rgnbase, rgnsize))
> +			break;
> +	}
> +
> +	return (i < rgn->cnt) ? i : -1;
> +}
> +
>  void lmb_init(struct lmb *lmb)
>  {
>  #if IS_ENABLED(CONFIG_LMB_USE_MAX_REGIONS)
> @@ -257,7 +273,7 @@ static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
>  				 phys_size_t size, enum lmb_flags flags)
>  {
>  	unsigned long coalesced = 0;
> -	long adjacent, i;
> +	long adjacent, i, overlap;
>  
>  	if (rgn->cnt == 0) {
>  		rgn->region[0].base = base;
> @@ -283,19 +299,21 @@ static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
>  		}
>  
>  		adjacent = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
> -		if (adjacent > 0) {
> -			if (flags != rgnflags)
> -				continue;
> -			rgn->region[i].base -= size;
> -			rgn->region[i].size += size;
> -			coalesced++;
> -			break;
> -		} else if (adjacent < 0) {
> +		if (adjacent != 0) {
>  			if (flags != rgnflags)
>  				continue;
> -			rgn->region[i].size += size;
> -			coalesced++;
> -			break;
> +			overlap = lmb_overlaps_region(rgn, base, size);
> +			if (overlap < 0 || flags == rgn->region[overlap].flags) {
> +				/*
> +				 * no overlap detected or overlap with same flags detected,
> +				 * extend region
> +				 */
> +				if  (adjacent > 0)
> +					rgn->region[i].base -= size;
> +				rgn->region[i].size += size;
> +				coalesced++;
> +				break;
> +			}
>  		} else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
>  			/* regions overlap */
>  			return -1;
> @@ -420,21 +438,6 @@ long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
>  	return lmb_reserve_flags(lmb, base, size, LMB_NONE);
>  }
>  
> -static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
> -				phys_size_t size)
> -{
> -	unsigned long i;
> -
> -	for (i = 0; i < rgn->cnt; i++) {
> -		phys_addr_t rgnbase = rgn->region[i].base;
> -		phys_size_t rgnsize = rgn->region[i].size;
> -		if (lmb_addrs_overlap(base, size, rgnbase, rgnsize))
> -			break;
> -	}
> -
> -	return (i < rgn->cnt) ? i : -1;
> -}
> -
>  phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align)
>  {
>  	return lmb_alloc_base(lmb, size, align, LMB_ALLOC_ANYWHERE);


I think this series (v2) is not correct even if now the CI tests are OK.
After re-reading carefully the lib_test_lmb_overlapping_reserve() test 
it appears to me there is a contradiction.

It's indicating that "check that calling lmb_reserve with overlapping regions fails" 

but the very last test of lib_test_lmb_overlapping_reserve() has this comment :
/* allocate 3rd region, coalesce with first and overlap with second */
and this test allows this overlap case.

It's not clear if LMB region can overlap each other or not ?

Udit, your patch edb5824be17f ("lmb: remove overlapping region with next range")
is authorizing LMB overlapping right ? 

Patrice







More information about the U-Boot mailing list