diff options
author | H. Peter Anvin <hpa@zytor.com> | 2008-02-11 17:55:29 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2008-02-11 17:57:15 -0800 |
commit | 44306d385483da3df32311d518f39a54c1d84ac4 (patch) | |
tree | dd359a5c6b5ad1ab801666193ff504f131c1c23c /com32/lib/syslinux/shuffle.c | |
parent | 21ab02fe9320ea827c67663626e1ea724c5a0463 (diff) | |
download | syslinux-44306d385483da3df32311d518f39a54c1d84ac4.tar.gz |
Handle arbitrary numbers of shuffle descriptors
Allocate high memory out of the way to hold the shuffle descriptors,
and generate continuation descriptors as needed.
Diffstat (limited to 'com32/lib/syslinux/shuffle.c')
-rw-r--r-- | com32/lib/syslinux/shuffle.c | 134 |
1 files changed, 117 insertions, 17 deletions
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c index 26c89f98..3393f2a8 100644 --- a/com32/lib/syslinux/shuffle.c +++ b/com32/lib/syslinux/shuffle.c @@ -34,8 +34,10 @@ */ #include <stdlib.h> +#include <string.h> #include <inttypes.h> #include <com32.h> +#include <minmax.h> #include <syslinux/movebits.h> #ifndef DEBUG @@ -52,55 +54,153 @@ struct shuffle_descriptor { uint32_t dst, src, len; }; +/* Allocate descriptor memory in these chunks */ +#define DESC_BLOCK_SIZE 256 + int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist, struct syslinux_memmap *memmap) { struct syslinux_movelist *moves = NULL, *mp; - struct syslinux_memmap *ml; - struct shuffle_descriptor *dp; - int np, rv = -1; + struct syslinux_memmap *rxmap = NULL, *ml; + struct shuffle_descriptor *dp, *dbuf; + int np, nb, rv = -1; + int desc_blocks; + addr_t desczone, descfree, descaddr, descoffs; + int nmoves, nzero; + struct shuffle_descriptor primaries[2]; + + /* Count the number of zero operations */ + nzero = 0; + for (ml = memmap; ml->type != SMT_END; ml = ml->next) { + if (ml->type == SMT_ZERO) + nzero++; + } - if (syslinux_compute_movelist(&moves, fraglist, memmap)) + rxmap = syslinux_dup_memmap(memmap); + for (mp = fraglist; mp; mp = mp->next) { + if (syslinux_add_memmap(&rxmap, mp->src, mp->len, SMT_ALLOC)) + goto bail; + } + + if (syslinux_memmap_largest(rxmap, SMT_FREE, &desczone, &descfree)) goto bail; + dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone, descfree); + + for (desc_blocks = (nzero+DESC_BLOCK_SIZE)/(DESC_BLOCK_SIZE-1) ; ; + desc_blocks++) { + addr_t descmem = desc_blocks* + sizeof(struct shuffle_descriptor)*DESC_BLOCK_SIZE; + + if (descfree < descmem) + goto bail; /* No memory block large enough */ + + descaddr = desczone + descfree - descmem; + if (syslinux_add_memmap(&rxmap, descaddr, descmem, SMT_ALLOC)) + goto bail; + +#if DEBUG + syslinux_dump_movelist(stdout, fraglist); +#endif + + if (syslinux_compute_movelist(&moves, fraglist, rxmap)) + goto bail; + + nmoves = 0; + for (mp = moves; mp; mp = mp->next) + nmoves++; + + if ((nmoves+nzero) <= desc_blocks*(DESC_BLOCK_SIZE-1)) + break; /* Sufficient memory, yay */ + } + #if DEBUG dprintf("Final movelist:\n"); syslinux_dump_movelist(stdout, moves); #endif - dp = __com32.cs_bounce; - np = 0; + syslinux_free_memmap(rxmap); + rxmap = NULL; - /* Copy the move sequence into the bounce buffer */ + dbuf = malloc((nmoves+nzero+desc_blocks)*sizeof(struct shuffle_descriptor)); + if (!dbuf) + goto bail; + + descoffs = descaddr - (addr_t)dbuf; + +#if DEBUG + dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n", + nmoves, nzero, dbuf, descoffs); +#endif + + /* Copy the move sequence into the descriptor buffer */ + np = 0; + nb = 0; + dp = dbuf; for (mp = moves; mp; mp = mp->next) { - if (np >= 65536/12) - goto bail; /* Way too many descriptors... */ + if (nb == DESC_BLOCK_SIZE-1) { + dp->dst = -1; /* Load new descriptors */ + dp->src = (addr_t)(dp+1) + descoffs; + dp->len = sizeof(*dp)*min(nmoves, DESC_BLOCK_SIZE); + dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len); + dp++; np++; + nb = 0; + } dp->dst = mp->dst; dp->src = mp->src; dp->len = mp->len; - dp++; np++; + dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len); + dp++; np++; nb++; } - /* Copy any zeroing operations into the bounce buffer */ + /* Copy bzero operations into the descriptor buffer */ for (ml = memmap; ml->type != SMT_END; ml = ml->next) { if (ml->type == SMT_ZERO) { - if (np >= 65536/12) - goto bail; - + if (nb == DESC_BLOCK_SIZE-1) { + dp->dst = (addr_t)-1; /* Load new descriptors */ + dp->src = (addr_t)(dp+1) + descoffs; + dp->len = sizeof(*dp)*min(nmoves, DESC_BLOCK_SIZE); + dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len); + dp++; np++; + nb = 0; + } + dp->dst = ml->start; - dp->src = (addr_t)-1; /* bzero this region */ + dp->src = (addr_t)-1; /* bzero region */ dp->len = ml->next->start - ml->start; - dp++; np++; + dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len); + dp++; np++; nb++; } } - rv = np; + /* Set up the primary descriptors in the bounce buffer. + The first one moves the descriptor list into its designated safe + zone, the second one loads the first descriptor block. */ + dp = primaries; + + dp->dst = descaddr; + dp->src = (addr_t)dbuf; + dp->len = np*sizeof(*dp); + dprintf("< %08x %08x %08x >\n", dp->dst, dp->src, dp->len); + dp++; + + dp->dst = (addr_t)-1; + dp->src = descaddr; + dp->len = sizeof(*dp)*min(np, DESC_BLOCK_SIZE); + dprintf("< %08x %08x %08x >\n", dp->dst, dp->src, dp->len); + dp++; + + memcpy(__com32.cs_bounce, primaries, 2*sizeof(*dp)); + + rv = 2; /* Always two primaries */ bail: /* This is safe only because free() doesn't use the bounce buffer!!!! */ if (moves) syslinux_free_movelist(moves); + if (rxmap) + syslinux_free_memmap(rxmap); return rv; } |