11 # define dprintf printf
13 # define dprintf(...) ((void)0)
16 #define min(x,y) ((x) < (y) ? (x) : (y))
17 #define max(x,y) ((x) > (y) ? (x) : (y))
20 * Public utility function
22 * Creates a movelist consisting of only one element, and
23 * if parent == NULL insert into the movelist chain immediately after
27 make_movelist(struct movelist
*pptr
, uintptr_t dst
, uintptr_t src
, uintptr_t len
)
29 struct movelist
*ml
= malloc(sizeof(struct movelist
));
37 ml
->next
= pptr
? pptr
->next
: NULL
;
46 * Public utility function
48 * Convert a movelist into a linear array of struct move_descriptors
51 linearize_movelist(struct move_descriptor
**d
, struct movelist
*m
)
55 struct move_descriptor
*l
;
57 /* Count the length of the list */
59 for ( mm
= m
; mm
; mm
= mm
->next
)
62 *d
= l
= malloc(n
* sizeof(struct move_descriptor
));
80 static jmp_buf new_movelist_bail
;
82 static struct movelist
*
83 new_movelist(uintptr_t dst
, uintptr_t src
, uintptr_t len
)
85 struct movelist
*ml
= malloc(sizeof(struct movelist
));
88 longjmp(new_movelist_bail
, 1);
98 static struct movelist
**
99 split_movelist(uintptr_t start
, uintptr_t len
, struct movelist
**parentptr
)
101 struct movelist
*m
, *ml
= *parentptr
;
103 assert(start
>= ml
->src
);
104 assert(start
< ml
->src
+ml
->len
);
106 /* Split off the beginning */
107 if ( start
> ml
->src
) {
108 uintptr_t l
= start
- ml
->src
;
110 m
= new_movelist(ml
->dst
+l
, start
, ml
->len
-l
);
115 parentptr
= &ml
->next
;
116 ml
= m
; /* Continue processing the new node */
119 if ( ml
->len
> len
) {
120 uintptr_t l
= ml
->len
- len
;
122 m
= new_movelist(ml
->dst
+len
, ml
->src
+len
, l
);
133 delete_movelist(struct movelist
**parentptr
)
135 struct movelist
*o
= *parentptr
;
136 *parentptr
= o
->next
;
142 * Scan the freelist looking for a particular chunk of memory
144 static struct movelist
**
145 is_free_zone(uintptr_t start
, uintptr_t len
, struct movelist
**space
)
149 while ( (s
= *space
) ) {
150 if ( s
->src
<= start
&& s
->src
+s
->len
>= start
+len
)
159 * Scan the freelist looking for the smallest chunk of memory which
162 static struct movelist
**
163 free_area(uintptr_t len
, struct movelist
**space
)
165 struct movelist
**best
= NULL
;
168 while ( (s
= *space
) ) {
169 if ( s
->len
>= len
) {
170 if ( !best
|| (*best
)->len
> s
->len
)
181 * Scan the freelist looking for the largest chunk of memory, returns parent ptr
183 static struct movelist
**
184 free_area_max(struct movelist
**space
)
186 struct movelist
**best
= NULL
;
189 while ( (s
= *space
) ) {
190 if ( !best
|| s
->len
> (*best
)->len
)
199 * Remove a chunk from the freelist
202 allocate_from(uintptr_t start
, uintptr_t len
, struct movelist
**parentptr
)
204 struct movelist
*c
= *parentptr
;
206 assert(c
->src
<= start
);
207 assert(c
->src
+c
->len
>= start
+len
);
209 if ( c
->src
!= start
|| c
->len
!= len
) {
210 parentptr
= split_movelist(start
, len
, parentptr
);
214 *parentptr
= c
->next
;
219 * Remove any chunk from the freelist which is already
220 * claimed by source data. This somewhat frivolously
221 * assumes that the fragments are either completely
222 * covered by a free zone or not covered at all.
225 tidy_freelist(struct movelist
**frags
, struct movelist
**space
)
227 struct movelist
**sep
;
230 while ( (f
= *frags
) ) {
231 if ( (sep
= is_free_zone(f
->src
, f
->len
, space
)) )
232 allocate_from(f
->src
, f
->len
, sep
);
238 * moves is computed from "frags" and "freemem". "space" lists
239 * free memory areas at our disposal, and is (src, cnt) only.
243 compute_movelist(struct movelist
**moves
, struct movelist
*frags
,
244 struct movelist
*space
)
247 struct movelist
*f
, **fp
, **ep
;
248 struct movelist
*o
, **op
;
249 uintptr_t needbase
, needlen
, copysrc
, copydst
, copylen
;
250 uintptr_t freebase
, freelen
;
254 if ( setjmp(new_movelist_bail
) )
255 return -1; /* malloc() failed */
257 tidy_freelist(&frags
, &space
);
259 for ( fp
= &frags
, f
= *fp
; f
; fp
= &f
->next
, f
= *fp
) {
260 dprintf("@: 0x%08x bytes at 0x%08x -> 0x%08x\n",
261 f
->len
, f
->src
, f
->dst
);
263 if ( f
->src
== f
->dst
) {
264 //delete_movelist(fp); /* Already in the right place! */
268 /* See if we can move this chunk into place by claiming
269 the destination, or in the case of partial overlap, the
275 dprintf("need: base = 0x%08x, len = 0x%08x\n", needbase
, needlen
);
277 if ( f
->src
< f
->dst
&& (f
->dst
- f
->src
) < f
->len
) {
278 /* "Shift up" type overlap */
279 needlen
= f
->dst
- f
->src
;
280 needbase
= f
->dst
+ (f
->len
- needlen
);
281 } else if ( f
->src
> f
->dst
&& (f
->src
- f
->dst
) < f
->len
) {
282 /* "Shift down" type overlap */
284 needlen
= f
->src
- f
->dst
;
287 if ( (ep
= is_free_zone(needbase
, 1, &space
)) ) {
288 /* We can move at least part of this chunk into place without further ado */
289 copylen
= min(needlen
, (*ep
)->len
);
290 allocate_from(needbase
, copylen
, ep
);
294 /* At this point, we need to evict something out of our space.
295 Find the object occupying the first byte of our target space,
296 and move it out (the whole object if we can, otherwise a subset.)
297 Then move a chunk of ourselves into place. */
298 for ( op
= &f
->next
, o
= *op
; o
; op
= &o
->next
, o
= *op
) {
300 dprintf("O: 0x%08x bytes at 0x%08x -> 0x%08x\n",
301 o
->len
, o
->src
, o
->dst
);
303 if ( !(o
->src
<= needbase
&& o
->src
+o
->len
> needbase
) )
304 continue; /* Not what we're looking for... */
306 /* Find somewhere to put it... */
307 if ( (ep
= free_area(o
->len
, &space
)) ) {
308 /* We got what we wanted... */
309 copydst
= (*ep
)->src
;
312 ep
= free_area_max(&space
);
314 return -1; /* Stuck! */
315 copydst
= (*ep
)->src
;
316 copylen
= (*ep
)->len
;
318 allocate_from(copydst
, copylen
, ep
);
320 if ( copylen
>= o
->len
- (needbase
-o
->src
) ) {
321 copysrc
= o
->src
+ (o
->len
- copylen
);
326 if ( copylen
< o
->len
) {
327 op
= split_movelist(copysrc
, copylen
, op
);
331 mv
= new_movelist(copydst
, copysrc
, copylen
);
332 dprintf("C: 0x%08x bytes at 0x%08x -> 0x%08x\n",
333 mv
->len
, mv
->src
, mv
->dst
);
339 if ( copylen
> needlen
) {
340 /* We don't need all the memory we freed up. Mark it free. */
341 if ( copysrc
< needbase
) {
342 mv
= new_movelist(0, copysrc
, needbase
-copysrc
);
345 copylen
-= (needbase
-copysrc
);
347 if ( copylen
> needlen
) {
348 mv
= new_movelist(0, copysrc
+needlen
, copylen
-needlen
);
356 return -1; /* Stuck! */
359 /* We're allowed to move the chunk into place now. */
361 if ( copylen
< needlen
) {
362 /* Didn't get all we wanted, so we have to split the chunk */
363 fp
= split_movelist(f
->src
, copylen
+(needbase
-f
->dst
), fp
);
367 mv
= new_movelist(f
->dst
, f
->src
, f
->len
);
368 dprintf("A: 0x%08x bytes at 0x%08x -> 0x%08x\n",
369 mv
->len
, mv
->src
, mv
->dst
);
373 /* Figure out what memory we just freed up */
374 if ( f
->dst
> f
->src
) {
376 freelen
= min(f
->len
, f
->dst
-f
->src
);
377 } else if ( f
->src
>= f
->dst
+f
->len
) {
381 freelen
= f
->src
-f
->dst
;
382 freebase
= f
->dst
+f
->len
;
385 mv
= new_movelist(0, freebase
, freelen
);
397 int main(int argc
, char *argv
[])
400 unsigned long d
, s
, l
;
401 struct movelist
*frags
;
402 struct movelist
**fep
= &frags
;
403 struct movelist
*space
;
404 struct movelist
**sep
= &space
;
405 struct movelist
*mv
, *moves
;
407 f
= fopen(argv
[1], "r");
408 while ( fscanf(f
, "%lx %lx %lx", &d
, &s
, &l
) == 3 ) {
410 mv
= new_movelist(d
, s
, l
);
414 mv
= new_movelist(0, s
, l
);
421 if ( compute_movelist(&moves
, frags
, space
) ) {
422 printf("Failed to compute a move sequence\n");
425 for ( mv
= moves
; mv
; mv
= mv
->next
) {
426 printf("0x%08x bytes at 0x%08x -> 0x%08x\n",
427 mv
->len
, mv
->src
, mv
->dst
);