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 static BOOL
allowed_hunk(BPTR seglist
);
54 BPTR
InternalLoadSeg_AOS(BPTR fh
,
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
;
70 UBYTE
*overlaytable
= NULL
;
74 static STRPTR segtypes
[] = { "CODE", "DATA", "BSS", };
77 SIPTR
*error
= &dummy
;
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 */
90 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
94 count
= AROS_BE2LONG(count
);
96 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
98 D(bug("\tlibname: \"%.*s\"\n", count
, name_buf
));
100 if (read_block(fh
, &numhunks
, sizeof(numhunks
), funcarray
, DOSBase
))
103 numhunks
= AROS_BE2LONG(numhunks
);
105 D(bug("\tHunk count: %ld\n", numhunks
));
108 hunktab
= ilsAllocVec(sizeof(BPTR
) * (numhunks
+ 1 + 1), MEMF_CLEAR
);
110 ERROR(ERROR_NO_FREE_STORE
);
113 if (read_block(fh
, &first
, sizeof(first
), funcarray
, DOSBase
))
116 first
= AROS_BE2LONG(first
);
118 D(bug("\tFirst hunk: %ld\n", first
));
120 if (read_block(fh
, &last
, sizeof(last
), funcarray
, DOSBase
))
123 last
= AROS_BE2LONG(last
);
125 D(bug("\tLast hunk: %ld\n", last
));
127 for (i
= first
; i
<= numhunks
; i
++) {
136 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
139 count
= AROS_BE2LONG(count
);
140 tmp
= count
& (HUNKF_FAST
| HUNKF_CHIP
);
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
))
147 req
= AROS_BE2LONG(req
);
148 D(bug("FLAGS=%08x", req
));
149 } else if (tmp
== HUNKF_FAST
) {
152 } else if (tmp
== HUNKF_CHIP
) {
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
);
171 ERROR(ERROR_NO_FREE_STORE
);
172 hunktab
[i
] = MKBADDR(hunkptr
);
173 D(bug(" @%p\n", hunkptr
));
175 firsthunk
= hunktab
[i
];
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)
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)
194 /* The SYMBOL_HUNK looks like this:
195 ---------------------
197 | symbol in longs | may
198 |-------------------| be
199 | n longwords = name| repeated
201 |-------------------| number
202 | value (1 long) | of times
203 --------------------|
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
))
220 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
223 count
= AROS_BE2LONG(count
) ;
226 if (read_block(fh
, name_buf
, count
, funcarray
, DOSBase
))
228 D(bug("HUNK_UNIT: \"%.*s\"\n", count
, name_buf
));
235 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
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
))
255 case HUNK_RELRELOC32
:
256 D(bug("HUNK_RELOC32:\n"));
262 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
267 count
= AROS_BE2LONG(count
);
270 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
273 count
= AROS_BE2LONG(count
);
275 D(bug("\tHunk #%ld:\n", count
));
278 if (read_block(fh
, &offset
, sizeof(offset
), funcarray
, DOSBase
))
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
)));
292 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
299 case HUNK_DREL32
: /* For compatibility with V37 */
300 case HUNK_RELOC32SHORT
:
312 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
317 word
= AROS_BE2LONG(word
);
321 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
324 word
= AROS_BE2WORD(word
);
327 D(bug("\tHunk #%ld @%p: %ld relocations\n", count
, GETHUNKPTR(lasthunk
), i
));
331 /* read a 16bit number (2 bytes) */
332 if (read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
))
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
));
352 /* if the amount of words read was odd, then skip the following
354 if (0x1 == (Wordcount
& 0x1)) {
356 read_block(fh
, &word
, sizeof(word
), funcarray
, DOSBase
);
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
)
374 bug("HUNK_RELOC16 not implemented\n");
375 ERROR(ERROR_BAD_HUNK
);
378 bug("HUNK_RELOC8 not implemented\n");
379 ERROR(ERROR_BAD_HUNK
);
382 bug("HUNK_NAME not implemented\n");
383 ERROR(ERROR_BAD_HUNK
);
386 bug("HUNK_EXT not implemented\n");
387 ERROR(ERROR_BAD_HUNK
);
390 if (read_block(fh
, &count
, sizeof(count
), funcarray
, DOSBase
))
393 count
= AROS_BE2LONG(count
);
395 D(bug("HUNK_DEBUG (%x Bytes)\n",count
));
396 if (seek_forward(fh
, count
, funcarray
, DOSBase
))
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
))
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
))
421 D(bug("HUNK_BREAK\n"));
423 ERROR(ERROR_BAD_HUNK
);
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
))
431 count
= AROS_BE2LONG(count
);
432 if (seek_forward(fh
, count
* 4, funcarray
, DOSBase
))
435 bug("Hunk type 0x%06lx not implemented\n", hunktype
& 0xFFFFFF);
436 ERROR(ERROR_BAD_HUNK
);
441 if (firsthunk
&& !allowed_hunk(firsthunk
))
443 ERROR(ERROR_NOT_EXECUTABLE
);
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)
460 for (t
= first
; t
< numhunks
&& t
<= last
; t
++)
462 hunksize
= *((ULONG
*)BADDR(hunktab
[t
]) - 1);
464 CacheClearE(BADDR(hunktab
[t
]), hunksize
, CACRF_ClearI
| CACRF_ClearD
);
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)
481 D(bug("overlay not supported!\n"));
482 ERROR(ERROR_BAD_HUNK
);
484 /* overlay executable */
486 h
[4] = (ULONG
)overlaytable
;
487 h
[5] = (ULONG
)MKBADDR(hunktab
);
488 D(bug("overlay loaded!\n"));
489 return (BPTR
)(-(LONG
)MKBADDR(h
));
495 ilsFreeVec(overlaytable
);
496 ERROR(ERROR_BAD_HUNK
);
501 register_hunk(fh
, firsthunk
, NULL
, DOSBase
);
510 for (t
= 0 /* first */; t
< numhunks
/* last */; t
++)
511 ilsFreeVec(BADDR(hunktab
[t
]));
515 } /* InternalLoadSeg */
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
)
527 return FRead(file
, buffer
, 1, length
);
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
)
540 return AllocMem(length
, flags
);
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
)
553 FreeMem(buffer
, length
);
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
))
566 void (*FunctionArray
[3])();
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
))
576 hunktype
= AROS_BE2LONG(hunktype
);
577 if (hunktype
!= HUNK_HEADER
)
579 return InternalLoadSeg_AOS(fh
, hunktable
, (SIPTR
*)FunctionArray
, NULL
, DosBase
);
586 static BOOL
allowed_hunk(BPTR seglist
)
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)