static jmp_buf new_movelist_bail;
-static struct syslinux_movelist *
-new_movelist(addr_t dst, addr_t src, addr_t len)
+static struct syslinux_movelist *new_movelist(addr_t dst, addr_t src,
+ addr_t len)
{
- struct syslinux_movelist *ml = malloc(sizeof(struct syslinux_movelist));
+ struct syslinux_movelist *ml = malloc(sizeof(struct syslinux_movelist));
- if ( !ml )
- longjmp(new_movelist_bail, 1);
+ if (!ml)
+ longjmp(new_movelist_bail, 1);
- ml->dst = dst;
- ml->src = src;
- ml->len = len;
- ml->next = NULL;
+ ml->dst = dst;
+ ml->src = src;
+ ml->len = len;
+ ml->next = NULL;
- return ml;
+ return ml;
}
-static struct syslinux_movelist *
-dup_movelist(struct syslinux_movelist *src)
+static struct syslinux_movelist *dup_movelist(struct syslinux_movelist *src)
{
- struct syslinux_movelist *dst = NULL, **dstp = &dst, *ml;
+ struct syslinux_movelist *dst = NULL, **dstp = &dst, *ml;
- while (src) {
- ml = new_movelist(src->dst, src->src, src->len);
- *dstp = ml;
- dstp = &ml->next;
- src = src->next;
- }
+ while (src) {
+ ml = new_movelist(src->dst, src->src, src->len);
+ *dstp = ml;
+ dstp = &ml->next;
+ src = src->next;
+ }
- return dst;
+ return dst;
}
static void
add_freelist(struct syslinux_memmap **mmap, addr_t start,
addr_t len, enum syslinux_memmap_types type)
{
- if (syslinux_add_memmap(mmap, start, len, type))
- longjmp(new_movelist_bail, 1);
+ if (syslinux_add_memmap(mmap, start, len, type))
+ longjmp(new_movelist_bail, 1);
}
/*
* Take a chunk, entirely confined in **parentptr, and split it off so that
* it has its own structure.
*/
-static struct syslinux_movelist **
-split_movelist(addr_t start, addr_t len, struct syslinux_movelist **parentptr)
+static struct syslinux_movelist **split_movelist(addr_t start, addr_t len,
+ struct syslinux_movelist
+ **parentptr)
{
- struct syslinux_movelist *m, *ml = *parentptr;
+ struct syslinux_movelist *m, *ml = *parentptr;
- assert(start >= ml->src);
- assert(start < ml->src+ml->len);
+ assert(start >= ml->src);
+ assert(start < ml->src + ml->len);
- /* Split off the beginning */
- if ( start > ml->src ) {
- addr_t l = start - ml->src;
+ /* Split off the beginning */
+ if (start > ml->src) {
+ addr_t l = start - ml->src;
- m = new_movelist(ml->dst+l, start, ml->len-l);
- m->next = ml->next;
- ml->len = l;
- ml->next = m;
+ m = new_movelist(ml->dst + l, start, ml->len - l);
+ m->next = ml->next;
+ ml->len = l;
+ ml->next = m;
- parentptr = &ml->next;
- ml = m; /* Continue processing the new node */
- }
+ parentptr = &ml->next;
+ ml = m; /* Continue processing the new node */
+ }
- /* Split off the end */
- if ( ml->len > len ) {
- addr_t l = ml->len - len;
+ /* Split off the end */
+ if (ml->len > len) {
+ addr_t l = ml->len - len;
- m = new_movelist(ml->dst+len, ml->src+len, l);
- m->next = ml->next;
- ml->len = len;
- ml->next = m;
- }
+ m = new_movelist(ml->dst + len, ml->src + len, l);
+ m->next = ml->next;
+ ml->len = len;
+ ml->next = m;
+ }
- return parentptr;
+ return parentptr;
}
-static void
-delete_movelist(struct syslinux_movelist **parentptr)
+static void delete_movelist(struct syslinux_movelist **parentptr)
{
- struct syslinux_movelist *o = *parentptr;
- *parentptr = o->next;
- free(o);
+ struct syslinux_movelist *o = *parentptr;
+ *parentptr = o->next;
+ free(o);
}
-static void
-free_movelist(struct syslinux_movelist **parentptr)
+static void free_movelist(struct syslinux_movelist **parentptr)
{
- while (*parentptr)
- delete_movelist(parentptr);
+ while (*parentptr)
+ delete_movelist(parentptr);
}
/*
* Scan the freelist looking for a particular chunk of memory
*/
-static const struct syslinux_memmap *
-is_free_zone(const struct syslinux_memmap *list, addr_t start, addr_t len)
+static const struct syslinux_memmap *is_free_zone(const struct syslinux_memmap
+ *list, addr_t start,
+ addr_t len)
{
- dprintf("f: 0x%08x bytes at 0x%08x\n", len, start);
-
- addr_t last, llast;
-
- last = start+len-1;
-
- while (list->type != SMT_END) {
- llast = list->next->start-1;
- if (list->start <= start) {
- if (llast >= last) {
- /* Chunk has a single, well-defined type */
- if (list->type == SMT_FREE) {
- dprintf("F: 0x%08x bytes at 0x%08x\n",
- list->next->start, list->start);
- return list; /* It's free */
+ dprintf("f: 0x%08x bytes at 0x%08x\n", len, start);
+
+ addr_t last, llast;
+
+ last = start + len - 1;
+
+ while (list->type != SMT_END) {
+ llast = list->next->start - 1;
+ if (list->start <= start) {
+ if (llast >= last) {
+ /* Chunk has a single, well-defined type */
+ if (list->type == SMT_FREE) {
+ dprintf("F: 0x%08x bytes at 0x%08x\n",
+ list->next->start, list->start);
+ return list; /* It's free */
+ }
+ return NULL; /* Not free */
+ } else if (llast >= start) {
+ return NULL; /* Crosses region boundary */
+ }
}
- return NULL; /* Not free */
- } else if (llast >= start) {
- return NULL; /* Crosses region boundary */
- }
+ list = list->next;
}
- list = list->next;
- }
- return NULL; /* Internal error? */
+ return NULL; /* Internal error? */
}
/*
* can fit X bytes; returns the length of the block on success.
*/
static addr_t free_area(const struct syslinux_memmap *mmap,
- addr_t len, addr_t *start)
+ addr_t len, addr_t * start)
{
- const struct syslinux_memmap *best = NULL;
- const struct syslinux_memmap *s;
- addr_t slen, best_len = -1;
-
- for (s = mmap; s->type != SMT_END; s = s->next) {
- if (s->type != SMT_FREE)
- continue;
- slen = s->next->start - s->start;
- if (slen >= len) {
- if (!best || best_len > slen) {
- best = s;
- best_len = slen;
- }
+ const struct syslinux_memmap *best = NULL;
+ const struct syslinux_memmap *s;
+ addr_t slen, best_len = -1;
+
+ for (s = mmap; s->type != SMT_END; s = s->next) {
+ if (s->type != SMT_FREE)
+ continue;
+ slen = s->next->start - s->start;
+ if (slen >= len) {
+ if (!best || best_len > slen) {
+ best = s;
+ best_len = slen;
+ }
+ }
+ }
+
+ if (best) {
+ *start = best->start;
+ return best_len;
+ } else {
+ return 0;
}
- }
-
- if (best) {
- *start = best->start;
- return best_len;
- } else {
- return 0;
- }
}
/*
static void
allocate_from(struct syslinux_memmap **mmap, addr_t start, addr_t len)
{
- syslinux_add_memmap(mmap, start, len, SMT_ALLOC);
+ syslinux_add_memmap(mmap, start, len, SMT_ALLOC);
}
/*
static void shuffle_dealias(struct syslinux_movelist **fraglist,
struct syslinux_movelist **postcopy)
{
- struct syslinux_movelist *mp, **mpp, *mx, *np;
- addr_t ps, pe, xs, xe, delta;
- bool advance;
+ struct syslinux_movelist *mp, **mpp, *mx, *np;
+ addr_t ps, pe, xs, xe, delta;
+ bool advance;
#if DEBUG
- dprintf("Before alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
+ dprintf("Before alias resolution:\n");
+ syslinux_dump_movelist(stdout, *fraglist);
#endif
- *postcopy = NULL;
-
- /*
- * Note: as written, this is an O(n^2) algorithm; by producing a list
- * sorted by destination address we could reduce it to O(n log n).
- */
- mpp = fraglist;
- while ((mp = *mpp)) {
- dprintf("mp -> (%#x,%#x,%#x)\n", mp->dst, mp->src, mp->len);
- ps = mp->src;
- pe = mp->src + mp->len - 1;
- for (mx = *fraglist; mx != mp; mx = mx->next) {
- dprintf("mx -> (%#x,%#x,%#x)\n", mx->dst, mx->src, mx->len);
- /*
- * If there is any overlap between mx and mp, mp should be
- * modified and possibly split.
- */
- xs = mx->src;
- xe = mx->src + mx->len - 1;
-
- dprintf("?: %#x..%#x (inside %#x..%#x)\n", ps, pe, xs, xe);
-
- if (pe <= xs || ps >= xe)
- continue; /* No overlap */
-
- advance = false;
- *mpp = mp->next; /* Remove from list */
-
- if (pe > xe) {
- delta = pe-xe;
- np = new_movelist(mp->dst+mp->len-delta, mp->src+mp->len-delta, delta);
- mp->len -= delta; pe = xe;
- np->next = *mpp;
- *mpp = np;
- advance = true;
- }
- if (ps < xs) {
- delta = xs-ps;
- np = new_movelist(mp->dst, ps, delta);
- mp->src += delta; ps = mp->src;
- mp->dst += delta;
- mp->len -= delta;
- np->next = *mpp;
- *mpp = np;
- advance = true;
- }
-
- assert(ps >= xs && pe <= xe);
-
- dprintf("Overlap: %#x..%#x (inside %#x..%#x)\n", ps, pe, xs, xe);
-
- mp->src = mx->dst + (ps-xs);
- mp->next = *postcopy;
- *postcopy = mp;
-
- mp = *mpp;
-
- if (!advance)
- goto restart;
+ *postcopy = NULL;
+
+ /*
+ * Note: as written, this is an O(n^2) algorithm; by producing a list
+ * sorted by destination address we could reduce it to O(n log n).
+ */
+ mpp = fraglist;
+ while ((mp = *mpp)) {
+ dprintf("mp -> (%#x,%#x,%#x)\n", mp->dst, mp->src, mp->len);
+ ps = mp->src;
+ pe = mp->src + mp->len - 1;
+ for (mx = *fraglist; mx != mp; mx = mx->next) {
+ dprintf("mx -> (%#x,%#x,%#x)\n", mx->dst, mx->src, mx->len);
+ /*
+ * If there is any overlap between mx and mp, mp should be
+ * modified and possibly split.
+ */
+ xs = mx->src;
+ xe = mx->src + mx->len - 1;
+
+ dprintf("?: %#x..%#x (inside %#x..%#x)\n", ps, pe, xs, xe);
+
+ if (pe <= xs || ps >= xe)
+ continue; /* No overlap */
+
+ advance = false;
+ *mpp = mp->next; /* Remove from list */
+
+ if (pe > xe) {
+ delta = pe - xe;
+ np = new_movelist(mp->dst + mp->len - delta,
+ mp->src + mp->len - delta, delta);
+ mp->len -= delta;
+ pe = xe;
+ np->next = *mpp;
+ *mpp = np;
+ advance = true;
+ }
+ if (ps < xs) {
+ delta = xs - ps;
+ np = new_movelist(mp->dst, ps, delta);
+ mp->src += delta;
+ ps = mp->src;
+ mp->dst += delta;
+ mp->len -= delta;
+ np->next = *mpp;
+ *mpp = np;
+ advance = true;
+ }
+
+ assert(ps >= xs && pe <= xe);
+
+ dprintf("Overlap: %#x..%#x (inside %#x..%#x)\n", ps, pe, xs, xe);
+
+ mp->src = mx->dst + (ps - xs);
+ mp->next = *postcopy;
+ *postcopy = mp;
+
+ mp = *mpp;
+
+ if (!advance)
+ goto restart;
+ }
+
+ mpp = &mp->next;
+restart:
+ ;
}
-
- mpp = &mp->next;
- restart:
- ;
- }
#if DEBUG
- dprintf("After alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
- dprintf("Post-shuffle copies:\n");
- syslinux_dump_movelist(stdout, *postcopy);
+ dprintf("After alias resolution:\n");
+ syslinux_dump_movelist(stdout, *fraglist);
+ dprintf("Post-shuffle copies:\n");
+ syslinux_dump_movelist(stdout, *postcopy);
#endif
}
struct syslinux_memmap **mmap,
struct syslinux_movelist **fp, addr_t copylen)
{
- addr_t copydst, copysrc;
- addr_t freebase, freelen;
- addr_t needlen;
- int reverse;
- struct syslinux_movelist *f = *fp, *mv;
-
- if ( f->src < f->dst && (f->dst - f->src) < f->len ) {
- /* "Shift up" type overlap */
- needlen = f->dst - f->src;
- reverse = 1;
- } else if ( f->src > f->dst && (f->src - f->dst) < f->len ) {
- /* "Shift down" type overlap */
- needlen = f->src - f->dst;
- reverse = 0;
- } else {
- needlen = f->len;
- reverse = 0;
- }
-
- copydst = f->dst;
- copysrc = f->src;
-
- dprintf("Q: copylen = 0x%08x, needlen = 0x%08x\n", copylen, needlen);
-
- if ( copylen < needlen ) {
- if (reverse) {
- copydst += (f->len-copylen);
- copysrc += (f->len-copylen);
+ addr_t copydst, copysrc;
+ addr_t freebase, freelen;
+ addr_t needlen;
+ int reverse;
+ struct syslinux_movelist *f = *fp, *mv;
+
+ if (f->src < f->dst && (f->dst - f->src) < f->len) {
+ /* "Shift up" type overlap */
+ needlen = f->dst - f->src;
+ reverse = 1;
+ } else if (f->src > f->dst && (f->src - f->dst) < f->len) {
+ /* "Shift down" type overlap */
+ needlen = f->src - f->dst;
+ reverse = 0;
+ } else {
+ needlen = f->len;
+ reverse = 0;
+ }
+
+ copydst = f->dst;
+ copysrc = f->src;
+
+ dprintf("Q: copylen = 0x%08x, needlen = 0x%08x\n", copylen, needlen);
+
+ if (copylen < needlen) {
+ if (reverse) {
+ copydst += (f->len - copylen);
+ copysrc += (f->len - copylen);
+ }
+
+ dprintf("X: 0x%08x bytes at 0x%08x -> 0x%08x\n",
+ copylen, copysrc, copydst);
+
+ /* Didn't get all we wanted, so we have to split the chunk */
+ fp = split_movelist(copysrc, copylen, fp); /* Is this right? */
+ f = *fp;
}
- dprintf("X: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- copylen, copysrc, copydst);
-
- /* Didn't get all we wanted, so we have to split the chunk */
- fp = split_movelist(copysrc, copylen, fp); /* Is this right? */
- f = *fp;
- }
-
- mv = new_movelist(f->dst, f->src, f->len);
- dprintf("A: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- mv->len, mv->src, mv->dst);
- **moves = mv;
- *moves = &mv->next;
-
- /* Figure out what memory we just freed up */
- if ( f->dst > f->src ) {
- freebase = f->src;
- freelen = min(f->len, f->dst-f->src);
- } else if ( f->src >= f->dst+f->len ) {
- freebase = f->src;
- freelen = f->len;
- } else {
- freelen = f->src-f->dst;
- freebase = f->dst+f->len;
- }
-
- dprintf("F: 0x%08x bytes at 0x%08x\n", freelen, freebase);
-
- add_freelist(mmap, freebase, freelen, SMT_FREE);
-
- delete_movelist(fp);
+ mv = new_movelist(f->dst, f->src, f->len);
+ dprintf("A: 0x%08x bytes at 0x%08x -> 0x%08x\n", mv->len, mv->src, mv->dst);
+ **moves = mv;
+ *moves = &mv->next;
+
+ /* Figure out what memory we just freed up */
+ if (f->dst > f->src) {
+ freebase = f->src;
+ freelen = min(f->len, f->dst - f->src);
+ } else if (f->src >= f->dst + f->len) {
+ freebase = f->src;
+ freelen = f->len;
+ } else {
+ freelen = f->src - f->dst;
+ freebase = f->dst + f->len;
+ }
+
+ dprintf("F: 0x%08x bytes at 0x%08x\n", freelen, freebase);
+
+ add_freelist(mmap, freebase, freelen, SMT_FREE);
+
+ delete_movelist(fp);
}
/*
struct syslinux_movelist *ifrags,
struct syslinux_memmap *memmap)
{
- struct syslinux_memmap *mmap = NULL;
- const struct syslinux_memmap *mm, *ep;
- struct syslinux_movelist *frags = NULL;
- struct syslinux_movelist *postcopy = NULL;
- struct syslinux_movelist *mv;
- struct syslinux_movelist *f, **fp;
- struct syslinux_movelist *o, **op;
- addr_t needbase, needlen, copysrc, copydst, copylen;
- addr_t avail;
- addr_t fstart, flen;
- addr_t cbyte;
- addr_t ep_len;
- int rv = -1;
- int reverse;
-
- dprintf("entering syslinux_compute_movelist()...\n");
-
- if (setjmp(new_movelist_bail)) {
- nomem:
- dprintf("Out of working memory!\n");
- goto bail;
- }
-
- *moves = NULL;
-
- /* Create our memory map. Anything that is SMT_FREE or SMT_ZERO is
- fair game, but mark anything used by source material as SMT_ALLOC. */
- mmap = syslinux_init_memmap();
- if (!mmap)
- goto nomem;
-
- frags = dup_movelist(ifrags);
-
- /* Process one-to-many conditions */
- shuffle_dealias(&frags, &postcopy);
-
- for (mm = memmap; mm->type != SMT_END; mm = mm->next)
- add_freelist(&mmap, mm->start, mm->next->start - mm->start,
- mm->type == SMT_ZERO ? SMT_FREE : mm->type);
-
- for (f = frags; f; f = f->next)
- add_freelist(&mmap, f->src, f->len, SMT_ALLOC);
-
- /* As long as there are unprocessed fragments in the chain... */
- while ( (fp = &frags, f = *fp) ) {
+ struct syslinux_memmap *mmap = NULL;
+ const struct syslinux_memmap *mm, *ep;
+ struct syslinux_movelist *frags = NULL;
+ struct syslinux_movelist *postcopy = NULL;
+ struct syslinux_movelist *mv;
+ struct syslinux_movelist *f, **fp;
+ struct syslinux_movelist *o, **op;
+ addr_t needbase, needlen, copysrc, copydst, copylen;
+ addr_t avail;
+ addr_t fstart, flen;
+ addr_t cbyte;
+ addr_t ep_len;
+ int rv = -1;
+ int reverse;
+
+ dprintf("entering syslinux_compute_movelist()...\n");
+
+ if (setjmp(new_movelist_bail)) {
+nomem:
+ dprintf("Out of working memory!\n");
+ goto bail;
+ }
-#if DEBUG
- dprintf("Current free list:\n");
- syslinux_dump_memmap(stdout, mmap);
- dprintf("Current frag list:\n");
- syslinux_dump_movelist(stdout, frags);
-#endif
+ *moves = NULL;
- /* Scan for fragments which can be discarded without action. */
- if ( f->src == f->dst ) {
- delete_movelist(fp);
- continue;
- }
- op = &f->next;
- while ( (o = *op) ) {
- if ( o->src == o->dst )
- delete_movelist(op);
- else
- op = &o->next;
- }
+ /* Create our memory map. Anything that is SMT_FREE or SMT_ZERO is
+ fair game, but mark anything used by source material as SMT_ALLOC. */
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto nomem;
- /* Scan for fragments which can be immediately moved
- to their final destination, if so handle them now */
- for ( op = fp; (o = *op); op = &o->next ) {
- if ( o->src < o->dst && (o->dst - o->src) < o->len ) {
- /* "Shift up" type overlap */
- needlen = o->dst - o->src;
- needbase = o->dst + (o->len - needlen);
- reverse = 1;
- cbyte = o->dst + o->len - 1;
- } else if ( o->src > o->dst && (o->src - o->dst) < o->len ) {
- /* "Shift down" type overlap */
- needlen = o->src - o->dst;
- needbase = o->dst;
- reverse = 0;
- cbyte = o->dst; /* "Critical byte" */
- } else {
- needlen = o->len;
- needbase = o->dst;
- reverse = 0;
- cbyte = o->dst; /* "Critical byte" */
- }
+ frags = dup_movelist(ifrags);
- if (is_free_zone(mmap, needbase, needlen)) {
- fp = op, f = o;
- dprintf("!: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- f->len, f->src, f->dst);
- copysrc = f->src;
- copylen = needlen;
- allocate_from(&mmap, needbase, copylen);
- goto move_chunk;
- }
- }
+ /* Process one-to-many conditions */
+ shuffle_dealias(&frags, &postcopy);
- /* Ok, bother. Need to do real work at least with one chunk. */
-
- dprintf("@: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- f->len, f->src, f->dst);
-
- /* See if we can move this chunk into place by claiming
- the destination, or in the case of partial overlap, the
- missing portion. */
-
- if ( f->src < f->dst && (f->dst - f->src) < f->len ) {
- /* "Shift up" type overlap */
- needlen = f->dst - f->src;
- needbase = f->dst + (f->len - needlen);
- reverse = 1;
- cbyte = f->dst + f->len - 1;
- } else if ( f->src > f->dst && (f->src - f->dst) < f->len ) {
- /* "Shift down" type overlap */
- needlen = f->src - f->dst;
- needbase = f->dst;
- reverse = 0;
- cbyte = f->dst; /* "Critical byte" */
- } else {
- needlen = f->len;
- needbase = f->dst;
- reverse = 0;
- cbyte = f->dst;
- }
+ for (mm = memmap; mm->type != SMT_END; mm = mm->next)
+ add_freelist(&mmap, mm->start, mm->next->start - mm->start,
+ mm->type == SMT_ZERO ? SMT_FREE : mm->type);
- dprintf("need: base = 0x%08x, len = 0x%08x, "
- "reverse = %d, cbyte = 0x%08x\n",
- needbase, needlen, reverse, cbyte);
-
- ep = is_free_zone(mmap, cbyte, 1);
- if (ep) {
- ep_len = ep->next->start - ep->start;
- if (reverse)
- avail = needbase+needlen - ep->start;
- else
- avail = ep_len - (needbase - ep->start);
- } else {
- avail = 0;
- }
+ for (f = frags; f; f = f->next)
+ add_freelist(&mmap, f->src, f->len, SMT_ALLOC);
- if (avail) {
- /* We can move at least part of this chunk into place without
- further ado */
- dprintf("space: start 0x%08x, len 0x%08x, free 0x%08x\n",
- ep->start, ep_len, avail);
- copylen = min(needlen, avail);
+ /* As long as there are unprocessed fragments in the chain... */
+ while ((fp = &frags, f = *fp)) {
- if (reverse)
- allocate_from(&mmap, needbase+needlen-copylen, copylen);
- else
- allocate_from(&mmap, needbase, copylen);
+#if DEBUG
+ dprintf("Current free list:\n");
+ syslinux_dump_memmap(stdout, mmap);
+ dprintf("Current frag list:\n");
+ syslinux_dump_movelist(stdout, frags);
+#endif
- goto move_chunk;
- }
+ /* Scan for fragments which can be discarded without action. */
+ if (f->src == f->dst) {
+ delete_movelist(fp);
+ continue;
+ }
+ op = &f->next;
+ while ((o = *op)) {
+ if (o->src == o->dst)
+ delete_movelist(op);
+ else
+ op = &o->next;
+ }
- /* At this point, we need to evict something out of our space.
- Find the object occupying the critical byte of our target space,
- and move it out (the whole object if we can, otherwise a subset.)
- Then move a chunk of ourselves into place. */
- for ( op = &f->next, o = *op ; o ; op = &o->next, o = *op ) {
-
- dprintf("O: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- o->len, o->src, o->dst);
-
- if ( !(o->src <= cbyte && o->src+o->len > cbyte) )
- continue; /* Not what we're looking for... */
-
- /* Find somewhere to put it... */
-
- if ( is_free_zone(mmap, o->dst, o->len) ) {
- /* Score! We can move it into place directly... */
- copydst = o->dst;
- copysrc = o->src;
- copylen = o->len;
- } else if ( free_area(mmap, o->len, &fstart) ) {
- /* We can move the whole chunk */
- copydst = fstart;
- copysrc = o->src;
- copylen = o->len;
- } else {
- /* Well, copy as much as we can... */
- if (syslinux_memmap_largest(mmap, SMT_FREE, &fstart, &flen)) {
- dprintf("No free memory at all!\n");
- goto bail; /* Stuck! */
+ /* Scan for fragments which can be immediately moved
+ to their final destination, if so handle them now */
+ for (op = fp; (o = *op); op = &o->next) {
+ if (o->src < o->dst && (o->dst - o->src) < o->len) {
+ /* "Shift up" type overlap */
+ needlen = o->dst - o->src;
+ needbase = o->dst + (o->len - needlen);
+ reverse = 1;
+ cbyte = o->dst + o->len - 1;
+ } else if (o->src > o->dst && (o->src - o->dst) < o->len) {
+ /* "Shift down" type overlap */
+ needlen = o->src - o->dst;
+ needbase = o->dst;
+ reverse = 0;
+ cbyte = o->dst; /* "Critical byte" */
+ } else {
+ needlen = o->len;
+ needbase = o->dst;
+ reverse = 0;
+ cbyte = o->dst; /* "Critical byte" */
+ }
+
+ if (is_free_zone(mmap, needbase, needlen)) {
+ fp = op, f = o;
+ dprintf("!: 0x%08x bytes at 0x%08x -> 0x%08x\n",
+ f->len, f->src, f->dst);
+ copysrc = f->src;
+ copylen = needlen;
+ allocate_from(&mmap, needbase, copylen);
+ goto move_chunk;
+ }
}
- /* Make sure we include the critical byte */
- copydst = fstart;
- if (reverse) {
- copysrc = max(o->src, cbyte+1 - flen);
- copylen = cbyte+1 - copysrc;
+ /* Ok, bother. Need to do real work at least with one chunk. */
+
+ dprintf("@: 0x%08x bytes at 0x%08x -> 0x%08x\n",
+ f->len, f->src, f->dst);
+
+ /* See if we can move this chunk into place by claiming
+ the destination, or in the case of partial overlap, the
+ missing portion. */
+
+ if (f->src < f->dst && (f->dst - f->src) < f->len) {
+ /* "Shift up" type overlap */
+ needlen = f->dst - f->src;
+ needbase = f->dst + (f->len - needlen);
+ reverse = 1;
+ cbyte = f->dst + f->len - 1;
+ } else if (f->src > f->dst && (f->src - f->dst) < f->len) {
+ /* "Shift down" type overlap */
+ needlen = f->src - f->dst;
+ needbase = f->dst;
+ reverse = 0;
+ cbyte = f->dst; /* "Critical byte" */
+ } else {
+ needlen = f->len;
+ needbase = f->dst;
+ reverse = 0;
+ cbyte = f->dst;
+ }
+
+ dprintf("need: base = 0x%08x, len = 0x%08x, "
+ "reverse = %d, cbyte = 0x%08x\n",
+ needbase, needlen, reverse, cbyte);
+
+ ep = is_free_zone(mmap, cbyte, 1);
+ if (ep) {
+ ep_len = ep->next->start - ep->start;
+ if (reverse)
+ avail = needbase + needlen - ep->start;
+ else
+ avail = ep_len - (needbase - ep->start);
} else {
- copysrc = cbyte;
- copylen = min(flen, o->len - (cbyte-o->src));
+ avail = 0;
}
- }
- allocate_from(&mmap, copydst, copylen);
-
- if ( copylen < o->len ) {
- op = split_movelist(copysrc, copylen, op);
- o = *op;
- }
-
- mv = new_movelist(copydst, copysrc, copylen);
- dprintf("C: 0x%08x bytes at 0x%08x -> 0x%08x\n",
- mv->len, mv->src, mv->dst);
- *moves = mv;
- moves = &mv->next;
-
- o->src = copydst;
-
- if ( copylen > needlen ) {
- /* We don't need all the memory we freed up. Mark it free. */
- if ( copysrc < needbase ) {
- add_freelist(&mmap, copysrc, needbase-copysrc, SMT_FREE);
- copylen -= (needbase-copysrc);
+
+ if (avail) {
+ /* We can move at least part of this chunk into place without
+ further ado */
+ dprintf("space: start 0x%08x, len 0x%08x, free 0x%08x\n",
+ ep->start, ep_len, avail);
+ copylen = min(needlen, avail);
+
+ if (reverse)
+ allocate_from(&mmap, needbase + needlen - copylen, copylen);
+ else
+ allocate_from(&mmap, needbase, copylen);
+
+ goto move_chunk;
}
- if ( copylen > needlen ) {
- add_freelist(&mmap, copysrc+needlen, copylen-needlen, SMT_FREE);
- copylen = needlen;
+
+ /* At this point, we need to evict something out of our space.
+ Find the object occupying the critical byte of our target space,
+ and move it out (the whole object if we can, otherwise a subset.)
+ Then move a chunk of ourselves into place. */
+ for (op = &f->next, o = *op; o; op = &o->next, o = *op) {
+
+ dprintf("O: 0x%08x bytes at 0x%08x -> 0x%08x\n",
+ o->len, o->src, o->dst);
+
+ if (!(o->src <= cbyte && o->src + o->len > cbyte))
+ continue; /* Not what we're looking for... */
+
+ /* Find somewhere to put it... */
+
+ if (is_free_zone(mmap, o->dst, o->len)) {
+ /* Score! We can move it into place directly... */
+ copydst = o->dst;
+ copysrc = o->src;
+ copylen = o->len;
+ } else if (free_area(mmap, o->len, &fstart)) {
+ /* We can move the whole chunk */
+ copydst = fstart;
+ copysrc = o->src;
+ copylen = o->len;
+ } else {
+ /* Well, copy as much as we can... */
+ if (syslinux_memmap_largest(mmap, SMT_FREE, &fstart, &flen)) {
+ dprintf("No free memory at all!\n");
+ goto bail; /* Stuck! */
+ }
+
+ /* Make sure we include the critical byte */
+ copydst = fstart;
+ if (reverse) {
+ copysrc = max(o->src, cbyte + 1 - flen);
+ copylen = cbyte + 1 - copysrc;
+ } else {
+ copysrc = cbyte;
+ copylen = min(flen, o->len - (cbyte - o->src));
+ }
+ }
+ allocate_from(&mmap, copydst, copylen);
+
+ if (copylen < o->len) {
+ op = split_movelist(copysrc, copylen, op);
+ o = *op;
+ }
+
+ mv = new_movelist(copydst, copysrc, copylen);
+ dprintf("C: 0x%08x bytes at 0x%08x -> 0x%08x\n",
+ mv->len, mv->src, mv->dst);
+ *moves = mv;
+ moves = &mv->next;
+
+ o->src = copydst;
+
+ if (copylen > needlen) {
+ /* We don't need all the memory we freed up. Mark it free. */
+ if (copysrc < needbase) {
+ add_freelist(&mmap, copysrc, needbase - copysrc, SMT_FREE);
+ copylen -= (needbase - copysrc);
+ }
+ if (copylen > needlen) {
+ add_freelist(&mmap, copysrc + needlen, copylen - needlen,
+ SMT_FREE);
+ copylen = needlen;
+ }
+ }
+ reverse = 0;
+ goto move_chunk;
}
- }
- reverse = 0;
- goto move_chunk;
+ dprintf("Cannot find the chunk containing the critical byte\n");
+ goto bail; /* Stuck! */
+
+move_chunk:
+ move_chunk(&moves, &mmap, fp, copylen);
}
- dprintf("Cannot find the chunk containing the critical byte\n");
- goto bail; /* Stuck! */
-
- move_chunk:
- move_chunk(&moves, &mmap, fp, copylen);
- }
-
- /* Finally, append the postcopy chain to the end of the moves list */
- for (op = moves; (o = *op); op = &o->next)
- ; /* Locate the end of the list */
- *op = postcopy;
- postcopy = NULL;
-
- rv = 0;
- bail:
- if (mmap)
- syslinux_free_memmap(mmap);
- if (frags)
- free_movelist(&frags);
- if (postcopy)
- free_movelist(&postcopy);
- return rv;
+
+ /* Finally, append the postcopy chain to the end of the moves list */
+ for (op = moves; (o = *op); op = &o->next) ; /* Locate the end of the list */
+ *op = postcopy;
+ postcopy = NULL;
+
+ rv = 0;
+bail:
+ if (mmap)
+ syslinux_free_memmap(mmap);
+ if (frags)
+ free_movelist(&frags);
+ if (postcopy)
+ free_movelist(&postcopy);
+ return rv;
}
#ifdef TEST
int main(int argc, char *argv[])
{
- FILE *f;
- unsigned long d, s, l;
- struct syslinux_movelist *frags;
- struct syslinux_movelist **fep = &frags;
- struct syslinux_movelist *mv, *moves;
- struct syslinux_memmap *memmap;
- char line[BUFSIZ];
-
- (void)argc;
-
- memmap = syslinux_init_memmap();
-
- f = fopen(argv[1], "r");
- while ( fgets(line, sizeof line, f) != NULL ) {
- if ( sscanf(line, "%lx %lx %lx", &s, &d, &l) == 3 ) {
- if ( d ) {
- if (s == -1UL) {
- syslinux_add_memmap(&memmap, d, l, SMT_ZERO);
- } else {
- mv = new_movelist(d, s, l);
- *fep = mv;
- fep = &mv->next;
+ FILE *f;
+ unsigned long d, s, l;
+ struct syslinux_movelist *frags;
+ struct syslinux_movelist **fep = &frags;
+ struct syslinux_movelist *mv, *moves;
+ struct syslinux_memmap *memmap;
+ char line[BUFSIZ];
+
+ (void)argc;
+
+ memmap = syslinux_init_memmap();
+
+ f = fopen(argv[1], "r");
+ while (fgets(line, sizeof line, f) != NULL) {
+ if (sscanf(line, "%lx %lx %lx", &s, &d, &l) == 3) {
+ if (d) {
+ if (s == -1UL) {
+ syslinux_add_memmap(&memmap, d, l, SMT_ZERO);
+ } else {
+ mv = new_movelist(d, s, l);
+ *fep = mv;
+ fep = &mv->next;
+ }
+ } else {
+ syslinux_add_memmap(&memmap, s, l, SMT_FREE);
+ }
}
- } else {
- syslinux_add_memmap(&memmap, s, l, SMT_FREE);
- }
}
- }
- fclose(f);
-
- *fep = NULL;
-
- printf("Input move list:\n");
- syslinux_dump_movelist(stdout, frags);
- printf("Input free list:\n");
- syslinux_dump_memmap(stdout, memmap);
-
- if ( syslinux_compute_movelist(&moves, frags, memmap) ) {
- printf("Failed to compute a move sequence\n");
- return 1;
- } else {
- printf("Final move list:\n");
- syslinux_dump_movelist(stdout, moves);
- return 0;
- }
- }
+ fclose(f);
+
+ *fep = NULL;
+
+ printf("Input move list:\n");
+ syslinux_dump_movelist(stdout, frags);
+ printf("Input free list:\n");
+ syslinux_dump_memmap(stdout, memmap);
+
+ if (syslinux_compute_movelist(&moves, frags, memmap)) {
+ printf("Failed to compute a move sequence\n");
+ return 1;
+ } else {
+ printf("Final move list:\n");
+ syslinux_dump_movelist(stdout, moves);
+ return 0;
+ }
+}
#endif /* TEST */