Detabbed
[AROS.git] / rom / dos / internalloadseg_aos.c
blob42d81781f50edee544f951053aa556a47b1bb83a
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"
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)
33 int err = 0;
34 ULONG tmp;
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
43 * read ahead.
45 while (count && !(err = read_block(fd, &tmp, sizeof(tmp), funcarray, DOSBase)))
46 count--;
48 return err;
51 BPTR InternalLoadSeg_AOS(BPTR fh,
52 BPTR table,
53 SIPTR * funcarray,
54 LONG * stacksize,
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;
63 LONG t;
64 UBYTE name_buf[255];
65 register int i;
66 BPTR last_p = 0;
67 UBYTE *overlaytable = NULL;
68 ULONG tmp, req;
69 SIPTR dummy;
70 #if DEBUG
71 static STRPTR segtypes[] = { "CODE", "DATA", "BSS", };
72 #endif
75 SIPTR *error = &dummy;
77 if (DOSBase) {
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 */
86 while (1)
88 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
89 goto end;
90 if (count == 0L)
91 break;
92 count = AROS_BE2LONG(count);
93 count *= 4;
94 if (read_block(fh, name_buf, count, funcarray, DOSBase))
95 goto end;
96 D(bug("\tlibname: \"%.*s\"\n", count, name_buf));
98 if (read_block(fh, &numhunks, sizeof(numhunks), funcarray, DOSBase))
99 goto end;
101 numhunks = AROS_BE2LONG(numhunks);
103 D(bug("\tHunk count: %ld\n", numhunks));
105 if (!hunktab) {
106 hunktab = ilsAllocVec(sizeof(BPTR) * (numhunks + 1 + 1), MEMF_CLEAR);
107 if (hunktab == NULL)
108 ERROR(ERROR_NO_FREE_STORE);
111 if (read_block(fh, &first, sizeof(first), funcarray, DOSBase))
112 goto end;
114 first = AROS_BE2LONG(first);
116 D(bug("\tFirst hunk: %ld\n", first));
117 curhunk = first;
118 if (read_block(fh, &last, sizeof(last), funcarray, DOSBase))
119 goto end;
121 last = AROS_BE2LONG(last);
123 D(bug("\tLast hunk: %ld\n", last));
125 for (i = first; i <= numhunks; i++) {
126 UBYTE *hunkptr;
127 ULONG hunksize;
129 if (i > last) {
130 hunktab[i] = BNULL;
131 continue;
134 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
135 goto end;
137 count = AROS_BE2LONG(count);
138 tmp = count & (HUNKF_FAST | HUNKF_CHIP);
139 count &= 0xFFFFFF;
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))
144 goto end;
145 req = AROS_BE2LONG(req);
146 D(bug("FLAGS=%08x", req));
147 } else if (tmp == HUNKF_FAST) {
148 D(bug("FAST"));
149 req |= MEMF_FAST;
150 } else if (tmp == HUNKF_CHIP) {
151 D(bug("CHIP"));
152 req |= MEMF_CHIP;
154 D(bug(" memory"));
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);
168 if (!hunkptr)
169 ERROR(ERROR_NO_FREE_STORE);
170 hunktab[i] = MKBADDR(hunkptr);
171 D(bug(" @%p\n", hunkptr));
172 if (!firsthunk)
173 firsthunk = hunktab[i];
174 /* Link hunks
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)
179 if (prevhunk)
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)
191 case HUNK_SYMBOL:
192 /* The SYMBOL_HUNK looks like this:
193 ---------------------
194 | n = size of | This
195 | symbol in longs | may
196 |-------------------| be
197 | n longwords = name| repeated
198 | of symbol | any
199 |-------------------| number
200 | value (1 long) | of times
201 --------------------|
202 | 0 = end of HUNK_ |
203 | SYMBOL |
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))
212 goto end;
214 break;
216 case HUNK_UNIT:
218 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
219 goto end;
221 count = AROS_BE2LONG(count) ;
223 count *= 4;
224 if (read_block(fh, name_buf, count, funcarray, DOSBase))
225 goto end;
226 D(bug("HUNK_UNIT: \"%.*s\"\n", count, name_buf));
227 break;
229 case HUNK_CODE:
230 case HUNK_DATA:
231 case HUNK_BSS:
233 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
234 goto end;
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))
244 goto end;
248 lasthunk = curhunk;
249 ++curhunk;
250 break;
252 case HUNK_RELOC32:
253 case HUNK_RELRELOC32:
254 D(bug("HUNK_RELOC32:\n"));
255 while (1)
257 ULONG *addr;
258 ULONG offset;
260 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
261 goto end;
262 if (count == 0L)
263 break;
265 count = AROS_BE2LONG(count);
267 i = count;
268 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
269 goto end;
271 count = AROS_BE2LONG(count);
273 D(bug("\tHunk #%ld:\n", count));
274 while (i > 0)
276 if (read_block(fh, &offset, sizeof(offset), funcarray, DOSBase))
277 goto end;
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)));
289 else
290 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
292 --i;
295 break;
297 case HUNK_DREL32: /* For compatibility with V37 */
298 case HUNK_RELOC32SHORT:
300 ULONG Wordcount = 0;
301 ULONG offset;
303 while (1)
305 ULONG *addr;
306 UWORD word;
308 Wordcount++;
310 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
311 goto end;
312 if (word == 0L)
313 break;
315 word = AROS_BE2LONG(word);
317 i = word;
318 Wordcount++;
319 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
320 goto end;
322 word = AROS_BE2WORD(word);
324 count = word;
325 D(bug("\tHunk #%ld @%p: %ld relocations\n", count, GETHUNKPTR(lasthunk), i));
326 while (i > 0)
328 Wordcount++;
329 /* read a 16bit number (2 bytes) */
330 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
331 goto end;
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));
346 --i;
347 } /* while (i > 0)*/
348 } /* while (1) */
350 /* if the amount of words read was odd, then skip the following
351 16-bit word */
352 if (0x1 == (Wordcount & 0x1)) {
353 UWORD word;
354 read_block(fh, &word, sizeof(word), funcarray, DOSBase);
357 break;
359 case HUNK_END:
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)
367 goto done;
369 break;
371 case HUNK_RELOC16:
372 bug("HUNK_RELOC16 not implemented\n");
373 ERROR(ERROR_BAD_HUNK);
375 case HUNK_RELOC8:
376 bug("HUNK_RELOC8 not implemented\n");
377 ERROR(ERROR_BAD_HUNK);
379 case HUNK_NAME:
380 bug("HUNK_NAME not implemented\n");
381 ERROR(ERROR_BAD_HUNK);
383 case HUNK_EXT:
384 bug("HUNK_EXT not implemented\n");
385 ERROR(ERROR_BAD_HUNK);
387 case HUNK_DEBUG:
388 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
389 goto end;
391 count = AROS_BE2LONG(count);
393 D(bug("HUNK_DEBUG (%x Bytes)\n",count));
394 if (seek_forward(fh, count, funcarray, DOSBase))
395 goto end;
396 break;
398 case HUNK_OVERLAY:
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))
404 goto end;
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))
414 goto end;
415 goto done;
418 case HUNK_BREAK:
419 D(bug("HUNK_BREAK\n"));
420 if (!table)
421 ERROR(ERROR_BAD_HUNK);
422 goto done;
424 default:
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))
428 goto end;
429 count = AROS_BE2LONG(count);
430 if (seek_forward(fh, count * 4, funcarray, DOSBase))
431 goto end;
432 } else {
433 bug("Hunk type 0x%06lx not implemented\n", hunktype & 0xFFFFFF);
434 ERROR(ERROR_BAD_HUNK);
436 } /* switch */
437 } /* while */
438 done:
439 if (hunktab)
441 ULONG hunksize;
443 #ifdef __mc68000
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)
451 /* Clear caches */
452 for (t = first; t < numhunks && t <= last; t++)
454 hunksize = *((ULONG*)BADDR(hunktab[t]) - 1);
455 if (hunksize)
456 CacheClearE(BADDR(hunktab[t]), hunksize, CACRF_ClearI | CACRF_ClearD);
459 #endif
461 if (table)
462 return firsthunk;
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)
472 #if __WORDSIZE != 32
473 D(bug("overlay not supported!\n"));
474 ERROR(ERROR_BAD_HUNK);
475 #else
476 /* overlay executable */
477 h[3] = (ULONG)fh;
478 h[4] = (ULONG)overlaytable;
479 h[5] = (ULONG)MKBADDR(hunktab);
480 D(bug("overlay loaded!\n"));
481 return (BPTR)(-(LONG)MKBADDR(h));
482 #endif
486 if (overlaytable) {
487 ilsFreeVec(overlaytable);
488 ERROR(ERROR_BAD_HUNK);
491 last_p = firsthunk;
493 ilsFreeVec(hunktab);
494 hunktab = NULL;
497 end:
498 if (hunktab != NULL)
500 for (t = 0 /* first */; t < numhunks /* last */; t++)
501 ilsFreeVec(BADDR(hunktab[t]));
502 ilsFreeVec(hunktab);
504 return last_p;
505 } /* InternalLoadSeg */
507 #ifdef __mc68000
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)
515 AROS_USERFUNC_INIT
517 return FRead(file, buffer, 1, length);
519 AROS_USERFUNC_EXIT
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)
528 AROS_USERFUNC_INIT
530 return AllocMem(length, flags);
532 AROS_USERFUNC_EXIT
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)
541 AROS_USERFUNC_INIT
543 FreeMem(buffer, length);
545 AROS_USERFUNC_EXIT
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))
554 AROS_USERFUNC_INIT
556 void (*FunctionArray[3])();
557 ULONG hunktype;
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))
565 return BNULL;
566 hunktype = AROS_BE2LONG(hunktype);
567 if (hunktype != HUNK_HEADER)
568 return BNULL;
569 return InternalLoadSeg_AOS(fh, hunktable, (SIPTR*)FunctionArray, NULL, DosBase);
571 AROS_USERFUNC_EXIT
574 #endif