summaryrefslogtreecommitdiff
path: root/lib_generic
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2008-06-16 13:58:55 -0500
committerWolfgang Denk <wd@denx.de>2008-06-28 22:22:05 +0200
commit7570a9941fc565922078679a72d246fe208d696d (patch)
tree91ed5c3837bb2c491fb4ef101c3371c5f58fb79a /lib_generic
parent63796c4e61b207d2e635729d41b7a7f7d188b03c (diff)
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.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/lib_generic/lmb.c b/lib_generic/lmb.c
index 3240f66bf98..93264c15ec6 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)