summaryrefslogtreecommitdiff
path: root/com32/lib/syslinux/shuffle.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-03-10 14:36:36 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-03-10 14:38:05 -0700
commit86981dec7307fd10f98410561107bde5bff7e10b (patch)
tree6f9c5f094f750a378647b1a8738c43d7ecdfaf61 /com32/lib/syslinux/shuffle.c
parent9c8898254752a8d29331ab838bb9794904a3f707 (diff)
downloadsyslinux-86981dec7307fd10f98410561107bde5bff7e10b.tar.gz
shuffler: fix the handling of more than one block of descriptors
When allocating more than one block of descriptors, make sure we account for all the memory used correctly. Otherwise, very bad things happen.
Diffstat (limited to 'com32/lib/syslinux/shuffle.c')
-rw-r--r--com32/lib/syslinux/shuffle.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index cb2751af..edba4209 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -76,7 +76,7 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
struct syslinux_movelist *moves = NULL, *mp;
struct syslinux_memmap *rxmap = NULL, *ml;
struct shuffle_descriptor *dp, *dbuf;
- int np, nb, rv = -1;
+ int np, nb, nl, rv = -1;
int desc_blocks, need_blocks;
addr_t desczone, descfree, descaddr, descoffs;
int nmoves, nzero;
@@ -89,7 +89,7 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
nzero++;
}
- /* Find the larges contiguous region unused by input *and* output;
+ /* Find the largest contiguous region unused by input *and* output;
this is where we put the move descriptor list */
rxmap = syslinux_dup_memmap(memmap);
@@ -165,12 +165,13 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
/* Copy the move sequence into the descriptor buffer */
np = 0;
nb = 0;
+ nl = nmoves+nzero;
dp = dbuf;
for (mp = moves; mp; mp = mp->next) {
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);
+ dp->len = sizeof(*dp)*min(nl, DESC_BLOCK_SIZE);
dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
dp++; np++;
nb = 0;
@@ -180,7 +181,7 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
dp->src = mp->src;
dp->len = mp->len;
dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
- dp++; np++; nb++;
+ dp++; np++; nb++; nl--;
}
/* Copy bzero operations into the descriptor buffer */
@@ -189,7 +190,7 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
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);
+ dp->len = sizeof(*dp)*min(nl, DESC_BLOCK_SIZE);
dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
dp++; np++;
nb = 0;
@@ -199,10 +200,17 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
dp->src = (addr_t)-1; /* bzero region */
dp->len = ml->next->start - ml->start;
dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
- dp++; np++; nb++;
+ dp++; np++; nb++; nl--;
}
}
+#if DEBUG
+ if (np != nmoves+nzero+desc_blocks) {
+ dprintf("!!! np = %d : nmoves = %d, nzero = %d, desc_blocks = %d\n",
+ np, nmoves, nzero, desc_blocks);
+ }
+#endif
+
/* 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. */