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
, lasthunk
, numhunks
;
67 UBYTE
*overlaytable
= NULL
;
71 static STRPTR segtypes
[] = { "CODE", "DATA", "BSS", };
75 SIPTR
*error
= &dummy
;
78 struct Process
*me
= (struct Process
*)FindTask(NULL
);
79 ASSERT_VALID_PROCESS(me
);
81 error
=&me
->pr_Result2
;
84 curhunk
= lasthunk
= 0; /* keep GCC quiet */
85 /* start point is HUNK_HEADER + 4 */
88 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
92 count
= AROS_BE2LONG(count
);
94 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
96 D(bug("\tlibname: \"%.*s\"\n", count
, name_buf
));
98 if (read_block(fh
, &numhunks
, sizeof(numhunks
), funcarray
, DOSBase
))
101 numhunks
= AROS_BE2LONG(numhunks
);
103 D(bug("\tHunk count: %ld\n", numhunks
));
106 hunktab
= ilsAllocVec(sizeof(BPTR
) * (numhunks
+ 1 + 1), MEMF_CLEAR
);
108 ERROR(ERROR_NO_FREE_STORE
);
111 if (read_block(fh
, &first
, sizeof(first
), funcarray
, DOSBase
))
114 first
= AROS_BE2LONG(first
);
116 D(bug("\tFirst hunk: %ld\n", first
));
118 if (read_block(fh
, &last
, sizeof(last
), funcarray
, DOSBase
))
121 last
= AROS_BE2LONG(last
);
123 D(bug("\tLast hunk: %ld\n", last
));
125 for (i
= first
; i
<= numhunks
; i
++) {
134 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
137 count
= AROS_BE2LONG(count
);
138 tmp
= count
& (HUNKF_FAST
| HUNKF_CHIP
);
140 D(bug("\tHunk %d size: 0x%06lx bytes in ", i
, count
*4));
141 req
= MEMF_CLEAR
| MEMF_PUBLIC
;
142 if (tmp
== (HUNKF_FAST
| HUNKF_CHIP
)) {
143 if (read_block(fh
, &req
, sizeof(req
), funcarray
, DOSBase
))
145 req
= AROS_BE2LONG(req
);
146 D(bug("FLAGS=%08x", req
));
147 } else if (tmp
== HUNKF_FAST
) {
150 } else if (tmp
== HUNKF_CHIP
) {
157 * We need space for the code, the length of this hunk and
158 * for a pointer to the next hunk.
159 * Note also MEMF_31BIT flag appended to memory requirements.
160 * This is important on 64-bit machines where AmigaDOS hunk
161 * files need to be loaded into low memory (<2GB). This is needed
162 * for correct interpretation of pointers in these files.
163 * Yes, they can't be executed in such environments, but they still can
164 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
166 hunksize
= count
* 4 + sizeof(ULONG
) + sizeof(BPTR
);
167 hunkptr
= ilsAllocVec(hunksize
, req
| MEMF_31BIT
);
169 ERROR(ERROR_NO_FREE_STORE
);
170 hunktab
[i
] = MKBADDR(hunkptr
);
171 D(bug(" @%p\n", hunkptr
));
173 firsthunk
= hunktab
[i
];
175 if this is not the first hunk that is loaded, then connect
176 it to the previous one (pointer to the field where the
177 pointer to the next hunk is located)
180 ((BPTR
*)(BADDR(prevhunk
)))[0] = hunktab
[i
];
181 prevhunk
= hunktab
[i
];
184 while(!read_block(fh
, &hunktype
, sizeof(hunktype
), funcarray
, DOSBase
))
186 hunktype
= AROS_BE2LONG(hunktype
);
187 D(bug("Hunk Type: %d\n", hunktype
& 0xFFFFFF));
189 switch(hunktype
& 0xFFFFFF)
192 /* The SYMBOL_HUNK looks like this:
193 ---------------------
195 | symbol in longs | may
196 |-------------------| be
197 | n longwords = name| repeated
199 |-------------------| number
200 | value (1 long) | of times
201 --------------------|
204 -------------------- */
206 D(bug("HUNK_SYMBOL (skipping)\n"));
207 while(!read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
) && count
)
209 count
= AROS_BE2LONG(count
) ;
211 if (seek_forward(fh
, count
+1, funcarray
, DOSBase
))
218 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
221 count
= AROS_BE2LONG(count
) ;
224 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
226 D(bug("HUNK_UNIT: \"%.*s\"\n", count
, name_buf
));
233 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
236 count
= AROS_BE2LONG(count
);
238 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
239 segtypes
[(hunktype
& 0xFFFFFF)-HUNK_CODE
], curhunk
, count
*4));
241 if ((hunktype
& 0xFFFFFF) != HUNK_BSS
&& count
)
243 if (read_block(fh
, GETHUNKPTR(curhunk
), count
*4, funcarray
, DOSBase
))
253 case HUNK_RELRELOC32
:
254 D(bug("HUNK_RELOC32:\n"));
260 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
265 count
= AROS_BE2LONG(count
);
268 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
271 count
= AROS_BE2LONG(count
);
273 D(bug("\tHunk #%ld:\n", count
));
276 if (read_block(fh
, &offset
, sizeof(offset
), funcarray
, DOSBase
))
279 offset
= AROS_BE2LONG(offset
);
281 //D(bug("\t\t0x%06lx\n", offset));
282 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
284 /* See the above MEMF_31 explanation for why this
285 * works on AROS 64-bit.
287 if ((hunktype
& 0xFFFFFF) == HUNK_RELRELOC32
)
288 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)(GETHUNKPTR(count
) - GETHUNKPTR(curhunk
)));
290 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
297 case HUNK_DREL32
: /* For compatibility with V37 */
298 case HUNK_RELOC32SHORT
:
310 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
315 word
= AROS_BE2LONG(word
);
319 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
322 word
= AROS_BE2WORD(word
);
325 D(bug("\tHunk #%ld @%p: %ld relocations\n", count
, GETHUNKPTR(lasthunk
), i
));
329 /* read a 16bit number (2 bytes) */
330 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
333 /* offset now contains the byte offset in it`s 16 highest bits.
334 These 16 highest bits have to become the 16 lowest bits so
335 we get the word we need. */
336 offset
= AROS_BE2WORD(word
);
338 D(bug("\t\t0x%06lx += 0x%lx\n", offset
, GETHUNKPTR(count
)));
339 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
341 /* See the above MEMF_31 explanation for why this
342 * works on AROS 64-bit.
344 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
350 /* if the amount of words read was odd, then skip the following
352 if (0x1 == (Wordcount
& 0x1)) {
354 read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
);
361 D(bug("HUNK_END\n"));
362 /* DOSBase == NULL: Called from RDB filesystem loader which does not
363 * know filesystem's original size. Exit if last HUNK_END. This can't
364 * be done normally because it would break overlayed executables.
366 if (!DOSBase
&& curhunk
> last
)
372 bug("HUNK_RELOC16 not implemented\n");
373 ERROR(ERROR_BAD_HUNK
);
376 bug("HUNK_RELOC8 not implemented\n");
377 ERROR(ERROR_BAD_HUNK
);
380 bug("HUNK_NAME not implemented\n");
381 ERROR(ERROR_BAD_HUNK
);
384 bug("HUNK_EXT not implemented\n");
385 ERROR(ERROR_BAD_HUNK
);
388 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
391 count
= AROS_BE2LONG(count
);
393 D(bug("HUNK_DEBUG (%x Bytes)\n",count
));
394 if (seek_forward(fh
, count
, funcarray
, DOSBase
))
400 D(bug("HUNK_OVERLAY:\n"));
401 if (table
) /* overlay inside overlay? */
402 ERROR(ERROR_BAD_HUNK
);
403 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
405 count
= AROS_BE2LONG(count
);
406 D(bug("Overlay table size: %d\n", count
));
408 /* See above for MEMF_31BIT explanation */
409 count
= count
* 4 + sizeof(ULONG
) + sizeof(ULONG
);
410 overlaytable
= ilsAllocVec(count
, MEMF_CLEAR
| MEMF_31BIT
);
411 if (overlaytable
== NULL
)
412 ERROR(ERROR_NO_FREE_STORE
);
413 if (read_block(fh
, overlaytable
, count
- sizeof(ULONG
), funcarray
, DOSBase
))
419 D(bug("HUNK_BREAK\n"));
421 ERROR(ERROR_BAD_HUNK
);
425 if (hunktype
& HUNKF_ADVISORY
) {
426 D(bug("Unknown hunk 0x%06lx with advisory flag skipped\n", hunktype
& 0xFFFFFF));
427 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
429 count
= AROS_BE2LONG(count
);
430 if (seek_forward(fh
, count
* 4, funcarray
, DOSBase
))
433 bug("Hunk type 0x%06lx not implemented\n", hunktype
& 0xFFFFFF);
434 ERROR(ERROR_BAD_HUNK
);
445 * On non-m68k systems, hunk files are not executable.
446 * And even if AROS ever gets m68k emulator, they are still data files.
447 * So we flush caches only on m68k.
449 if (SysBase
->LibNode
.lib_Version
>= 36)
452 for (t
= first
; t
< numhunks
&& t
<= last
; t
++)
454 hunksize
= *((ULONG
*)BADDR(hunktab
[t
]) - 1);
456 CacheClearE(BADDR(hunktab
[t
]), hunksize
, CACRF_ClearI
| CACRF_ClearD
);
464 hunksize
= *((ULONG
*)BADDR(hunktab
[0]) - 1);
465 if (last
> first
&& hunksize
>= 32 / 4)
467 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
468 ULONG
*h
= (ULONG
*)(BADDR(hunktab
[first
]));
470 if (h
[2] == 0x0000abcd)
473 D(bug("overlay not supported!\n"));
474 ERROR(ERROR_BAD_HUNK
);
476 /* overlay executable */
478 h
[4] = (ULONG
)overlaytable
;
479 h
[5] = (ULONG
)MKBADDR(hunktab
);
480 D(bug("overlay loaded!\n"));
481 return (BPTR
)(-(LONG
)MKBADDR(h
));
487 ilsFreeVec(overlaytable
);
488 ERROR(ERROR_BAD_HUNK
);
500 for (t
= 0 /* first */; t
< numhunks
/* last */; t
++)
501 ilsFreeVec(BADDR(hunktab
[t
]));
505 } /* InternalLoadSeg */
508 static AROS_UFH4(LONG
, ReadFunc
,
509 AROS_UFHA(BPTR
, file
, D1
),
510 AROS_UFHA(APTR
, buffer
, D2
),
511 AROS_UFHA(LONG
, length
, D3
),
512 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
)
517 return FRead(file
, buffer
, 1, length
);
522 static AROS_UFH3(APTR
, AllocFunc
,
523 AROS_UFHA(ULONG
, length
, D0
),
524 AROS_UFHA(ULONG
, flags
, D1
),
525 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
530 return AllocMem(length
, flags
);
535 static AROS_UFH3(void, FreeFunc
,
536 AROS_UFHA(APTR
, buffer
, A1
),
537 AROS_UFHA(ULONG
, length
, D0
),
538 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
543 FreeMem(buffer
, length
);
548 AROS_UFH4(BPTR
, LoadSeg_Overlay
,
549 AROS_UFHA(UBYTE
*, name
, D1
),
550 AROS_UFHA(BPTR
, hunktable
, D2
),
551 AROS_UFHA(BPTR
, fh
, D3
),
552 AROS_UFHA(struct DosLibrary
*, DosBase
, A6
))
556 void (*FunctionArray
[3])();
559 FunctionArray
[0] = (APTR
)ReadFunc
;
560 FunctionArray
[1] = (APTR
)AllocFunc
;
561 FunctionArray
[2] = (APTR
)FreeFunc
;
563 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable
, fh
));
564 if (read_block(fh
, &hunktype
, sizeof(hunktype
), (SIPTR
*)FunctionArray
, DosBase
))
566 hunktype
= AROS_BE2LONG(hunktype
);
567 if (hunktype
!= HUNK_HEADER
)
569 return InternalLoadSeg_AOS(fh
, hunktable
, (SIPTR
*)FunctionArray
, NULL
, DosBase
);