source: bootcd/isolinux/syslinux-6.03/com32/lib/syslinux/shuffle.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[e16e8f2]1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4 *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
5 *
6 *   Permission is hereby granted, free of charge, to any person
7 *   obtaining a copy of this software and associated documentation
8 *   files (the "Software"), to deal in the Software without
9 *   restriction, including without limitation the rights to use,
10 *   copy, modify, merge, publish, distribute, sublicense, and/or
11 *   sell copies of the Software, and to permit persons to whom
12 *   the Software is furnished to do so, subject to the following
13 *   conditions:
14 *
15 *   The above copyright notice and this permission notice shall
16 *   be included in all copies or substantial portions of the Software.
17 *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 *   OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * ----------------------------------------------------------------------- */
28
29/*
30 * shuffle.c
31 *
32 * Common code for "shuffle and boot" operation; generates a shuffle list
33 * and puts it in the bounce buffer.  Returns the number of shuffle
34 * descriptors.
35 */
36
37#include <stdlib.h>
38#include <string.h>
39#include <inttypes.h>
40#include <com32.h>
41#include <core.h>
42#include <minmax.h>
43#include <dprintf.h>
44#include <syslinux/movebits.h>
45#include <klibc/compiler.h>
46#include <syslinux/boot.h>
47
48struct shuffle_descriptor {
49    uint32_t dst, src, len;
50};
51
52/*
53 * Allocate descriptor memory in these chunks; if this is large we may
54 * waste memory, if it is small we may get slow convergence.
55 */
56#define DESC_BLOCK_SIZE 256
57
58int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
59                        struct syslinux_memmap *memmap,
60                        addr_t entry_point, addr_t entry_type,
61                        uint16_t bootflags)
62{
63    int rv = -1;
64    struct syslinux_movelist *moves = NULL, *mp;
65    struct syslinux_memmap *rxmap = NULL, *ml;
66    struct shuffle_descriptor *dp, *dbuf;
67    int np;
68    int desc_blocks, need_blocks;
69    int need_ptrs;
70    addr_t desczone, descfree, descaddr;
71    int nmoves, nzero;
72
73#ifndef __FIRMWARE_BIOS__
74    errno = ENOSYS;
75    return -1;                  /* Not supported at this time*/
76#endif
77
78    descaddr = 0;
79    dp = dbuf = NULL;
80
81    /* Count the number of zero operations */
82    nzero = 0;
83    for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
84        if (ml->type == SMT_ZERO)
85            nzero++;
86    }
87
88    /* Find the largest contiguous region unused by input *and* output;
89       this is where we put the move descriptor list and safe area */
90
91    rxmap = syslinux_dup_memmap(memmap);
92    if (!rxmap)
93        goto bail;
94    /* Avoid using the low 1 MB for the shuffle area -- this avoids
95       possible interference with the real mode code or stack */
96    if (syslinux_add_memmap(&rxmap, 0, 1024 * 1024, SMT_RESERVED))
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;
102    }
103    if (syslinux_memmap_largest(rxmap, SMT_FREE, &desczone, &descfree))
104        goto bail;
105
106    syslinux_free_memmap(rxmap);
107
108    dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone, descfree);
109
110    rxmap = syslinux_dup_memmap(memmap);
111    if (!rxmap)
112        goto bail;
113
114    desc_blocks = (nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
115    for (;;) {
116        /* We want (desc_blocks) allocation blocks, plus the terminating
117           descriptor, plus the shuffler safe area. */
118        addr_t descmem = desc_blocks *
119            sizeof(struct shuffle_descriptor) * DESC_BLOCK_SIZE
120            + sizeof(struct shuffle_descriptor)
121            + syslinux_shuffler_size();
122
123        descaddr = (desczone + descfree - descmem) & ~3;
124
125        if (descaddr < desczone)
126            goto bail;          /* No memory block large enough */
127
128        /* Mark memory used by shuffle descriptors as reserved */
129        if (syslinux_add_memmap(&rxmap, descaddr, descmem, SMT_RESERVED))
130            goto bail;
131
132#if DEBUG > 1
133        syslinux_dump_movelist(fraglist);
134#endif
135
136        if (syslinux_compute_movelist(&moves, fraglist, rxmap))
137            goto bail;
138
139        nmoves = 0;
140        for (mp = moves; mp; mp = mp->next)
141            nmoves++;
142
143        need_blocks = (nmoves + nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
144
145        if (desc_blocks >= need_blocks)
146            break;              /* Sufficient memory, yay */
147
148        desc_blocks = need_blocks;      /* Try again... */
149    }
150
151#if DEBUG > 1
152    dprintf("Final movelist:\n");
153    syslinux_dump_movelist(moves);
154#endif
155
156    syslinux_free_memmap(rxmap);
157    rxmap = NULL;
158
159    need_ptrs = nmoves + nzero + 1;
160    dbuf = malloc(need_ptrs * sizeof(struct shuffle_descriptor));
161    if (!dbuf)
162        goto bail;
163
164#if DEBUG
165    {
166        addr_t descoffs = descaddr - (addr_t) dbuf;
167
168        dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n",
169                nmoves, nzero, dbuf, descoffs);
170    }
171#endif
172
173    /* Copy the move sequence into the descriptor buffer */
174    np = 0;
175    dp = dbuf;
176    for (mp = moves; mp; mp = mp->next) {
177        dp->dst = mp->dst;
178        dp->src = mp->src;
179        dp->len = mp->len;
180        dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
181        dp++;
182        np++;
183    }
184
185    /* Copy bzero operations into the descriptor buffer */
186    for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
187        if (ml->type == SMT_ZERO) {
188            dp->dst = ml->start;
189            dp->src = (addr_t) - 1;     /* bzero region */
190            dp->len = ml->next->start - ml->start;
191            dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
192            dp++;
193            np++;
194        }
195    }
196
197    /* Finally, record the termination entry */
198    dp->dst = entry_point;
199    dp->src = entry_type;
200    dp->len = 0;
201    dp++;
202    np++;
203
204    if (np != need_ptrs) {
205        dprintf("!!! np = %d : nmoves = %d, nzero = %d, desc_blocks = %d\n",
206                np, nmoves, nzero, desc_blocks);
207    }
208
209    rv = 0;
210
211bail:
212    /* This is safe only because free() doesn't use the bounce buffer!!!! */
213    if (moves)
214        syslinux_free_movelist(moves);
215    if (rxmap)
216        syslinux_free_memmap(rxmap);
217
218    if (rv)
219        return rv;
220
221    /* Actually do it... */
222    bios_do_shuffle_and_boot(bootflags, descaddr, dbuf,
223                             (size_t)dp - (size_t)dbuf);
224
225    return -1;                  /* Shouldn't have returned! */
226}
227
228/*
229 * Common helper routine: takes a memory map and blots out the
230 * zones which are used in the destination of a fraglist
231 */
232struct syslinux_memmap *syslinux_target_memmap(struct syslinux_movelist
233                                               *fraglist,
234                                               struct syslinux_memmap *memmap)
235{
236    struct syslinux_memmap *tmap;
237    struct syslinux_movelist *mp;
238
239    tmap = syslinux_dup_memmap(memmap);
240    if (!tmap)
241        return NULL;
242
243    for (mp = fraglist; mp; mp = mp->next) {
244        if (syslinux_add_memmap(&tmap, mp->dst, mp->len, SMT_ALLOC)) {
245            syslinux_free_memmap(tmap);
246            return NULL;
247        }
248    }
249
250    return tmap;
251}
Note: See TracBrowser for help on using the repository browser.