diff options
Diffstat (limited to 'contrib/syslinux/latest/com32/lib/syslinux/movebits.c')
-rw-r--r-- | contrib/syslinux/latest/com32/lib/syslinux/movebits.c | 710 |
1 files changed, 0 insertions, 710 deletions
diff --git a/contrib/syslinux/latest/com32/lib/syslinux/movebits.c b/contrib/syslinux/latest/com32/lib/syslinux/movebits.c deleted file mode 100644 index bd5ce0e..0000000 --- a/contrib/syslinux/latest/com32/lib/syslinux/movebits.c +++ /dev/null @@ -1,710 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved - * Copyright 2009 Intel Corporation; author: H. Peter Anvin - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall - * be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * ----------------------------------------------------------------------- */ - -/* - * movebits.c - * - * Utility function to take a list of memory areas to shuffle and - * convert it to a set of shuffle operations. - * - * Note: a lot of the functions in this file deal with "parent pointers", - * which are pointers to a pointer to a list, or part of the list. - * They can be pointers to a variable holding the list root pointer, - * or pointers to a next field of a previous entry. - */ - -#include <assert.h> -#include <stdio.h> -#include <errno.h> -#include <stdlib.h> -#include <inttypes.h> -#include <setjmp.h> -#include <minmax.h> -#include <stdbool.h> - -#include <syslinux/movebits.h> - -#ifndef DEBUG -# ifdef TEST -# define DEBUG 1 -# else -# define DEBUG 0 -# endif -#endif - -#if DEBUG -# include <stdio.h> -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif - -static jmp_buf new_movelist_bail; - -static struct syslinux_movelist *new_movelist(addr_t dst, addr_t src, - addr_t len) -{ - struct syslinux_movelist *ml = malloc(sizeof(struct syslinux_movelist)); - - if (!ml) - longjmp(new_movelist_bail, 1); - - ml->dst = dst; - ml->src = src; - ml->len = len; - ml->next = NULL; - - return ml; -} - -static struct syslinux_movelist *dup_movelist(struct syslinux_movelist *src) -{ - 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; - } - - 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); -} - -/* - * 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) -{ - struct syslinux_movelist *m, *ml = *parentptr; - - assert(start >= ml->src); - assert(start < ml->src + ml->len); - - /* 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; - - parentptr = &ml->next; - ml = m; /* Continue processing the new node */ - } - - /* 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; - } - - return parentptr; -} - -static void delete_movelist(struct syslinux_movelist **parentptr) -{ - struct syslinux_movelist *o = *parentptr; - *parentptr = o->next; - free(o); -} - -static void free_movelist(struct syslinux_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) -{ - 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 */ - } - } - list = list->next; - } - - return NULL; /* Internal error? */ -} - -/* - * Scan the freelist looking for the smallest chunk of memory which - * 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) -{ - 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; - } -} - -/* - * Remove a chunk from the freelist - */ -static void -allocate_from(struct syslinux_memmap **mmap, addr_t start, addr_t len) -{ - syslinux_add_memmap(mmap, start, len, SMT_ALLOC); -} - -/* - * Find chunks of a movelist which are one-to-many (one source, multiple - * destinations.) Those chunks can get turned into post-shuffle copies, - * to avoid confusing the shuffler. - */ -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; - -#if DEBUG - 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; - } - - 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); -#endif -} - -/* - * The code to actually emit moving of a chunk into its final place. - */ -static void -move_chunk(struct syslinux_movelist ***moves, - 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); - } - - 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); -} - -/* - * moves is computed from "frags" and "freemem". "space" lists - * free memory areas at our disposal, and is (src, cnt) only. - */ -int -syslinux_compute_movelist(struct syslinux_movelist **moves, - 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)) { - -#if DEBUG - dprintf("Current free list:\n"); - syslinux_dump_memmap(stdout, mmap); - dprintf("Current frag list:\n"); - syslinux_dump_movelist(stdout, frags); -#endif - - /* 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; - } - - /* 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; - } - } - - /* 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 { - avail = 0; - } - - 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; - } - - /* 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; - } - 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; -} - -#ifdef TEST - -#include <stdio.h> - -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; - } - } 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; - } -} - -#endif /* TEST */ |