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
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 * ----------------------------------------------------------------------- */
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
41 #include <syslinux/movebits.h>
42 #include <klibc/compiler.h>
49 # define dprintf printf
51 # define dprintf(f, ...) ((void)0)
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, ®
, ®
);
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
;
80 int desc_blocks
, need_blocks
;
81 addr_t desczone
, descfree
, descaddr
, descoffs
;
83 struct shuffle_descriptor primaries
[2];
85 /* Count the number of zero operations */
87 for (ml
= memmap
; ml
->type
!= SMT_END
; ml
= ml
->next
) {
88 if (ml
->type
== SMT_ZERO
)
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
);
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
))
103 if (syslinux_memmap_largest(rxmap
, SMT_FREE
, &desczone
, &descfree
))
106 syslinux_free_memmap(rxmap
);
108 dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone
, descfree
);
110 rxmap
= syslinux_dup_memmap(memmap
);
114 desc_blocks
= (nzero
+DESC_BLOCK_SIZE
)/(DESC_BLOCK_SIZE
-1);
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
))
128 syslinux_dump_movelist(stdout
, fraglist
);
131 if (syslinux_compute_movelist(&moves
, fraglist
, rxmap
))
135 for (mp
= moves
; mp
; mp
= mp
->next
)
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... */
147 dprintf("Final movelist:\n");
148 syslinux_dump_movelist(stdout
, moves
);
151 syslinux_free_memmap(rxmap
);
154 dbuf
= malloc((nmoves
+nzero
+desc_blocks
)*sizeof(struct shuffle_descriptor
));
158 descoffs
= descaddr
- (addr_t
)dbuf
;
161 dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n",
162 nmoves
, nzero
, dbuf
, descoffs
);
165 /* Copy the move sequence into the descriptor buffer */
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
);
182 dprintf("[ %08x %08x %08x ]\n", dp
->dst
, dp
->src
, dp
->len
);
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
);
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
);
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. */
212 dp
->src
= (addr_t
)dbuf
;
213 dp
->len
= np
*sizeof(*dp
);
214 dprintf("< %08x %08x %08x >\n", dp
->dst
, dp
->src
, dp
->len
);
217 dp
->dst
= (addr_t
)-1;
219 dp
->len
= sizeof(*dp
)*min(np
, DESC_BLOCK_SIZE
);
220 dprintf("< %08x %08x %08x >\n", dp
->dst
, dp
->src
, dp
->len
);
223 memcpy(__com32
.cs_bounce
, primaries
, 2*sizeof(*dp
));
225 rv
= 2; /* Always two primaries */
228 /* This is safe only because free() doesn't use the bounce buffer!!!! */
230 syslinux_free_movelist(moves
);
232 syslinux_free_memmap(rxmap
);