diff options
author | Andy Fleming <afleming@freescale.com> | 2008-06-16 13:58:55 -0500 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2008-06-28 22:22:05 +0200 |
commit | 7570a9941fc565922078679a72d246fe208d696d (patch) | |
tree | 91ed5c3837bb2c491fb4ef101c3371c5f58fb79a /lib_generic | |
parent | 63796c4e61b207d2e635729d41b7a7f7d188b03c (diff) | |
download | bootable_bootloader_goldelico_gta04-7570a9941fc565922078679a72d246fe208d696d.zip bootable_bootloader_goldelico_gta04-7570a9941fc565922078679a72d246fe208d696d.tar.gz bootable_bootloader_goldelico_gta04-7570a9941fc565922078679a72d246fe208d696d.tar.bz2 |
Fix an underflow bug in __lmb_alloc_base
__lmb_alloc_base can underflow if it fails to find free space. This was fixed
in linux with commit d9024df02ffe74d723d97d552f86de3b34beb8cc. This patch
merely updates __lmb_alloc_base to resemble the current version in Linux.
Signed-off-by: Andy Fleming <afleming@freescale.com>
Diffstat (limited to 'lib_generic')
-rw-r--r-- | lib_generic/lmb.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/lib_generic/lmb.c b/lib_generic/lmb.c index 3240f66..93264c1 100644 --- a/lib_generic/lmb.c +++ b/lib_generic/lmb.c @@ -285,11 +285,14 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy { long i, j; phys_addr_t base = 0; + phys_addr_t res_base; for (i = lmb->memory.cnt-1; i >= 0; i--) { phys_addr_t lmbbase = lmb->memory.region[i].base; phys_size_t lmbsize = lmb->memory.region[i].size; + if (lmbsize < size) + continue; if (max_addr == LMB_ALLOC_ANYWHERE) base = lmb_align_down(lmbbase + lmbsize - size, align); else if (lmbbase < max_addr) { @@ -298,22 +301,23 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy } else continue; - while ((lmbbase <= base) && - ((j = lmb_overlaps_region(&(lmb->reserved), base, size)) >= 0) ) - base = lmb_align_down(lmb->reserved.region[j].base - size, - align); - - if ((base != 0) && (lmbbase <= base)) - break; + while (base && lmbbase <= base) { + j = lmb_overlaps_region(&lmb->reserved, base, size); + if (j < 0) { + /* This area isn't reserved, take it */ + if (lmb_add_region(&lmb->reserved, base, + lmb_align_up(size, + align)) < 0) + return 0; + return base; + } + res_base = lmb->reserved.region[j].base; + if (res_base < size) + break; + base = lmb_align_down(res_base - size, align); + } } - - if (i < 0) - return 0; - - if (lmb_add_region(&(lmb->reserved), base, lmb_align_up(size, align)) < 0) - return 0; - - return base; + return 0; } int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) |