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"
23 #include "include/loadseg.h"
25 #include <proto/dos.h>
27 #define GETHUNKPTR(x) ((UBYTE*)(BADDR(hunktab[x]) + sizeof(BPTR)))
29 /* Seek forward by count ULONGs.
30 * Returns 0 on success, 1 on failure.
32 static int seek_forward(BPTR fd
, ULONG count
, SIPTR
*funcarray
, struct DosLibrary
*DOSBase
)
37 /* For AOS compatibility, we can't use DOS/Seek() here,
38 * as AOS callers to InternalLoadSeg will not pass
39 * in a Seek element of the funcarray, and the read
40 * callback of funcarray may be for reading in-memory
41 * instead of pointing to DOS/Read.
43 * Luckily, reading HUNKs is linear, so we can just
46 while (count
&& !(err
= read_block(fd
, &tmp
, sizeof(tmp
), funcarray
, DOSBase
)))
52 BPTR
InternalLoadSeg_AOS(BPTR fh
,
56 struct DosLibrary
* DOSBase
)
58 #define ERROR(a) { *error=a; goto end; }
61 BPTR
*hunktab
= BADDR(table
);
62 BPTR firsthunk
= BNULL
, prevhunk
= BNULL
;
63 ULONG hunktype
, count
, first
, last
, curhunk
, lasthunk
, numhunks
;
68 UBYTE
*overlaytable
= NULL
;
72 static STRPTR segtypes
[] = { "CODE", "DATA", "BSS", };
76 SIPTR
*error
= &dummy
;
79 struct Process
*me
= (struct Process
*)FindTask(NULL
);
80 ASSERT_VALID_PROCESS(me
);
82 error
=&me
->pr_Result2
;
85 curhunk
= lasthunk
= 0; /* keep GCC quiet */
86 /* start point is HUNK_HEADER + 4 */
89 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
93 count
= AROS_BE2LONG(count
);
95 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
97 D(bug("\tlibname: \"%.*s\"\n", count
, name_buf
));
99 if (read_block(fh
, &numhunks
, sizeof(numhunks
), funcarray
, DOSBase
))
102 numhunks
= AROS_BE2LONG(numhunks
);
104 D(bug("\tHunk count: %ld\n", numhunks
));
107 hunktab
= ilsAllocVec(sizeof(BPTR
) * (numhunks
+ 1 + 1), MEMF_CLEAR
);
109 ERROR(ERROR_NO_FREE_STORE
);
112 if (read_block(fh
, &first
, sizeof(first
), funcarray
, DOSBase
))
115 first
= AROS_BE2LONG(first
);
117 D(bug("\tFirst hunk: %ld\n", first
));
119 if (read_block(fh
, &last
, sizeof(last
), funcarray
, DOSBase
))
122 last
= AROS_BE2LONG(last
);
124 D(bug("\tLast hunk: %ld\n", last
));
126 for (i
= first
; i
<= numhunks
; i
++) {
135 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
138 count
= AROS_BE2LONG(count
);
139 tmp
= count
& (HUNKF_FAST
| HUNKF_CHIP
);
141 D(bug("\tHunk %d size: 0x%06lx bytes in ", i
, count
*4));
142 req
= MEMF_CLEAR
| MEMF_PUBLIC
;
143 if (tmp
== (HUNKF_FAST
| HUNKF_CHIP
)) {
144 if (read_block(fh
, &req
, sizeof(req
), funcarray
, DOSBase
))
146 req
= AROS_BE2LONG(req
);
147 D(bug("FLAGS=%08x", req
));
148 } else if (tmp
== HUNKF_FAST
) {
151 } else if (tmp
== HUNKF_CHIP
) {
158 * We need space for the code, the length of this hunk and
159 * for a pointer to the next hunk.
160 * Note also MEMF_31BIT flag appended to memory requirements.
161 * This is important on 64-bit machines where AmigaDOS hunk
162 * files need to be loaded into low memory (<2GB). This is needed
163 * for correct interpretation of pointers in these files.
164 * Yes, they can't be executed in such environments, but they still can
165 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
167 hunksize
= count
* 4 + sizeof(ULONG
) + sizeof(BPTR
);
168 hunkptr
= ilsAllocVec(hunksize
, req
| MEMF_31BIT
);
170 ERROR(ERROR_NO_FREE_STORE
);
171 hunktab
[i
] = MKBADDR(hunkptr
);
172 D(bug(" @%p\n", hunkptr
));
174 firsthunk
= hunktab
[i
];
176 if this is not the first hunk that is loaded, then connect
177 it to the previous one (pointer to the field where the
178 pointer to the next hunk is located)
181 ((BPTR
*)(BADDR(prevhunk
)))[0] = hunktab
[i
];
182 prevhunk
= hunktab
[i
];
185 while(!read_block(fh
, &hunktype
, sizeof(hunktype
), funcarray
, DOSBase
))
187 hunktype
= AROS_BE2LONG(hunktype
);
188 D(bug("Hunk Type: %d\n", hunktype
& 0xFFFFFF));
190 switch(hunktype
& 0xFFFFFF)
193 /* The SYMBOL_HUNK looks like this:
194 ---------------------
196 | symbol in longs | may
197 |-------------------| be
198 | n longwords = name| repeated
200 |-------------------| number
201 | value (1 long) | of times
202 --------------------|
205 -------------------- */
207 D(bug("HUNK_SYMBOL (skipping)\n"));
208 while(!read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
) && count
)
210 count
= AROS_BE2LONG(count
) ;
212 if (seek_forward(fh
, count
+1, funcarray
, DOSBase
))
219 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
222 count
= AROS_BE2LONG(count
) ;
225 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
227 D(bug("HUNK_UNIT: \"%.*s\"\n", count
, name_buf
));
234 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
237 count
= AROS_BE2LONG(count
);
239 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
240 segtypes
[(hunktype
& 0xFFFFFF)-HUNK_CODE
], curhunk
, count
*4));
242 if ((hunktype
& 0xFFFFFF) != HUNK_BSS
&& count
)
244 if (read_block(fh
, GETHUNKPTR(curhunk
), count
*4, funcarray
, DOSBase
))
254 case HUNK_RELRELOC32
:
255 D(bug("HUNK_RELOC32:\n"));
261 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
266 count
= AROS_BE2LONG(count
);
269 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
272 count
= AROS_BE2LONG(count
);
274 D(bug("\tHunk #%ld:\n", count
));
277 if (read_block(fh
, &offset
, sizeof(offset
), funcarray
, DOSBase
))
280 offset
= AROS_BE2LONG(offset
);
282 //D(bug("\t\t0x%06lx\n", offset));
283 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
285 /* See the above MEMF_31 explanation for why this
286 * works on AROS 64-bit.
288 if ((hunktype
& 0xFFFFFF) == HUNK_RELRELOC32
)
289 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)(GETHUNKPTR(count
) - GETHUNKPTR(curhunk
)));
291 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
298 case HUNK_DREL32
: /* For compatibility with V37 */
299 case HUNK_RELOC32SHORT
:
311 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
316 word
= AROS_BE2LONG(word
);
320 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
323 word
= AROS_BE2WORD(word
);
326 D(bug("\tHunk #%ld @%p: %ld relocations\n", count
, GETHUNKPTR(lasthunk
), i
));
330 /* read a 16bit number (2 bytes) */
331 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
334 /* offset now contains the byte offset in it`s 16 highest bits.
335 These 16 highest bits have to become the 16 lowest bits so
336 we get the word we need. */
337 offset
= AROS_BE2WORD(word
);
339 D(bug("\t\t0x%06lx += 0x%lx\n", offset
, GETHUNKPTR(count
)));
340 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
342 /* See the above MEMF_31 explanation for why this
343 * works on AROS 64-bit.
345 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
351 /* if the amount of words read was odd, then skip the following
353 if (0x1 == (Wordcount
& 0x1)) {
355 read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
);
362 D(bug("HUNK_END\n"));
363 /* DOSBase == NULL: Called from RDB filesystem loader which does not
364 * know filesystem's original size. Exit if last HUNK_END. This can't
365 * be done normally because it would break overlayed executables.
367 if (!DOSBase
&& curhunk
> last
)
373 bug("HUNK_RELOC16 not implemented\n");
374 ERROR(ERROR_BAD_HUNK
);
377 bug("HUNK_RELOC8 not implemented\n");
378 ERROR(ERROR_BAD_HUNK
);
381 bug("HUNK_NAME not implemented\n");
382 ERROR(ERROR_BAD_HUNK
);
385 bug("HUNK_EXT not implemented\n");
386 ERROR(ERROR_BAD_HUNK
);
389 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
392 count
= AROS_BE2LONG(count
);
394 D(bug("HUNK_DEBUG (%x Bytes)\n",count
));
395 if (seek_forward(fh
, count
, funcarray
, DOSBase
))
401 D(bug("HUNK_OVERLAY:\n"));
402 if (table
) /* overlay inside overlay? */
403 ERROR(ERROR_BAD_HUNK
);
404 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
406 count
= AROS_BE2LONG(count
);
407 D(bug("Overlay table size: %d\n", count
));
409 /* See above for MEMF_31BIT explanation */
410 count
= count
* 4 + sizeof(ULONG
) + sizeof(ULONG
);
411 overlaytable
= ilsAllocVec(count
, MEMF_CLEAR
| MEMF_31BIT
);
412 if (overlaytable
== NULL
)
413 ERROR(ERROR_NO_FREE_STORE
);
414 if (read_block(fh
, overlaytable
, count
- sizeof(ULONG
), funcarray
, DOSBase
))
420 D(bug("HUNK_BREAK\n"));
422 ERROR(ERROR_BAD_HUNK
);
426 if (hunktype
& HUNKF_ADVISORY
) {
427 D(bug("Unknown hunk 0x%06lx with advisory flag skipped\n", hunktype
& 0xFFFFFF));
428 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
430 count
= AROS_BE2LONG(count
);
431 if (seek_forward(fh
, count
* 4, funcarray
, DOSBase
))
434 bug("Hunk type 0x%06lx not implemented\n", hunktype
& 0xFFFFFF);
435 ERROR(ERROR_BAD_HUNK
);
446 * On non-m68k systems, hunk files are not executable.
447 * And even if AROS ever gets m68k emulator, they are still data files.
448 * So we flush caches only on m68k.
450 if (SysBase
->LibNode
.lib_Version
>= 36)
453 for (t
= first
; t
< numhunks
&& t
<= last
; t
++)
455 hunksize
= *((ULONG
*)BADDR(hunktab
[t
]) - 1);
457 CacheClearE(BADDR(hunktab
[t
]), hunksize
, CACRF_ClearI
| CACRF_ClearD
);
465 hunksize
= *((ULONG
*)BADDR(hunktab
[0]) - 1);
466 if (last
> first
&& hunksize
>= 32 / 4)
468 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
469 ULONG
*h
= (ULONG
*)(BADDR(hunktab
[first
]));
471 if (h
[2] == 0x0000abcd)
474 D(bug("overlay not supported!\n"));
475 ERROR(ERROR_BAD_HUNK
);
477 /* overlay executable */
479 h
[4] = (ULONG
)overlaytable
;
480 h
[5] = (ULONG
)MKBADDR(hunktab
);
481 D(bug("overlay loaded!\n"));
482 return (BPTR
)(-(LONG
)MKBADDR(h
));
488 ilsFreeVec(overlaytable
);
489 ERROR(ERROR_BAD_HUNK
);
494 register_hunk(fh
, firsthunk
, NULL
, DOSBase
);
503 for (t
= 0 /* first */; t
< numhunks
/* last */; t
++)
504 ilsFreeVec(BADDR(hunktab
[t
]));
508 } /* InternalLoadSeg */
511 static AROS_UFH4(LONG
, ReadFunc
,
512 AROS_UFHA(BPTR
, file
, D1
),
513 AROS_UFHA(APTR
, buffer
, D2
),
514 AROS_UFHA(LONG
, length
, D3
),
515 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
)
520 return FRead(file
, buffer
, 1, length
);
525 static AROS_UFH3(APTR
, AllocFunc
,
526 AROS_UFHA(ULONG
, length
, D0
),
527 AROS_UFHA(ULONG
, flags
, D1
),
528 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
533 return AllocMem(length
, flags
);
538 static AROS_UFH3(void, FreeFunc
,
539 AROS_UFHA(APTR
, buffer
, A1
),
540 AROS_UFHA(ULONG
, length
, D0
),
541 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
546 FreeMem(buffer
, length
);
551 AROS_UFH4(BPTR
, LoadSeg_Overlay
,
552 AROS_UFHA(UBYTE
*, name
, D1
),
553 AROS_UFHA(BPTR
, hunktable
, D2
),
554 AROS_UFHA(BPTR
, fh
, D3
),
555 AROS_UFHA(struct DosLibrary
*, DosBase
, A6
))
559 void (*FunctionArray
[3])();
562 FunctionArray
[0] = (APTR
)ReadFunc
;
563 FunctionArray
[1] = (APTR
)AllocFunc
;
564 FunctionArray
[2] = (APTR
)FreeFunc
;
566 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable
, fh
));
567 if (read_block(fh
, &hunktype
, sizeof(hunktype
), (SIPTR
*)FunctionArray
, DosBase
))
569 hunktype
= AROS_BE2LONG(hunktype
);
570 if (hunktype
!= HUNK_HEADER
)
572 return InternalLoadSeg_AOS(fh
, hunktable
, (SIPTR
*)FunctionArray
, NULL
, DosBase
);