2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
9 #include <exec/execbase.h>
10 #include <exec/memory.h>
11 #include <dos/dosasl.h>
12 #include <dos/doshunks.h>
13 #include <dos/dosextens.h>
14 #include <proto/exec.h>
15 #include <proto/dos.h>
16 #include <proto/arossupport.h>
17 #include <aros/asmcall.h>
18 #include <aros/debug.h>
19 #include <aros/macros.h>
21 #include "dos_intern.h"
22 #include "internalloadseg.h"
24 #include <proto/dos.h>
26 #define GETHUNKPTR(x) ((UBYTE*)(BADDR(hunktab[x]) + sizeof(BPTR)))
28 /* Seek forward by count ULONGs.
29 * Returns 0 on success, 1 on failure.
31 static int seek_forward(BPTR fd
, ULONG count
, SIPTR
*funcarray
, struct DosLibrary
*DOSBase
)
36 /* For AOS compatibility, we can't use DOS/Seek() here,
37 * as AOS callers to InternalLoadSeg will not pass
38 * in a Seek element of the funcarray, and the read
39 * callback of funcarray may be for reading in-memory
40 * instead of pointing to DOS/Read.
42 * Luckily, reading HUNKs is linear, so we can just
45 while (count
&& !(err
= read_block(fd
, &tmp
, sizeof(tmp
), funcarray
, DOSBase
)))
51 BPTR
InternalLoadSeg_AOS(BPTR fh
,
55 struct DosLibrary
* DOSBase
)
57 #define ERROR(a) { *error=a; goto end; }
60 BPTR
*hunktab
= BADDR(table
);
61 BPTR firsthunk
= BNULL
, prevhunk
= BNULL
;
62 ULONG hunktype
, count
, first
, last
, curhunk
, numhunks
;
67 UBYTE
*overlaytable
= NULL
;
71 static STRPTR segtypes
[] = { "CODE", "DATA", "BSS", };
75 SIPTR
*error
= &dummy
;
78 error
=&((struct Process
*)FindTask(NULL
))->pr_Result2
;
80 curhunk
= 0; /* keep GCC quiet */
81 /* start point is HUNK_HEADER + 4 */
84 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
88 count
= AROS_BE2LONG(count
);
90 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
92 D(bug("\tlibname: \"%.*s\"\n", count
, name_buf
));
94 if (read_block(fh
, &numhunks
, sizeof(numhunks
), funcarray
, DOSBase
))
97 numhunks
= AROS_BE2LONG(numhunks
);
99 D(bug("\tHunk count: %ld\n", numhunks
));
102 hunktab
= ilsAllocVec(sizeof(BPTR
) * (numhunks
+ 1 + 1), MEMF_CLEAR
);
104 ERROR(ERROR_NO_FREE_STORE
);
107 if (read_block(fh
, &first
, sizeof(first
), funcarray
, DOSBase
))
110 first
= AROS_BE2LONG(first
);
112 D(bug("\tFirst hunk: %ld\n", first
));
114 if (read_block(fh
, &last
, sizeof(last
), funcarray
, DOSBase
))
117 last
= AROS_BE2LONG(last
);
119 D(bug("\tLast hunk: %ld\n", last
));
121 for (i
= first
; i
<= numhunks
; i
++) {
130 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
133 count
= AROS_BE2LONG(count
);
135 tmp
= count
& 0xFF000000;
137 D(bug("\tHunk %d size: 0x%06lx bytes in ", i
, count
*4));
138 req
= MEMF_CLEAR
| MEMF_PUBLIC
;
154 if (read_block(fh
, &req
, sizeof(req
), funcarray
, DOSBase
))
156 req
= AROS_BE2LONG(req
);
167 * We need space for the code, the length of this hunk and
168 * for a pointer to the next hunk.
169 * Note also MEMF_31BIT flag appended to memory requirements.
170 * This is important on 64-bit machines where AmigaDOS hunk
171 * files need to be loaded into low memory (<2GB). This is needed
172 * for correct interpretation of pointers in these files.
173 * Yes, they can't be executed in such environments, but they still can
174 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
176 hunksize
= count
* 4 + sizeof(ULONG
) + sizeof(BPTR
);
177 hunkptr
= ilsAllocVec(hunksize
, req
| MEMF_31BIT
);
179 ERROR(ERROR_NO_FREE_STORE
);
180 hunktab
[i
] = MKBADDR(hunkptr
);
181 D(bug(" @%p\n", hunkptr
));
183 firsthunk
= hunktab
[i
];
185 if this is not the first hunk that is loaded, then connect
186 it to the previous one (pointer to the field where the
187 pointer to the next hunk is located)
190 ((BPTR
*)(BADDR(prevhunk
)))[0] = hunktab
[i
];
191 prevhunk
= hunktab
[i
];
194 while(!read_block(fh
, &hunktype
, sizeof(hunktype
), funcarray
, DOSBase
))
196 hunktype
= AROS_BE2LONG(hunktype
);
197 D(bug("Hunk Type: %d\n", hunktype
& 0xFFFFFF));
199 switch(hunktype
& 0xFFFFFF)
202 /* The SYMBOL_HUNK looks like this:
203 ---------------------
205 | symbol in longs | may
206 |-------------------| be
207 | n longwords = name| repeated
209 |-------------------| number
210 | value (1 long) | of times
211 --------------------|
214 -------------------- */
216 D(bug("HUNK_SYMBOL (skipping)\n"));
217 while(!read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
) && count
)
219 count
= AROS_BE2LONG(count
) ;
221 if (seek_forward(fh
, count
+1, funcarray
, DOSBase
))
228 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
231 count
= AROS_BE2LONG(count
) ;
234 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
236 D(bug("HUNK_UNIT: \"%.*s\"\n", count
, name_buf
));
243 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
246 count
= AROS_BE2LONG(count
);
248 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
249 segtypes
[(hunktype
& 0xFFFFFF)-HUNK_CODE
], curhunk
, count
*4));
251 switch(hunktype
& 0xFF000000)
265 if (read_block(fh
, &req
, sizeof(req
), funcarray
, DOSBase
))
268 req
= AROS_BE2LONG(req
);
279 if ((hunktype
& 0xFFFFFF) != HUNK_BSS
&& count
)
281 if (read_block(fh
, GETHUNKPTR(curhunk
), count
*4, funcarray
, DOSBase
))
288 D(bug("HUNK_RELOC32:\n"));
294 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
299 count
= AROS_BE2LONG(count
);
302 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
305 count
= AROS_BE2LONG(count
);
307 D(bug("\tHunk #%ld:\n", count
));
310 if (read_block(fh
, &offset
, sizeof(offset
), funcarray
, DOSBase
))
313 offset
= AROS_BE2LONG(offset
);
315 //D(bug("\t\t0x%06lx\n", offset));
316 addr
= (ULONG
*)(GETHUNKPTR(curhunk
) + offset
);
318 /* See the above MEMF_31 explanation for why this
319 * works on AROS 64-bit.
321 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
328 case HUNK_DREL32
: /* For compatibility with V37 */
329 case HUNK_RELOC32SHORT
:
341 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
346 word
= AROS_BE2LONG(word
);
350 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
353 word
= AROS_BE2WORD(word
);
356 D(bug("\tHunk #%ld @%p: %ld relocations\n", count
, GETHUNKPTR(curhunk
), i
));
360 /* read a 16bit number (2 bytes) */
361 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
364 /* offset now contains the byte offset in it`s 16 highest bits.
365 These 16 highest bits have to become the 16 lowest bits so
366 we get the word we need. */
367 offset
= AROS_BE2WORD(word
);
369 D(bug("\t\t0x%06lx += 0x%lx\n", offset
, GETHUNKPTR(count
)));
370 addr
= (ULONG
*)(GETHUNKPTR(curhunk
) + offset
);
372 /* See the above MEMF_31 explanation for why this
373 * works on AROS 64-bit.
375 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
381 /* if the amount of words read was odd, then skip the following
383 if (0x1 == (Wordcount
& 0x1)) {
385 read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
);
392 D(bug("HUNK_END\n"));
394 /* DOSBase == NULL: Called from RDB filesystem loader which does not
395 * know filesystem's original size. Exit if last HUNK_END. This can't
396 * be done normally because it would break overlayed executables.
398 if (!DOSBase
&& curhunk
> last
)
404 bug("HUNK_RELOC16 not implemented\n");
405 ERROR(ERROR_BAD_HUNK
);
408 bug("HUNK_RELOC8 not implemented\n");
409 ERROR(ERROR_BAD_HUNK
);
412 bug("HUNK_NAME not implemented\n");
413 ERROR(ERROR_BAD_HUNK
);
416 bug("HUNK_EXT not implemented\n");
417 ERROR(ERROR_BAD_HUNK
);
420 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
423 count
= AROS_BE2LONG(count
);
425 D(bug("HUNK_DEBUG (%x Bytes)\n",count
));
426 if (seek_forward(fh
, count
, funcarray
, DOSBase
))
432 D(bug("HUNK_OVERLAY:\n"));
433 if (table
) /* overlay inside overlay? */
434 ERROR(ERROR_BAD_HUNK
);
435 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
437 count
= AROS_BE2LONG(count
);
438 D(bug("Overlay table size: %d\n", count
));
440 /* See above for MEMF_31BIT explanation */
441 count
= count
* 4 + sizeof(ULONG
) + sizeof(ULONG
);
442 overlaytable
= ilsAllocVec(count
, MEMF_CLEAR
| MEMF_31BIT
);
443 if (overlaytable
== NULL
)
444 ERROR(ERROR_NO_FREE_STORE
);
445 if (read_block(fh
, overlaytable
, count
- sizeof(ULONG
), funcarray
, DOSBase
))
451 D(bug("HUNK_BREAK\n"));
453 ERROR(ERROR_BAD_HUNK
);
457 bug("Hunk type 0x%06lx not implemented\n", hunktype
& 0xFFFFFF);
458 ERROR(ERROR_BAD_HUNK
);
468 * On non-m68k systems, hunk files are not executable.
469 * And even if AROS ever gets m68k emulator, they are still data files.
470 * So we flush caches only on m68k.
472 if (SysBase
->LibNode
.lib_Version
>= 36)
475 for (t
= first
; t
< numhunks
&& t
<= last
; t
++)
477 hunksize
= *((ULONG
*)BADDR(hunktab
[t
]) - 1);
479 CacheClearE(BADDR(hunktab
[t
]), hunksize
, CACRF_ClearI
| CACRF_ClearD
);
487 hunksize
= *((ULONG
*)BADDR(hunktab
[0]) - 1);
488 if (last
> first
&& hunksize
>= 32 / 4)
490 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
491 ULONG
*h
= (ULONG
*)(BADDR(hunktab
[first
]));
493 if (h
[2] == 0x0000abcd)
496 D(bug("overlay not supported!\n"));
497 ERROR(ERROR_BAD_HUNK
);
499 /* overlay executable */
501 h
[4] = (ULONG
)overlaytable
;
502 h
[5] = (ULONG
)MKBADDR(hunktab
);
503 D(bug("overlay loaded!\n"));
504 return (BPTR
)(-(LONG
)MKBADDR(h
));
510 ilsFreeVec(overlaytable
);
511 ERROR(ERROR_BAD_HUNK
);
523 for (t
= 0 /* first */; t
< numhunks
/* last */; t
++)
524 ilsFreeVec(BADDR(hunktab
[t
]));
528 } /* InternalLoadSeg */
531 static AROS_UFH4(LONG
, ReadFunc
,
532 AROS_UFHA(BPTR
, file
, D1
),
533 AROS_UFHA(APTR
, buffer
, D2
),
534 AROS_UFHA(LONG
, length
, D3
),
535 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
)
540 return FRead(file
, buffer
, 1, length
);
545 static AROS_UFH3(APTR
, AllocFunc
,
546 AROS_UFHA(ULONG
, length
, D0
),
547 AROS_UFHA(ULONG
, flags
, D1
),
548 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
553 return AllocMem(length
, flags
);
558 static AROS_UFH3(void, FreeFunc
,
559 AROS_UFHA(APTR
, buffer
, A1
),
560 AROS_UFHA(ULONG
, length
, D0
),
561 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
566 FreeMem(buffer
, length
);
571 AROS_UFH4(BPTR
, LoadSeg_Overlay
,
572 AROS_UFHA(UBYTE
*, name
, D1
),
573 AROS_UFHA(BPTR
, hunktable
, D2
),
574 AROS_UFHA(BPTR
, fh
, D3
),
575 AROS_UFHA(struct DosLibrary
*, DosBase
, A6
))
579 void (*FunctionArray
[3])();
582 FunctionArray
[0] = (APTR
)ReadFunc
;
583 FunctionArray
[1] = (APTR
)AllocFunc
;
584 FunctionArray
[2] = (APTR
)FreeFunc
;
586 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable
, fh
));
587 if (read_block(fh
, &hunktype
, sizeof(hunktype
), (SIPTR
*)FunctionArray
, DosBase
))
589 hunktype
= AROS_BE2LONG(hunktype
);
590 if (hunktype
!= HUNK_HEADER
)
592 return InternalLoadSeg_AOS(fh
, hunktable
, (SIPTR
*)FunctionArray
, NULL
, DosBase
);