Adding upstream version 3.62+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / syslinux / shuffle.c
blobcb2751afa98d7b20b8922c61bd4ff71ca92cce0b
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
29 * shuffle.c
31 * Common code for "shuffle and boot" operation; generates a shuffle list
32 * and puts it in the bounce buffer. Returns the number of shuffle
33 * descriptors.
36 #include <stdlib.h>
37 #include <string.h>
38 #include <inttypes.h>
39 #include <com32.h>
40 #include <minmax.h>
41 #include <syslinux/movebits.h>
42 #include <klibc/compiler.h>
44 #ifndef DEBUG
45 # define DEBUG 0
46 #endif
47 #if DEBUG
48 # include <stdio.h>
49 # define dprintf printf
50 #else
51 # define dprintf(f, ...) ((void)0)
52 #endif
54 struct shuffle_descriptor {
55 uint32_t dst, src, len;
58 static int desc_block_size;
60 static void __constructor __syslinux_get_desc_block_size(void)
62 static com32sys_t reg;
64 reg.eax.w[0] = 0x0011;
65 __intcall(0x22, &reg, &reg);
67 desc_block_size = (reg.eflags.l & EFLAGS_CF) ? 64 : reg.ecx.w[0];
70 /* Allocate descriptor memory in these chunks */
71 #define DESC_BLOCK_SIZE desc_block_size
73 int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
74 struct syslinux_memmap *memmap)
76 struct syslinux_movelist *moves = NULL, *mp;
77 struct syslinux_memmap *rxmap = NULL, *ml;
78 struct shuffle_descriptor *dp, *dbuf;
79 int np, nb, rv = -1;
80 int desc_blocks, need_blocks;
81 addr_t desczone, descfree, descaddr, descoffs;
82 int nmoves, nzero;
83 struct shuffle_descriptor primaries[2];
85 /* Count the number of zero operations */
86 nzero = 0;
87 for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
88 if (ml->type == SMT_ZERO)
89 nzero++;
92 /* Find the larges contiguous region unused by input *and* output;
93 this is where we put the move descriptor list */
95 rxmap = syslinux_dup_memmap(memmap);
96 if (!rxmap)
97 goto bail;
98 for (mp = fraglist; mp; mp = mp->next) {
99 if (syslinux_add_memmap(&rxmap, mp->src, mp->len, SMT_ALLOC) ||
100 syslinux_add_memmap(&rxmap, mp->dst, mp->len, SMT_ALLOC))
101 goto bail;
103 if (syslinux_memmap_largest(rxmap, SMT_FREE, &desczone, &descfree))
104 goto bail;
106 syslinux_free_memmap(rxmap);
108 dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone, descfree);
110 rxmap = syslinux_dup_memmap(memmap);
111 if (!rxmap)
112 goto bail;
114 desc_blocks = (nzero+DESC_BLOCK_SIZE)/(DESC_BLOCK_SIZE-1);
115 for (;;) {
116 addr_t descmem = desc_blocks*
117 sizeof(struct shuffle_descriptor)*DESC_BLOCK_SIZE;
119 if (descfree < descmem)
120 goto bail; /* No memory block large enough */
122 /* Mark memory used by shuffle descriptors as reserved */
123 descaddr = desczone + descfree - descmem;
124 if (syslinux_add_memmap(&rxmap, descaddr, descmem, SMT_RESERVED))
125 goto bail;
127 #if DEBUG
128 syslinux_dump_movelist(stdout, fraglist);
129 #endif
131 if (syslinux_compute_movelist(&moves, fraglist, rxmap))
132 goto bail;
134 nmoves = 0;
135 for (mp = moves; mp; mp = mp->next)
136 nmoves++;
138 need_blocks = (nmoves+nzero)/(DESC_BLOCK_SIZE-1);
140 if (desc_blocks >= need_blocks)
141 break; /* Sufficient memory, yay */
143 desc_blocks = need_blocks; /* Try again... */
146 #if DEBUG
147 dprintf("Final movelist:\n");
148 syslinux_dump_movelist(stdout, moves);
149 #endif
151 syslinux_free_memmap(rxmap);
152 rxmap = NULL;
154 dbuf = malloc((nmoves+nzero+desc_blocks)*sizeof(struct shuffle_descriptor));
155 if (!dbuf)
156 goto bail;
158 descoffs = descaddr - (addr_t)dbuf;
160 #if DEBUG
161 dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n",
162 nmoves, nzero, dbuf, descoffs);
163 #endif
165 /* Copy the move sequence into the descriptor buffer */
166 np = 0;
167 nb = 0;
168 dp = dbuf;
169 for (mp = moves; mp; mp = mp->next) {
170 if (nb == DESC_BLOCK_SIZE-1) {
171 dp->dst = -1; /* Load new descriptors */
172 dp->src = (addr_t)(dp+1) + descoffs;
173 dp->len = sizeof(*dp)*min(nmoves, DESC_BLOCK_SIZE);
174 dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
175 dp++; np++;
176 nb = 0;
179 dp->dst = mp->dst;
180 dp->src = mp->src;
181 dp->len = mp->len;
182 dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
183 dp++; np++; nb++;
186 /* Copy bzero operations into the descriptor buffer */
187 for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
188 if (ml->type == SMT_ZERO) {
189 if (nb == DESC_BLOCK_SIZE-1) {
190 dp->dst = (addr_t)-1; /* Load new descriptors */
191 dp->src = (addr_t)(dp+1) + descoffs;
192 dp->len = sizeof(*dp)*min(nmoves, DESC_BLOCK_SIZE);
193 dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
194 dp++; np++;
195 nb = 0;
198 dp->dst = ml->start;
199 dp->src = (addr_t)-1; /* bzero region */
200 dp->len = ml->next->start - ml->start;
201 dprintf("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
202 dp++; np++; nb++;
206 /* Set up the primary descriptors in the bounce buffer.
207 The first one moves the descriptor list into its designated safe
208 zone, the second one loads the first descriptor block. */
209 dp = primaries;
211 dp->dst = descaddr;
212 dp->src = (addr_t)dbuf;
213 dp->len = np*sizeof(*dp);
214 dprintf("< %08x %08x %08x >\n", dp->dst, dp->src, dp->len);
215 dp++;
217 dp->dst = (addr_t)-1;
218 dp->src = descaddr;
219 dp->len = sizeof(*dp)*min(np, DESC_BLOCK_SIZE);
220 dprintf("< %08x %08x %08x >\n", dp->dst, dp->src, dp->len);
221 dp++;
223 memcpy(__com32.cs_bounce, primaries, 2*sizeof(*dp));
225 rv = 2; /* Always two primaries */
227 bail:
228 /* This is safe only because free() doesn't use the bounce buffer!!!! */
229 if (moves)
230 syslinux_free_movelist(moves);
231 if (rxmap)
232 syslinux_free_memmap(rxmap);
234 return rv;