emul-handler: fh_Arg1 should be the only element of struct FileHandle touched during...
[AROS.git] / rom / dos / internalloadseg_aos.c
blobcdee666de4346a9b659948a88bc6175dce077b30
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
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)
34 int err = 0;
35 ULONG tmp;
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
44 * read ahead.
46 while (count && !(err = read_block(fd, &tmp, sizeof(tmp), funcarray, DOSBase)))
47 count--;
49 return err;
52 BPTR InternalLoadSeg_AOS(BPTR fh,
53 BPTR table,
54 SIPTR * funcarray,
55 LONG * stacksize,
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;
64 LONG t;
65 UBYTE name_buf[255];
66 register int i;
67 BPTR last_p = 0;
68 UBYTE *overlaytable = NULL;
69 ULONG tmp, req;
70 SIPTR dummy;
71 #if DEBUG
72 static STRPTR segtypes[] = { "CODE", "DATA", "BSS", };
73 #endif
76 SIPTR *error = &dummy;
78 if (DOSBase) {
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 */
87 while (1)
89 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
90 goto end;
91 if (count == 0L)
92 break;
93 count = AROS_BE2LONG(count);
94 count *= 4;
95 if (read_block(fh, name_buf, count, funcarray, DOSBase))
96 goto end;
97 D(bug("\tlibname: \"%.*s\"\n", count, name_buf));
99 if (read_block(fh, &numhunks, sizeof(numhunks), funcarray, DOSBase))
100 goto end;
102 numhunks = AROS_BE2LONG(numhunks);
104 D(bug("\tHunk count: %ld\n", numhunks));
106 if (!hunktab) {
107 hunktab = ilsAllocVec(sizeof(BPTR) * (numhunks + 1 + 1), MEMF_CLEAR);
108 if (hunktab == NULL)
109 ERROR(ERROR_NO_FREE_STORE);
112 if (read_block(fh, &first, sizeof(first), funcarray, DOSBase))
113 goto end;
115 first = AROS_BE2LONG(first);
117 D(bug("\tFirst hunk: %ld\n", first));
118 curhunk = first;
119 if (read_block(fh, &last, sizeof(last), funcarray, DOSBase))
120 goto end;
122 last = AROS_BE2LONG(last);
124 D(bug("\tLast hunk: %ld\n", last));
126 for (i = first; i <= numhunks; i++) {
127 UBYTE *hunkptr;
128 ULONG hunksize;
130 if (i > last) {
131 hunktab[i] = BNULL;
132 continue;
135 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
136 goto end;
138 count = AROS_BE2LONG(count);
139 tmp = count & (HUNKF_FAST | HUNKF_CHIP);
140 count &= 0xFFFFFF;
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))
145 goto end;
146 req = AROS_BE2LONG(req);
147 D(bug("FLAGS=%08x", req));
148 } else if (tmp == HUNKF_FAST) {
149 D(bug("FAST"));
150 req |= MEMF_FAST;
151 } else if (tmp == HUNKF_CHIP) {
152 D(bug("CHIP"));
153 req |= MEMF_CHIP;
155 D(bug(" memory"));
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);
169 if (!hunkptr)
170 ERROR(ERROR_NO_FREE_STORE);
171 hunktab[i] = MKBADDR(hunkptr);
172 D(bug(" @%p\n", hunkptr));
173 if (!firsthunk)
174 firsthunk = hunktab[i];
175 /* Link hunks
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)
180 if (prevhunk)
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)
192 case HUNK_SYMBOL:
193 /* The SYMBOL_HUNK looks like this:
194 ---------------------
195 | n = size of | This
196 | symbol in longs | may
197 |-------------------| be
198 | n longwords = name| repeated
199 | of symbol | any
200 |-------------------| number
201 | value (1 long) | of times
202 --------------------|
203 | 0 = end of HUNK_ |
204 | SYMBOL |
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))
213 goto end;
215 break;
217 case HUNK_UNIT:
219 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
220 goto end;
222 count = AROS_BE2LONG(count) ;
224 count *= 4;
225 if (read_block(fh, name_buf, count, funcarray, DOSBase))
226 goto end;
227 D(bug("HUNK_UNIT: \"%.*s\"\n", count, name_buf));
228 break;
230 case HUNK_CODE:
231 case HUNK_DATA:
232 case HUNK_BSS:
234 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
235 goto end;
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))
245 goto end;
249 lasthunk = curhunk;
250 ++curhunk;
251 break;
253 case HUNK_RELOC32:
254 case HUNK_RELRELOC32:
255 D(bug("HUNK_RELOC32:\n"));
256 while (1)
258 ULONG *addr;
259 ULONG offset;
261 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
262 goto end;
263 if (count == 0L)
264 break;
266 count = AROS_BE2LONG(count);
268 i = count;
269 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
270 goto end;
272 count = AROS_BE2LONG(count);
274 D(bug("\tHunk #%ld:\n", count));
275 while (i > 0)
277 if (read_block(fh, &offset, sizeof(offset), funcarray, DOSBase))
278 goto end;
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)));
290 else
291 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
293 --i;
296 break;
298 case HUNK_DREL32: /* For compatibility with V37 */
299 case HUNK_RELOC32SHORT:
301 ULONG Wordcount = 0;
302 ULONG offset;
304 while (1)
306 ULONG *addr;
307 UWORD word;
309 Wordcount++;
311 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
312 goto end;
313 if (word == 0L)
314 break;
316 word = AROS_BE2LONG(word);
318 i = word;
319 Wordcount++;
320 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
321 goto end;
323 word = AROS_BE2WORD(word);
325 count = word;
326 D(bug("\tHunk #%ld @%p: %ld relocations\n", count, GETHUNKPTR(lasthunk), i));
327 while (i > 0)
329 Wordcount++;
330 /* read a 16bit number (2 bytes) */
331 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
332 goto end;
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));
347 --i;
348 } /* while (i > 0)*/
349 } /* while (1) */
351 /* if the amount of words read was odd, then skip the following
352 16-bit word */
353 if (0x1 == (Wordcount & 0x1)) {
354 UWORD word;
355 read_block(fh, &word, sizeof(word), funcarray, DOSBase);
358 break;
360 case HUNK_END:
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)
368 goto done;
370 break;
372 case HUNK_RELOC16:
373 bug("HUNK_RELOC16 not implemented\n");
374 ERROR(ERROR_BAD_HUNK);
376 case HUNK_RELOC8:
377 bug("HUNK_RELOC8 not implemented\n");
378 ERROR(ERROR_BAD_HUNK);
380 case HUNK_NAME:
381 bug("HUNK_NAME not implemented\n");
382 ERROR(ERROR_BAD_HUNK);
384 case HUNK_EXT:
385 bug("HUNK_EXT not implemented\n");
386 ERROR(ERROR_BAD_HUNK);
388 case HUNK_DEBUG:
389 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
390 goto end;
392 count = AROS_BE2LONG(count);
394 D(bug("HUNK_DEBUG (%x Bytes)\n",count));
395 if (seek_forward(fh, count, funcarray, DOSBase))
396 goto end;
397 break;
399 case HUNK_OVERLAY:
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))
405 goto end;
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))
415 goto end;
416 goto done;
419 case HUNK_BREAK:
420 D(bug("HUNK_BREAK\n"));
421 if (!table)
422 ERROR(ERROR_BAD_HUNK);
423 goto done;
425 default:
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))
429 goto end;
430 count = AROS_BE2LONG(count);
431 if (seek_forward(fh, count * 4, funcarray, DOSBase))
432 goto end;
433 } else {
434 bug("Hunk type 0x%06lx not implemented\n", hunktype & 0xFFFFFF);
435 ERROR(ERROR_BAD_HUNK);
437 } /* switch */
438 } /* while */
439 done:
440 if (hunktab)
442 ULONG hunksize;
444 #ifdef __mc68000
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)
452 /* Clear caches */
453 for (t = first; t < numhunks && t <= last; t++)
455 hunksize = *((ULONG*)BADDR(hunktab[t]) - 1);
456 if (hunksize)
457 CacheClearE(BADDR(hunktab[t]), hunksize, CACRF_ClearI | CACRF_ClearD);
460 #endif
462 if (table)
463 return firsthunk;
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)
473 #if __WORDSIZE != 32
474 D(bug("overlay not supported!\n"));
475 ERROR(ERROR_BAD_HUNK);
476 #else
477 /* overlay executable */
478 h[3] = (ULONG)fh;
479 h[4] = (ULONG)overlaytable;
480 h[5] = (ULONG)MKBADDR(hunktab);
481 D(bug("overlay loaded!\n"));
482 return (BPTR)(-(LONG)MKBADDR(h));
483 #endif
487 if (overlaytable) {
488 ilsFreeVec(overlaytable);
489 ERROR(ERROR_BAD_HUNK);
492 last_p = firsthunk;
494 register_hunk(fh, firsthunk, NULL, DOSBase);
496 ilsFreeVec(hunktab);
497 hunktab = NULL;
500 end:
501 if (hunktab != NULL)
503 for (t = 0 /* first */; t < numhunks /* last */; t++)
504 ilsFreeVec(BADDR(hunktab[t]));
505 ilsFreeVec(hunktab);
507 return last_p;
508 } /* InternalLoadSeg */
510 #ifdef __mc68000
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)
518 AROS_USERFUNC_INIT
520 return FRead(file, buffer, 1, length);
522 AROS_USERFUNC_EXIT
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)
531 AROS_USERFUNC_INIT
533 return AllocMem(length, flags);
535 AROS_USERFUNC_EXIT
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)
544 AROS_USERFUNC_INIT
546 FreeMem(buffer, length);
548 AROS_USERFUNC_EXIT
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))
557 AROS_USERFUNC_INIT
559 void (*FunctionArray[3])();
560 ULONG hunktype;
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))
568 return BNULL;
569 hunktype = AROS_BE2LONG(hunktype);
570 if (hunktype != HUNK_HEADER)
571 return BNULL;
572 return InternalLoadSeg_AOS(fh, hunktable, (SIPTR*)FunctionArray, NULL, DosBase);
574 AROS_USERFUNC_EXIT
577 #endif