delint
[AROS.git] / rom / dos / internalloadseg_aos.c
blob20a96c0b15948f42ee436e290ae1ef8326533790
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 static BOOL allowed_hunk(BPTR seglist);
54 BPTR InternalLoadSeg_AOS(BPTR fh,
55 BPTR table,
56 SIPTR * funcarray,
57 LONG * stacksize,
58 struct DosLibrary * DOSBase)
60 #define ERROR(a) { *error=a; goto end; }
63 BPTR *hunktab = BADDR(table);
64 BPTR firsthunk = BNULL, prevhunk = BNULL;
65 ULONG hunktype, count, first, last, curhunk, lasthunk, numhunks;
66 LONG t;
67 UBYTE name_buf[255];
68 register int i;
69 BPTR last_p = 0;
70 UBYTE *overlaytable = NULL;
71 ULONG tmp, req;
72 SIPTR dummy;
73 #if DEBUG
74 static STRPTR segtypes[] = { "CODE", "DATA", "BSS", };
75 #endif
77 SIPTR *error = &dummy;
79 if (DOSBase) {
80 struct Process *me = (struct Process *)FindTask(NULL);
81 ASSERT_VALID_PROCESS(me);
83 error =&me->pr_Result2;
86 curhunk = lasthunk = 0; /* keep GCC quiet */
87 /* start point is HUNK_HEADER + 4 */
88 while (1)
90 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
91 goto end;
92 if (count == 0L)
93 break;
94 count = AROS_BE2LONG(count);
95 count *= 4;
96 if (read_block(fh, name_buf, count, funcarray, DOSBase))
97 goto end;
98 D(bug("\tlibname: \"%.*s\"\n", count, name_buf));
100 if (read_block(fh, &numhunks, sizeof(numhunks), funcarray, DOSBase))
101 goto end;
103 numhunks = AROS_BE2LONG(numhunks);
105 D(bug("\tHunk count: %ld\n", numhunks));
107 if (!hunktab) {
108 hunktab = ilsAllocVec(sizeof(BPTR) * (numhunks + 1 + 1), MEMF_CLEAR);
109 if (hunktab == NULL)
110 ERROR(ERROR_NO_FREE_STORE);
113 if (read_block(fh, &first, sizeof(first), funcarray, DOSBase))
114 goto end;
116 first = AROS_BE2LONG(first);
118 D(bug("\tFirst hunk: %ld\n", first));
119 curhunk = first;
120 if (read_block(fh, &last, sizeof(last), funcarray, DOSBase))
121 goto end;
123 last = AROS_BE2LONG(last);
125 D(bug("\tLast hunk: %ld\n", last));
127 for (i = first; i <= numhunks; i++) {
128 UBYTE *hunkptr;
129 ULONG hunksize;
131 if (i > last) {
132 hunktab[i] = BNULL;
133 continue;
136 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
137 goto end;
139 count = AROS_BE2LONG(count);
140 tmp = count & (HUNKF_FAST | HUNKF_CHIP);
141 count &= 0xFFFFFF;
142 D(bug("\tHunk %d size: 0x%06lx bytes in ", i, count*4));
143 req = MEMF_CLEAR | MEMF_PUBLIC;
144 if (tmp == (HUNKF_FAST | HUNKF_CHIP)) {
145 if (read_block(fh, &req, sizeof(req), funcarray, DOSBase))
146 goto end;
147 req = AROS_BE2LONG(req);
148 D(bug("FLAGS=%08x", req));
149 } else if (tmp == HUNKF_FAST) {
150 D(bug("FAST"));
151 req |= MEMF_FAST;
152 } else if (tmp == HUNKF_CHIP) {
153 D(bug("CHIP"));
154 req |= MEMF_CHIP;
156 D(bug(" memory"));
159 * We need space for the code, the length of this hunk and
160 * for a pointer to the next hunk.
161 * Note also MEMF_31BIT flag appended to memory requirements.
162 * This is important on 64-bit machines where AmigaDOS hunk
163 * files need to be loaded into low memory (<2GB). This is needed
164 * for correct interpretation of pointers in these files.
165 * Yes, they can't be executed in such environments, but they still can
166 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
168 hunksize = count * 4 + sizeof(ULONG) + sizeof(BPTR);
169 hunkptr = ilsAllocVec(hunksize, req | MEMF_31BIT);
170 if (!hunkptr)
171 ERROR(ERROR_NO_FREE_STORE);
172 hunktab[i] = MKBADDR(hunkptr);
173 D(bug(" @%p\n", hunkptr));
174 if (!firsthunk)
175 firsthunk = hunktab[i];
176 /* Link hunks
177 if this is not the first hunk that is loaded, then connect
178 it to the previous one (pointer to the field where the
179 pointer to the next hunk is located)
181 if (prevhunk)
182 ((BPTR *)(BADDR(prevhunk)))[0] = hunktab[i];
183 prevhunk = hunktab[i];
186 while(!read_block(fh, &hunktype, sizeof(hunktype), funcarray, DOSBase))
188 hunktype = AROS_BE2LONG(hunktype);
189 D(bug("Hunk Type: %d\n", hunktype & 0xFFFFFF));
191 switch(hunktype & 0xFFFFFF)
193 case HUNK_SYMBOL:
194 /* The SYMBOL_HUNK looks like this:
195 ---------------------
196 | n = size of | This
197 | symbol in longs | may
198 |-------------------| be
199 | n longwords = name| repeated
200 | of symbol | any
201 |-------------------| number
202 | value (1 long) | of times
203 --------------------|
204 | 0 = end of HUNK_ |
205 | SYMBOL |
206 -------------------- */
208 D(bug("HUNK_SYMBOL (skipping)\n"));
209 while(!read_block(fh, &count, sizeof(count), funcarray, DOSBase) && count)
211 count = AROS_BE2LONG(count) ;
213 if (seek_forward(fh, count+1, funcarray, DOSBase))
214 goto end;
216 break;
218 case HUNK_UNIT:
220 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
221 goto end;
223 count = AROS_BE2LONG(count) ;
225 count *= 4;
226 if (read_block(fh, name_buf, count, funcarray, DOSBase))
227 goto end;
228 D(bug("HUNK_UNIT: \"%.*s\"\n", count, name_buf));
229 break;
231 case HUNK_CODE:
232 case HUNK_DATA:
233 case HUNK_BSS:
235 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
236 goto end;
238 count = AROS_BE2LONG(count);
240 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
241 segtypes[(hunktype & 0xFFFFFF)-HUNK_CODE], curhunk, count*4));
243 if ((hunktype & 0xFFFFFF) != HUNK_BSS && count)
245 if (read_block(fh, GETHUNKPTR(curhunk), count*4, funcarray, DOSBase))
246 goto end;
250 lasthunk = curhunk;
251 ++curhunk;
252 break;
254 case HUNK_RELOC32:
255 case HUNK_RELRELOC32:
256 D(bug("HUNK_RELOC32:\n"));
257 while (1)
259 ULONG *addr;
260 ULONG offset;
262 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
263 goto end;
264 if (count == 0L)
265 break;
267 count = AROS_BE2LONG(count);
269 i = count;
270 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
271 goto end;
273 count = AROS_BE2LONG(count);
275 D(bug("\tHunk #%ld:\n", count));
276 while (i > 0)
278 if (read_block(fh, &offset, sizeof(offset), funcarray, DOSBase))
279 goto end;
281 offset = AROS_BE2LONG(offset);
283 //D(bug("\t\t0x%06lx\n", offset));
284 addr = (ULONG *)(GETHUNKPTR(lasthunk) + offset);
286 /* See the above MEMF_31 explanation for why this
287 * works on AROS 64-bit.
289 if ((hunktype & 0xFFFFFF) == HUNK_RELRELOC32)
290 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)(GETHUNKPTR(count) - GETHUNKPTR(curhunk)));
291 else
292 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
294 --i;
297 break;
299 case HUNK_DREL32: /* For compatibility with V37 */
300 case HUNK_RELOC32SHORT:
302 ULONG Wordcount = 0;
303 ULONG offset;
305 while (1)
307 ULONG *addr;
308 UWORD word;
310 Wordcount++;
312 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
313 goto end;
314 if (word == 0L)
315 break;
317 word = AROS_BE2LONG(word);
319 i = word;
320 Wordcount++;
321 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
322 goto end;
324 word = AROS_BE2WORD(word);
326 count = word;
327 D(bug("\tHunk #%ld @%p: %ld relocations\n", count, GETHUNKPTR(lasthunk), i));
328 while (i > 0)
330 Wordcount++;
331 /* read a 16bit number (2 bytes) */
332 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
333 goto end;
335 /* offset now contains the byte offset in it`s 16 highest bits.
336 These 16 highest bits have to become the 16 lowest bits so
337 we get the word we need. */
338 offset = AROS_BE2WORD(word);
340 D(bug("\t\t0x%06lx += 0x%lx\n", offset, GETHUNKPTR(count)));
341 addr = (ULONG *)(GETHUNKPTR(lasthunk) + offset);
343 /* See the above MEMF_31 explanation for why this
344 * works on AROS 64-bit.
346 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
348 --i;
349 } /* while (i > 0)*/
350 } /* while (1) */
352 /* if the amount of words read was odd, then skip the following
353 16-bit word */
354 if (0x1 == (Wordcount & 0x1)) {
355 UWORD word;
356 read_block(fh, &word, sizeof(word), funcarray, DOSBase);
359 break;
361 case HUNK_END:
363 D(bug("HUNK_END\n"));
364 /* DOSBase == NULL: Called from RDB filesystem loader which does not
365 * know filesystem's original size. Exit if last HUNK_END. This can't
366 * be done normally because it would break overlayed executables.
368 if (!DOSBase && curhunk > last)
369 goto done;
371 break;
373 case HUNK_RELOC16:
374 bug("HUNK_RELOC16 not implemented\n");
375 ERROR(ERROR_BAD_HUNK);
377 case HUNK_RELOC8:
378 bug("HUNK_RELOC8 not implemented\n");
379 ERROR(ERROR_BAD_HUNK);
381 case HUNK_NAME:
382 bug("HUNK_NAME not implemented\n");
383 ERROR(ERROR_BAD_HUNK);
385 case HUNK_EXT:
386 bug("HUNK_EXT not implemented\n");
387 ERROR(ERROR_BAD_HUNK);
389 case HUNK_DEBUG:
390 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
391 goto end;
393 count = AROS_BE2LONG(count);
395 D(bug("HUNK_DEBUG (%x Bytes)\n",count));
396 if (seek_forward(fh, count, funcarray, DOSBase))
397 goto end;
398 break;
400 case HUNK_OVERLAY:
402 D(bug("HUNK_OVERLAY:\n"));
403 if (table) /* overlay inside overlay? */
404 ERROR(ERROR_BAD_HUNK);
405 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
406 goto end;
407 count = AROS_BE2LONG(count);
408 D(bug("Overlay table size: %d\n", count));
410 /* See above for MEMF_31BIT explanation */
411 count = count * 4 + sizeof(ULONG) + sizeof(ULONG);
412 overlaytable = ilsAllocVec(count, MEMF_CLEAR | MEMF_31BIT);
413 if (overlaytable == NULL)
414 ERROR(ERROR_NO_FREE_STORE);
415 if (read_block(fh, overlaytable, count - sizeof(ULONG), funcarray, DOSBase))
416 goto end;
417 goto done;
420 case HUNK_BREAK:
421 D(bug("HUNK_BREAK\n"));
422 if (!table)
423 ERROR(ERROR_BAD_HUNK);
424 goto done;
426 default:
427 if (hunktype & HUNKF_ADVISORY) {
428 D(bug("Unknown hunk 0x%06lx with advisory flag skipped\n", hunktype & 0xFFFFFF));
429 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
430 goto end;
431 count = AROS_BE2LONG(count);
432 if (seek_forward(fh, count * 4, funcarray, DOSBase))
433 goto end;
434 } else {
435 bug("Hunk type 0x%06lx not implemented\n", hunktype & 0xFFFFFF);
436 ERROR(ERROR_BAD_HUNK);
438 } /* switch */
439 } /* while */
440 done:
441 if (firsthunk && !allowed_hunk(firsthunk))
443 ERROR(ERROR_NOT_EXECUTABLE);
444 goto end;
447 if (hunktab)
449 ULONG hunksize;
451 #ifdef __mc68000
453 * On non-m68k systems, hunk files are not executable.
454 * And even if AROS ever gets m68k emulator, they are still data files.
455 * So we flush caches only on m68k.
457 if (SysBase->LibNode.lib_Version >= 36)
459 /* Clear caches */
460 for (t = first; t < numhunks && t <= last; t++)
462 hunksize = *((ULONG*)BADDR(hunktab[t]) - 1);
463 if (hunksize)
464 CacheClearE(BADDR(hunktab[t]), hunksize, CACRF_ClearI | CACRF_ClearD);
467 #endif
469 if (table)
470 return firsthunk;
472 hunksize = *((ULONG*)BADDR(hunktab[0]) - 1);
473 if (last > first && hunksize >= 32 / 4)
475 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
476 ULONG *h = (ULONG*)(BADDR(hunktab[first]));
478 if (h[2] == 0x0000abcd)
480 #if __WORDSIZE != 32
481 D(bug("overlay not supported!\n"));
482 ERROR(ERROR_BAD_HUNK);
483 #else
484 /* overlay executable */
485 h[3] = (ULONG)fh;
486 h[4] = (ULONG)overlaytable;
487 h[5] = (ULONG)MKBADDR(hunktab);
488 D(bug("overlay loaded!\n"));
489 return (BPTR)(-(LONG)MKBADDR(h));
490 #endif
494 if (overlaytable) {
495 ilsFreeVec(overlaytable);
496 ERROR(ERROR_BAD_HUNK);
499 last_p = firsthunk;
501 register_hunk(fh, firsthunk, NULL, DOSBase);
503 ilsFreeVec(hunktab);
504 hunktab = NULL;
507 end:
508 if (hunktab != NULL)
510 for (t = 0 /* first */; t < numhunks /* last */; t++)
511 ilsFreeVec(BADDR(hunktab[t]));
512 ilsFreeVec(hunktab);
514 return last_p;
515 } /* InternalLoadSeg */
517 #ifdef __mc68000
518 static AROS_UFH4(LONG, ReadFunc,
519 AROS_UFHA(BPTR, file, D1),
520 AROS_UFHA(APTR, buffer, D2),
521 AROS_UFHA(LONG, length, D3),
522 AROS_UFHA(struct DosLibrary *, DOSBase, A6)
525 AROS_USERFUNC_INIT
527 return FRead(file, buffer, 1, length);
529 AROS_USERFUNC_EXIT
532 static AROS_UFH3(APTR, AllocFunc,
533 AROS_UFHA(ULONG, length, D0),
534 AROS_UFHA(ULONG, flags, D1),
535 AROS_UFHA(struct ExecBase *, SysBase, A6)
538 AROS_USERFUNC_INIT
540 return AllocMem(length, flags);
542 AROS_USERFUNC_EXIT
545 static AROS_UFH3(void, FreeFunc,
546 AROS_UFHA(APTR, buffer, A1),
547 AROS_UFHA(ULONG, length, D0),
548 AROS_UFHA(struct ExecBase *, SysBase, A6)
551 AROS_USERFUNC_INIT
553 FreeMem(buffer, length);
555 AROS_USERFUNC_EXIT
558 AROS_UFH4(BPTR, LoadSeg_Overlay,
559 AROS_UFHA(UBYTE*, name, D1),
560 AROS_UFHA(BPTR, hunktable, D2),
561 AROS_UFHA(BPTR, fh, D3),
562 AROS_UFHA(struct DosLibrary *, DosBase, A6))
564 AROS_USERFUNC_INIT
566 void (*FunctionArray[3])();
567 ULONG hunktype;
569 FunctionArray[0] = (APTR)ReadFunc;
570 FunctionArray[1] = (APTR)AllocFunc;
571 FunctionArray[2] = (APTR)FreeFunc;
573 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable, fh));
574 if (read_block(fh, &hunktype, sizeof(hunktype), (SIPTR*)FunctionArray, DosBase))
575 return BNULL;
576 hunktype = AROS_BE2LONG(hunktype);
577 if (hunktype != HUNK_HEADER)
578 return BNULL;
579 return InternalLoadSeg_AOS(fh, hunktable, (SIPTR*)FunctionArray, NULL, DosBase);
581 AROS_USERFUNC_EXIT
584 #endif
586 static BOOL allowed_hunk(BPTR seglist)
588 #ifdef __mc68000
589 return TRUE;
590 #else
591 /* deadwood: This is a not-so-great solution to the problem of crashes/reboots
592 * when users accidentally try running m68k hunk executables.
593 * I think the better solution would be to load the hunk (or non-native elf)
594 * but stop it from executing or redirect to emulator by mechanism similar
595 * to OS4 GetSegListInfo() and struct PseudoSegList. This way also runtime
596 * generated seglists would be handled properly.
598 UBYTE * ptr = (UBYTE *)BADDR(seglist);
600 /* Allow bitmap fonts */
601 if (ptr[22] == 0x0f && ptr[23] == 0x80)
602 return TRUE;
604 return FALSE;
605 #endif