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 #define LOADSEG_HUNK_BUFFER 2048
38 static int read_block_buffered(BPTR file
, APTR buffer
, ULONG size
, SIPTR
* funcarray
, struct SRBuffer
* srb
, struct DosLibrary
* DOSBase
)
41 return ilsRead(file
, buffer
, size
) == size
? 0 : 1;
44 srb
->buffer
= ilsAllocMem(LOADSEG_HUNK_BUFFER
, 0);
51 if (srb
->avail
== 0) {
53 srb
->avail
= ilsRead(file
, srb
->buffer
, LOADSEG_HUNK_BUFFER
);
57 tocopy
= srb
->avail
> size
? size
: srb
->avail
;
58 CopyMem(srb
->buffer
+ srb
->offset
, buffer
, tocopy
);
62 srb
->offset
+= tocopy
;
67 /* Seek forward by count ULONGs.
68 * Returns 0 on success, 1 on failure.
70 static int seek_forward(BPTR fd
, ULONG count
, SIPTR
*funcarray
, struct SRBuffer
*srb
, struct DosLibrary
*DOSBase
)
75 /* For AOS compatibility, we can't use DOS/Seek() here,
76 * as AOS callers to InternalLoadSeg will not pass
77 * in a Seek element of the funcarray, and the read
78 * callback of funcarray may be for reading in-memory
79 * instead of pointing to DOS/Read.
81 * Luckily, reading HUNKs is linear, so we can just
84 while (count
&& !(err
= read_block_buffered(fd
, &tmp
, sizeof(tmp
), funcarray
, srb
, DOSBase
)))
90 static BOOL
allowed_hunk(BPTR seglist
);
92 BPTR
InternalLoadSeg_AOS(BPTR fh
,
96 struct DosLibrary
* DOSBase
)
98 #define ERROR(a) { *error=a; goto end; }
101 BPTR
*hunktab
= BADDR(table
);
102 BPTR firsthunk
= BNULL
, prevhunk
= BNULL
;
103 ULONG hunktype
, count
, first
, last
, curhunk
, lasthunk
, numhunks
;
108 UBYTE
*overlaytable
= NULL
;
111 struct SRBuffer srbbuf
, *srb
;
113 static STRPTR segtypes
[] = { "CODE", "DATA", "BSS", };
116 SIPTR
*error
= &dummy
;
119 struct Process
*me
= (struct Process
*)FindTask(NULL
);
120 ASSERT_VALID_PROCESS(me
);
122 error
=&me
->pr_Result2
;
127 curhunk
= lasthunk
= 0; /* keep GCC quiet */
128 /* start point is HUNK_HEADER + 4 */
131 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
135 count
= AROS_BE2LONG(count
);
137 if (read_block_buffered(fh
, name_buf
, count
, funcarray
, srb
, DOSBase
))
139 D(bug("\tlibname: \"%.*s\"\n", count
, name_buf
));
141 if (read_block_buffered(fh
, &numhunks
, sizeof(numhunks
), funcarray
, srb
, DOSBase
))
144 numhunks
= AROS_BE2LONG(numhunks
);
146 D(bug("\tHunk count: %ld\n", numhunks
));
149 hunktab
= ilsAllocVec(sizeof(BPTR
) * (numhunks
+ 1 + 1), MEMF_CLEAR
);
151 ERROR(ERROR_NO_FREE_STORE
);
154 if (read_block_buffered(fh
, &first
, sizeof(first
), funcarray
, srb
, DOSBase
))
157 first
= AROS_BE2LONG(first
);
159 D(bug("\tFirst hunk: %ld\n", first
));
161 if (read_block_buffered(fh
, &last
, sizeof(last
), funcarray
, srb
, DOSBase
))
164 last
= AROS_BE2LONG(last
);
166 D(bug("\tLast hunk: %ld\n", last
));
168 for (i
= first
; i
<= numhunks
; i
++) {
177 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
180 count
= AROS_BE2LONG(count
);
181 tmp
= count
& (HUNKF_FAST
| HUNKF_CHIP
);
183 D(bug("\tHunk %d size: 0x%06lx bytes in ", i
, count
*4));
184 req
= MEMF_CLEAR
| MEMF_PUBLIC
;
185 if (tmp
== (HUNKF_FAST
| HUNKF_CHIP
)) {
186 if (read_block_buffered(fh
, &req
, sizeof(req
), funcarray
, srb
, DOSBase
))
188 req
= AROS_BE2LONG(req
);
189 D(bug("FLAGS=%08x", req
));
190 } else if (tmp
== HUNKF_FAST
) {
193 } else if (tmp
== HUNKF_CHIP
) {
200 * We need space for the code, the length of this hunk and
201 * for a pointer to the next hunk.
202 * Note also MEMF_31BIT flag appended to memory requirements.
203 * This is important on 64-bit machines where AmigaDOS hunk
204 * files need to be loaded into low memory (<2GB). This is needed
205 * for correct interpretation of pointers in these files.
206 * Yes, they can't be executed in such environments, but they still can
207 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
209 hunksize
= count
* 4 + sizeof(ULONG
) + sizeof(BPTR
);
210 hunkptr
= ilsAllocVec(hunksize
, req
| MEMF_31BIT
);
212 ERROR(ERROR_NO_FREE_STORE
);
213 hunktab
[i
] = MKBADDR(hunkptr
);
214 D(bug(" @%p\n", hunkptr
));
216 firsthunk
= hunktab
[i
];
218 if this is not the first hunk that is loaded, then connect
219 it to the previous one (pointer to the field where the
220 pointer to the next hunk is located)
223 ((BPTR
*)(BADDR(prevhunk
)))[0] = hunktab
[i
];
224 prevhunk
= hunktab
[i
];
227 while(!read_block_buffered(fh
, &hunktype
, sizeof(hunktype
), funcarray
, srb
, DOSBase
))
229 hunktype
= AROS_BE2LONG(hunktype
);
230 D(bug("Hunk Type: %d\n", hunktype
& 0xFFFFFF));
232 switch(hunktype
& 0xFFFFFF)
235 /* The SYMBOL_HUNK looks like this:
236 ---------------------
238 | symbol in longs | may
239 |-------------------| be
240 | n longwords = name| repeated
242 |-------------------| number
243 | value (1 long) | of times
244 --------------------|
247 -------------------- */
249 D(bug("HUNK_SYMBOL (skipping)\n"));
250 while(!read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
) && count
)
252 count
= AROS_BE2LONG(count
) ;
254 if (seek_forward(fh
, count
+1, funcarray
, srb
, DOSBase
))
261 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
264 count
= AROS_BE2LONG(count
) ;
267 if (read_block_buffered(fh
, name_buf
, count
, funcarray
, srb
, DOSBase
))
269 D(bug("HUNK_UNIT: \"%.*s\"\n", count
, name_buf
));
276 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
279 count
= AROS_BE2LONG(count
);
281 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
282 segtypes
[(hunktype
& 0xFFFFFF)-HUNK_CODE
], curhunk
, count
*4));
284 if ((hunktype
& 0xFFFFFF) != HUNK_BSS
&& count
)
286 if (read_block_buffered(fh
, GETHUNKPTR(curhunk
), count
*4, funcarray
, srb
, DOSBase
))
296 case HUNK_RELRELOC32
:
297 D(bug("HUNK_RELOC32:\n"));
303 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
308 count
= AROS_BE2LONG(count
);
311 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
314 count
= AROS_BE2LONG(count
);
316 D(bug("\tHunk #%ld:\n", count
));
319 if (read_block_buffered(fh
, &offset
, sizeof(offset
), funcarray
, srb
, DOSBase
))
322 offset
= AROS_BE2LONG(offset
);
324 //D(bug("\t\t0x%06lx\n", offset));
325 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
327 /* See the above MEMF_31 explanation for why this
328 * works on AROS 64-bit.
330 if ((hunktype
& 0xFFFFFF) == HUNK_RELRELOC32
)
331 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)(GETHUNKPTR(count
) - GETHUNKPTR(curhunk
)));
333 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
340 case HUNK_DREL32
: /* For compatibility with V37 */
341 case HUNK_RELOC32SHORT
:
353 if (read_block_buffered(fh
, &word
, sizeof(word
), funcarray
, srb
, DOSBase
))
358 word
= AROS_BE2LONG(word
);
362 if (read_block_buffered(fh
, &word
, sizeof(word
), funcarray
, srb
, DOSBase
))
365 word
= AROS_BE2WORD(word
);
368 D(bug("\tHunk #%ld @%p: %ld relocations\n", count
, GETHUNKPTR(lasthunk
), i
));
372 /* read a 16bit number (2 bytes) */
373 if (read_block_buffered(fh
, &word
, sizeof(word
), funcarray
, srb
, DOSBase
))
376 /* offset now contains the byte offset in it`s 16 highest bits.
377 These 16 highest bits have to become the 16 lowest bits so
378 we get the word we need. */
379 offset
= AROS_BE2WORD(word
);
381 D(bug("\t\t0x%06lx += 0x%lx\n", offset
, GETHUNKPTR(count
)));
382 addr
= (ULONG
*)(GETHUNKPTR(lasthunk
) + offset
);
384 /* See the above MEMF_31 explanation for why this
385 * works on AROS 64-bit.
387 *addr
= (ULONG
)(AROS_BE2LONG(*addr
) + (IPTR
)GETHUNKPTR(count
));
393 /* if the amount of words read was odd, then skip the following
395 if (0x1 == (Wordcount
& 0x1)) {
397 read_block_buffered(fh
, &word
, sizeof(word
), funcarray
, srb
, DOSBase
);
404 D(bug("HUNK_END\n"));
405 /* DOSBase == NULL: Called from RDB filesystem loader which does not
406 * know filesystem's original size. Exit if last HUNK_END. This can't
407 * be done normally because it would break overlayed executables.
409 if (!DOSBase
&& curhunk
> last
)
415 bug("HUNK_RELOC16 not implemented\n");
416 ERROR(ERROR_BAD_HUNK
);
419 bug("HUNK_RELOC8 not implemented\n");
420 ERROR(ERROR_BAD_HUNK
);
423 bug("HUNK_NAME not implemented\n");
424 ERROR(ERROR_BAD_HUNK
);
427 bug("HUNK_EXT not implemented\n");
428 ERROR(ERROR_BAD_HUNK
);
431 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
434 count
= AROS_BE2LONG(count
);
436 D(bug("HUNK_DEBUG (%x Bytes)\n",count
));
437 if (seek_forward(fh
, count
, funcarray
, srb
, DOSBase
))
443 D(bug("HUNK_OVERLAY:\n"));
444 if (table
) /* overlay inside overlay? */
445 ERROR(ERROR_BAD_HUNK
);
446 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
448 count
= AROS_BE2LONG(count
);
449 D(bug("Overlay table size: %d\n", count
));
451 /* See above for MEMF_31BIT explanation */
452 count
= count
* 4 + sizeof(ULONG
) + sizeof(ULONG
);
453 overlaytable
= ilsAllocVec(count
, MEMF_CLEAR
| MEMF_31BIT
);
454 if (overlaytable
== NULL
)
455 ERROR(ERROR_NO_FREE_STORE
);
456 if (read_block_buffered(fh
, overlaytable
, count
- sizeof(ULONG
), funcarray
, srb
, DOSBase
))
462 D(bug("HUNK_BREAK\n"));
464 ERROR(ERROR_BAD_HUNK
);
468 if (hunktype
& HUNKF_ADVISORY
) {
469 D(bug("Unknown hunk 0x%06lx with advisory flag skipped\n", hunktype
& 0xFFFFFF));
470 if (read_block_buffered(fh
, &count
, sizeof(count
), funcarray
, srb
, DOSBase
))
472 count
= AROS_BE2LONG(count
);
473 if (seek_forward(fh
, count
* 4, funcarray
, srb
, DOSBase
))
476 bug("Hunk type 0x%06lx not implemented\n", hunktype
& 0xFFFFFF);
477 ERROR(ERROR_BAD_HUNK
);
482 if (firsthunk
&& !allowed_hunk(firsthunk
))
484 ERROR(ERROR_NOT_EXECUTABLE
);
494 * On non-m68k systems, hunk files are not executable.
495 * And even if AROS ever gets m68k emulator, they are still data files.
496 * So we flush caches only on m68k.
498 if (SysBase
->LibNode
.lib_Version
>= 36)
501 for (t
= first
; t
< numhunks
&& t
<= last
; t
++)
503 hunksize
= *((ULONG
*)BADDR(hunktab
[t
]) - 1);
505 CacheClearE(BADDR(hunktab
[t
]), hunksize
, CACRF_ClearI
| CACRF_ClearD
);
513 hunksize
= *((ULONG
*)BADDR(hunktab
[0]) - 1);
514 if (last
> first
&& hunksize
>= 32 / 4)
516 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
517 ULONG
*h
= (ULONG
*)(BADDR(hunktab
[first
]));
519 if (h
[2] == 0x0000abcd)
522 D(bug("overlay not supported!\n"));
523 ERROR(ERROR_BAD_HUNK
);
525 /* overlay executable */
527 h
[4] = (ULONG
)overlaytable
;
528 h
[5] = (ULONG
)MKBADDR(hunktab
);
529 D(bug("overlay loaded!\n"));
530 return (BPTR
)(-(LONG
)MKBADDR(h
));
536 ilsFreeVec(overlaytable
);
537 ERROR(ERROR_BAD_HUNK
);
542 register_hunk(fh
, firsthunk
, NULL
, DOSBase
);
551 for (t
= 0 /* first */; t
< numhunks
/* last */; t
++)
552 ilsFreeVec(BADDR(hunktab
[t
]));
555 ilsFreeMem(srb
->buffer
, LOADSEG_HUNK_BUFFER
);
557 } /* InternalLoadSeg */
560 static AROS_UFH4(LONG
, ReadFunc
,
561 AROS_UFHA(BPTR
, file
, D1
),
562 AROS_UFHA(APTR
, buffer
, D2
),
563 AROS_UFHA(LONG
, length
, D3
),
564 AROS_UFHA(struct DosLibrary
*, DOSBase
, A6
)
569 return FRead(file
, buffer
, 1, length
);
574 static AROS_UFH3(APTR
, AllocFunc
,
575 AROS_UFHA(ULONG
, length
, D0
),
576 AROS_UFHA(ULONG
, flags
, D1
),
577 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
582 return AllocMem(length
, flags
);
587 static AROS_UFH3(void, FreeFunc
,
588 AROS_UFHA(APTR
, buffer
, A1
),
589 AROS_UFHA(ULONG
, length
, D0
),
590 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
595 FreeMem(buffer
, length
);
600 AROS_UFH4(BPTR
, LoadSeg_Overlay
,
601 AROS_UFHA(UBYTE
*, name
, D1
),
602 AROS_UFHA(BPTR
, hunktable
, D2
),
603 AROS_UFHA(BPTR
, fh
, D3
),
604 AROS_UFHA(struct DosLibrary
*, DosBase
, A6
))
608 void (*FunctionArray
[3])();
611 FunctionArray
[0] = (APTR
)ReadFunc
;
612 FunctionArray
[1] = (APTR
)AllocFunc
;
613 FunctionArray
[2] = (APTR
)FreeFunc
;
615 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable
, fh
));
616 if (read_block_buffered(fh
, &hunktype
, sizeof(hunktype
), (SIPTR
*)FunctionArray
, NULL
, DosBase
))
618 hunktype
= AROS_BE2LONG(hunktype
);
619 if (hunktype
!= HUNK_HEADER
)
621 return InternalLoadSeg_AOS(fh
, hunktable
, (SIPTR
*)FunctionArray
, NULL
, DosBase
);
628 static BOOL
allowed_hunk(BPTR seglist
)
633 /* deadwood: This is a not-so-great solution to the problem of crashes/reboots
634 * when users accidentally try running m68k hunk executables.
635 * I think the better solution would be to load the hunk (or non-native elf)
636 * but stop it from executing or redirect to emulator by mechanism similar
637 * to OS4 GetSegListInfo() and struct PseudoSegList. This way also runtime
638 * generated seglists would be handled properly.
640 UBYTE
* ptr
= (UBYTE
*)BADDR(seglist
) + sizeof(BPTR
);
642 /* Allow bitmap fonts */
643 if (ptr
[18] == 0x0f && ptr
[19] == 0x80)