1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include <stdlib.h>
38#include <string.h>
39#include <inttypes.h>
40#include <com32.h>
41#include <minmax.h>
42#include <dprintf.h>
43#include <syslinux/movebits.h>
44#include <klibc/compiler.h>
45
46struct shuffle_descriptor {
47 uint32_t dst, src, len;
48};
49
50static int shuffler_size;
51
52static void __constructor __syslinux_get_shuffer_size(void)
53{
54 static com32sys_t reg;
55
56 reg.eax.w[0] = 0x0023;
57 __intcall(0x22, ®, ®);
58
59 shuffler_size = (reg.eflags.l & EFLAGS_CF) ? 2048 : reg.ecx.w[0];
60}
61
62
63
64
65
66#define DESC_BLOCK_SIZE 256
67
68int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
69 struct syslinux_memmap *memmap,
70 addr_t entry_point, addr_t entry_type,
71 uint16_t bootflags)
72{
73 int rv = -1;
74 struct syslinux_movelist *moves = NULL, *mp;
75 struct syslinux_memmap *rxmap = NULL, *ml;
76 struct shuffle_descriptor *dp, *dbuf;
77 int np;
78 int desc_blocks, need_blocks;
79 int need_ptrs;
80 addr_t desczone, descfree, descaddr;
81 int nmoves, nzero;
82 com32sys_t ireg;
83
84 descaddr = 0;
85 dp = dbuf = NULL;
86
87
88 nzero = 0;
89 for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
90 if (ml->type == SMT_ZERO)
91 nzero++;
92 }
93
94
95
96
97 rxmap = syslinux_dup_memmap(memmap);
98 if (!rxmap)
99 goto bail;
100
101
102 if (syslinux_add_memmap(&rxmap, 0, 1024 * 1024, SMT_RESERVED))
103 goto bail;
104 for (mp = fraglist; mp; mp = mp->next) {
105 if (syslinux_add_memmap(&rxmap, mp->src, mp->len, SMT_ALLOC) ||
106 syslinux_add_memmap(&rxmap, mp->dst, mp->len, SMT_ALLOC))
107 goto bail;
108 }
109 if (syslinux_memmap_largest(rxmap, SMT_FREE, &desczone, &descfree))
110 goto bail;
111
112 syslinux_free_memmap(rxmap);
113
114 dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone, descfree);
115
116 rxmap = syslinux_dup_memmap(memmap);
117 if (!rxmap)
118 goto bail;
119
120 desc_blocks = (nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
121 for (;;) {
122
123
124 addr_t descmem = desc_blocks *
125 sizeof(struct shuffle_descriptor) * DESC_BLOCK_SIZE
126 + sizeof(struct shuffle_descriptor) + shuffler_size;
127
128 descaddr = (desczone + descfree - descmem) & ~3;
129
130 if (descaddr < desczone)
131 goto bail;
132
133
134 if (syslinux_add_memmap(&rxmap, descaddr, descmem, SMT_RESERVED))
135 goto bail;
136
137#if DEBUG > 1
138 syslinux_dump_movelist(stdout, fraglist);
139#endif
140
141 if (syslinux_compute_movelist(&moves, fraglist, rxmap))
142 goto bail;
143
144 nmoves = 0;
145 for (mp = moves; mp; mp = mp->next)
146 nmoves++;
147
148 need_blocks = (nmoves + nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
149
150 if (desc_blocks >= need_blocks)
151 break;
152
153 desc_blocks = need_blocks;
154 }
155
156#if DEBUG > 1
157 dprintf("Final movelist:\n");
158 syslinux_dump_movelist(stdout, moves);
159#endif
160
161 syslinux_free_memmap(rxmap);
162 rxmap = NULL;
163
164 need_ptrs = nmoves + nzero + 1;
165 dbuf = malloc(need_ptrs * sizeof(struct shuffle_descriptor));
166 if (!dbuf)
167 goto bail;
168
169#if DEBUG
170 {
171 addr_t descoffs = descaddr - (addr_t) dbuf;
172
173 dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n",
174 nmoves, nzero, dbuf, descoffs);
175 }
176#endif
177
178
179 np = 0;
180 dp = dbuf;
181 for (mp = moves; mp; mp = mp->next) {
182 dp->dst = mp->dst;
183 dp->src = mp->src;
184 dp->len = mp->len;
185 dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
186 dp++;
187 np++;
188 }
189
190
191 for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
192 if (ml->type == SMT_ZERO) {
193 dp->dst = ml->start;
194 dp->src = (addr_t) - 1;
195 dp->len = ml->next->start - ml->start;
196 dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
197 dp++;
198 np++;
199 }
200 }
201
202
203 dp->dst = entry_point;
204 dp->src = entry_type;
205 dp->len = 0;
206 dp++;
207 np++;
208
209 if (np != need_ptrs) {
210 dprintf("!!! np = %d : nmoves = %d, nzero = %d, desc_blocks = %d\n",
211 np, nmoves, nzero, desc_blocks);
212 }
213
214 rv = 0;
215
216bail:
217
218 if (moves)
219 syslinux_free_movelist(moves);
220 if (rxmap)
221 syslinux_free_memmap(rxmap);
222
223 if (rv)
224 return rv;
225
226
227 memset(&ireg, 0, sizeof ireg);
228 ireg.edi.l = descaddr;
229 ireg.esi.l = (addr_t) dbuf;
230 ireg.ecx.l = (addr_t) dp - (addr_t) dbuf;
231 ireg.edx.w[0] = bootflags;
232 ireg.eax.w[0] = 0x0024;
233 __intcall(0x22, &ireg, NULL);
234
235 return -1;
236}
237
238
239
240
241
242struct syslinux_memmap *syslinux_target_memmap(struct syslinux_movelist
243 *fraglist,
244 struct syslinux_memmap *memmap)
245{
246 struct syslinux_memmap *tmap;
247 struct syslinux_movelist *mp;
248
249 tmap = syslinux_dup_memmap(memmap);
250 if (!tmap)
251 return NULL;
252
253 for (mp = fraglist; mp; mp = mp->next) {
254 if (syslinux_add_memmap(&tmap, mp->dst, mp->len, SMT_ALLOC)) {
255 syslinux_free_memmap(tmap);
256 return NULL;
257 }
258 }
259
260 return tmap;
261}
262