- Fixed reporting of Chip RAM for Total RAM.
[AROS.git] / rom / dos / internalloadseg_aos.c
blob8929c7f18b760b91bce69ab5fde071f26e0484b8
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
8 #define DEBUG 0
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, 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 error =&((struct Process *)FindTask(NULL))->pr_Result2;
80 curhunk = 0; /* keep GCC quiet */
81 /* start point is HUNK_HEADER + 4 */
82 while (1)
84 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
85 goto end;
86 if (count == 0L)
87 break;
88 count = AROS_BE2LONG(count);
89 count *= 4;
90 if (read_block(fh, name_buf, count, funcarray, DOSBase))
91 goto end;
92 D(bug("\tlibname: \"%.*s\"\n", count, name_buf));
94 if (read_block(fh, &numhunks, sizeof(numhunks), funcarray, DOSBase))
95 goto end;
97 numhunks = AROS_BE2LONG(numhunks);
99 D(bug("\tHunk count: %ld\n", numhunks));
101 if (!hunktab) {
102 hunktab = ilsAllocVec(sizeof(BPTR) * (numhunks + 1 + 1), MEMF_CLEAR);
103 if (hunktab == NULL)
104 ERROR(ERROR_NO_FREE_STORE);
107 if (read_block(fh, &first, sizeof(first), funcarray, DOSBase))
108 goto end;
110 first = AROS_BE2LONG(first);
112 D(bug("\tFirst hunk: %ld\n", first));
113 curhunk = first;
114 if (read_block(fh, &last, sizeof(last), funcarray, DOSBase))
115 goto end;
117 last = AROS_BE2LONG(last);
119 D(bug("\tLast hunk: %ld\n", last));
121 for (i = first; i <= numhunks; i++) {
122 UBYTE *hunkptr;
123 ULONG hunksize;
125 if (i > last) {
126 hunktab[i] = BNULL;
127 continue;
130 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
131 goto end;
133 count = AROS_BE2LONG(count);
135 tmp = count & 0xFF000000;
136 count &= 0xFFFFFF;
137 D(bug("\tHunk %d size: 0x%06lx bytes in ", i, count*4));
138 req = MEMF_CLEAR | MEMF_PUBLIC;
140 switch(tmp)
142 case HUNKF_FAST:
143 D(bug("FAST"));
144 req |= MEMF_FAST;
145 break;
147 case HUNKF_CHIP:
148 D(bug("CHIP"));
149 req |= MEMF_CHIP;
150 break;
152 case HUNKF_ADVISORY:
153 D(bug("ADVISORY"));
154 if (read_block(fh, &req, sizeof(req), funcarray, DOSBase))
155 goto end;
156 req = AROS_BE2LONG(req);
157 break;
159 default:
160 D(bug("ANY"));
161 req |= MEMF_ANY;
162 break;
165 D(bug(" memory"));
167 * We need space for the code, the length of this hunk and
168 * for a pointer to the next hunk.
169 * Note also MEMF_31BIT flag appended to memory requirements.
170 * This is important on 64-bit machines where AmigaDOS hunk
171 * files need to be loaded into low memory (<2GB). This is needed
172 * for correct interpretation of pointers in these files.
173 * Yes, they can't be executed in such environments, but they still can
174 * be read as data files. This allows to use Amiga bitmap fonts on AROS.
176 hunksize = count * 4 + sizeof(ULONG) + sizeof(BPTR);
177 hunkptr = ilsAllocVec(hunksize, req | MEMF_31BIT);
178 if (!hunkptr)
179 ERROR(ERROR_NO_FREE_STORE);
180 hunktab[i] = MKBADDR(hunkptr);
181 D(bug(" @%p\n", hunkptr));
182 if (!firsthunk)
183 firsthunk = hunktab[i];
184 /* Link hunks
185 if this is not the first hunk that is loaded, then connect
186 it to the previous one (pointer to the field where the
187 pointer to the next hunk is located)
189 if (prevhunk)
190 ((BPTR *)(BADDR(prevhunk)))[0] = hunktab[i];
191 prevhunk = hunktab[i];
194 while(!read_block(fh, &hunktype, sizeof(hunktype), funcarray, DOSBase))
196 hunktype = AROS_BE2LONG(hunktype);
197 D(bug("Hunk Type: %d\n", hunktype & 0xFFFFFF));
199 switch(hunktype & 0xFFFFFF)
201 case HUNK_SYMBOL:
202 /* The SYMBOL_HUNK looks like this:
203 ---------------------
204 | n = size of | This
205 | symbol in longs | may
206 |-------------------| be
207 | n longwords = name| repeated
208 | of symbol | any
209 |-------------------| number
210 | value (1 long) | of times
211 --------------------|
212 | 0 = end of HUNK_ |
213 | SYMBOL |
214 -------------------- */
216 D(bug("HUNK_SYMBOL (skipping)\n"));
217 while(!read_block(fh, &count, sizeof(count), funcarray, DOSBase) && count)
219 count = AROS_BE2LONG(count) ;
221 if (seek_forward(fh, count+1, funcarray, DOSBase))
222 goto end;
224 break;
226 case HUNK_UNIT:
228 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
229 goto end;
231 count = AROS_BE2LONG(count) ;
233 count *= 4;
234 if (read_block(fh, name_buf, count, funcarray, DOSBase))
235 goto end;
236 D(bug("HUNK_UNIT: \"%.*s\"\n", count, name_buf));
237 break;
239 case HUNK_CODE:
240 case HUNK_DATA:
241 case HUNK_BSS:
243 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
244 goto end;
246 count = AROS_BE2LONG(count);
248 D(bug("HUNK_%s(%d): Length: 0x%06lx bytes in ",
249 segtypes[(hunktype & 0xFFFFFF)-HUNK_CODE], curhunk, count*4));
251 switch(hunktype & 0xFF000000)
253 case HUNKF_FAST:
254 D(bug("FAST"));
255 req = MEMF_FAST;
256 break;
258 case HUNKF_CHIP:
259 D(bug("CHIP"));
260 req = MEMF_CHIP;
261 break;
263 case HUNKF_ADVISORY:
264 D(bug("ADVISORY"));
265 if (read_block(fh, &req, sizeof(req), funcarray, DOSBase))
266 goto end;
268 req = AROS_BE2LONG(req);
270 break;
272 default:
273 D(bug("ANY"));
274 req = MEMF_ANY;
275 break;
278 D(bug(" memory\n"));
279 if ((hunktype & 0xFFFFFF) != HUNK_BSS && count)
281 if (read_block(fh, GETHUNKPTR(curhunk), count*4, funcarray, DOSBase))
282 goto end;
285 break;
287 case HUNK_RELOC32:
288 D(bug("HUNK_RELOC32:\n"));
289 while (1)
291 ULONG *addr;
292 ULONG offset;
294 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
295 goto end;
296 if (count == 0L)
297 break;
299 count = AROS_BE2LONG(count);
301 i = count;
302 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
303 goto end;
305 count = AROS_BE2LONG(count);
307 D(bug("\tHunk #%ld:\n", count));
308 while (i > 0)
310 if (read_block(fh, &offset, sizeof(offset), funcarray, DOSBase))
311 goto end;
313 offset = AROS_BE2LONG(offset);
315 //D(bug("\t\t0x%06lx\n", offset));
316 addr = (ULONG *)(GETHUNKPTR(curhunk) + offset);
318 /* See the above MEMF_31 explanation for why this
319 * works on AROS 64-bit.
321 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
323 --i;
326 break;
328 case HUNK_DREL32: /* For compatibility with V37 */
329 case HUNK_RELOC32SHORT:
331 ULONG Wordcount = 0;
332 ULONG offset;
334 while (1)
336 ULONG *addr;
337 UWORD word;
339 Wordcount++;
341 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
342 goto end;
343 if (word == 0L)
344 break;
346 word = AROS_BE2LONG(word);
348 i = word;
349 Wordcount++;
350 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
351 goto end;
353 word = AROS_BE2WORD(word);
355 count = word;
356 D(bug("\tHunk #%ld @%p: %ld relocations\n", count, GETHUNKPTR(curhunk), i));
357 while (i > 0)
359 Wordcount++;
360 /* read a 16bit number (2 bytes) */
361 if (read_block(fh, &word, sizeof(word), funcarray, DOSBase))
362 goto end;
364 /* offset now contains the byte offset in it`s 16 highest bits.
365 These 16 highest bits have to become the 16 lowest bits so
366 we get the word we need. */
367 offset = AROS_BE2WORD(word);
369 D(bug("\t\t0x%06lx += 0x%lx\n", offset, GETHUNKPTR(count)));
370 addr = (ULONG *)(GETHUNKPTR(curhunk) + offset);
372 /* See the above MEMF_31 explanation for why this
373 * works on AROS 64-bit.
375 *addr = (ULONG)(AROS_BE2LONG(*addr) + (IPTR)GETHUNKPTR(count));
377 --i;
378 } /* while (i > 0)*/
379 } /* while (1) */
381 /* if the amount of words read was odd, then skip the following
382 16-bit word */
383 if (0x1 == (Wordcount & 0x1)) {
384 UWORD word;
385 read_block(fh, &word, sizeof(word), funcarray, DOSBase);
388 break;
390 case HUNK_END:
392 D(bug("HUNK_END\n"));
393 ++curhunk;
394 /* DOSBase == NULL: Called from RDB filesystem loader which does not
395 * know filesystem's original size. Exit if last HUNK_END. This can't
396 * be done normally because it would break overlayed executables.
398 if (!DOSBase && curhunk > last)
399 goto done;
401 break;
403 case HUNK_RELOC16:
404 bug("HUNK_RELOC16 not implemented\n");
405 ERROR(ERROR_BAD_HUNK);
407 case HUNK_RELOC8:
408 bug("HUNK_RELOC8 not implemented\n");
409 ERROR(ERROR_BAD_HUNK);
411 case HUNK_NAME:
412 bug("HUNK_NAME not implemented\n");
413 ERROR(ERROR_BAD_HUNK);
415 case HUNK_EXT:
416 bug("HUNK_EXT not implemented\n");
417 ERROR(ERROR_BAD_HUNK);
419 case HUNK_DEBUG:
420 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
421 goto end;
423 count = AROS_BE2LONG(count);
425 D(bug("HUNK_DEBUG (%x Bytes)\n",count));
426 if (seek_forward(fh, count, funcarray, DOSBase))
427 goto end;
428 break;
430 case HUNK_OVERLAY:
432 D(bug("HUNK_OVERLAY:\n"));
433 if (table) /* overlay inside overlay? */
434 ERROR(ERROR_BAD_HUNK);
435 if (read_block(fh, &count, sizeof(count), funcarray, DOSBase))
436 goto end;
437 count = AROS_BE2LONG(count);
438 D(bug("Overlay table size: %d\n", count));
440 /* See above for MEMF_31BIT explanation */
441 count = count * 4 + sizeof(ULONG) + sizeof(ULONG);
442 overlaytable = ilsAllocVec(count, MEMF_CLEAR | MEMF_31BIT);
443 if (overlaytable == NULL)
444 ERROR(ERROR_NO_FREE_STORE);
445 if (read_block(fh, overlaytable, count - sizeof(ULONG), funcarray, DOSBase))
446 goto end;
447 goto done;
450 case HUNK_BREAK:
451 D(bug("HUNK_BREAK\n"));
452 if (!table)
453 ERROR(ERROR_BAD_HUNK);
454 goto done;
456 default:
457 bug("Hunk type 0x%06lx not implemented\n", hunktype & 0xFFFFFF);
458 ERROR(ERROR_BAD_HUNK);
459 } /* switch */
460 } /* while */
461 done:
462 if (hunktab)
464 ULONG hunksize;
466 #ifdef __mc68000
468 * On non-m68k systems, hunk files are not executable.
469 * And even if AROS ever gets m68k emulator, they are still data files.
470 * So we flush caches only on m68k.
472 if (SysBase->LibNode.lib_Version >= 36)
474 /* Clear caches */
475 for (t = first; t < numhunks && t <= last; t++)
477 hunksize = *((ULONG*)BADDR(hunktab[t]) - 1);
478 if (hunksize)
479 CacheClearE(BADDR(hunktab[t]), hunksize, CACRF_ClearI | CACRF_ClearD);
482 #endif
484 if (table)
485 return firsthunk;
487 hunksize = *((ULONG*)BADDR(hunktab[0]) - 1);
488 if (last > first && hunksize >= 32 / 4)
490 /* NOTE: HUNK_OVERLAY is not required for overlay mode. */
491 ULONG *h = (ULONG*)(BADDR(hunktab[first]));
493 if (h[2] == 0x0000abcd)
495 #if __WORDSIZE != 32
496 D(bug("overlay not supported!\n"));
497 ERROR(ERROR_BAD_HUNK);
498 #else
499 /* overlay executable */
500 h[3] = (ULONG)fh;
501 h[4] = (ULONG)overlaytable;
502 h[5] = (ULONG)MKBADDR(hunktab);
503 D(bug("overlay loaded!\n"));
504 return (BPTR)(-(LONG)MKBADDR(h));
505 #endif
509 if (overlaytable) {
510 ilsFreeVec(overlaytable);
511 ERROR(ERROR_BAD_HUNK);
514 last_p = firsthunk;
516 ilsFreeVec(hunktab);
517 hunktab = NULL;
520 end:
521 if (hunktab != NULL)
523 for (t = 0 /* first */; t < numhunks /* last */; t++)
524 ilsFreeVec(BADDR(hunktab[t]));
525 ilsFreeVec(hunktab);
527 return last_p;
528 } /* InternalLoadSeg */
530 #ifdef __mc68000
531 static AROS_UFH4(LONG, ReadFunc,
532 AROS_UFHA(BPTR, file, D1),
533 AROS_UFHA(APTR, buffer, D2),
534 AROS_UFHA(LONG, length, D3),
535 AROS_UFHA(struct DosLibrary *, DOSBase, A6)
538 AROS_USERFUNC_INIT
540 return FRead(file, buffer, 1, length);
542 AROS_USERFUNC_EXIT
545 static AROS_UFH3(APTR, AllocFunc,
546 AROS_UFHA(ULONG, length, D0),
547 AROS_UFHA(ULONG, flags, D1),
548 AROS_UFHA(struct ExecBase *, SysBase, A6)
551 AROS_USERFUNC_INIT
553 return AllocMem(length, flags);
555 AROS_USERFUNC_EXIT
558 static AROS_UFH3(void, FreeFunc,
559 AROS_UFHA(APTR, buffer, A1),
560 AROS_UFHA(ULONG, length, D0),
561 AROS_UFHA(struct ExecBase *, SysBase, A6)
564 AROS_USERFUNC_INIT
566 FreeMem(buffer, length);
568 AROS_USERFUNC_EXIT
571 AROS_UFH4(BPTR, LoadSeg_Overlay,
572 AROS_UFHA(UBYTE*, name, D1),
573 AROS_UFHA(BPTR, hunktable, D2),
574 AROS_UFHA(BPTR, fh, D3),
575 AROS_UFHA(struct DosLibrary *, DosBase, A6))
577 AROS_USERFUNC_INIT
579 void (*FunctionArray[3])();
580 ULONG hunktype;
582 FunctionArray[0] = (APTR)ReadFunc;
583 FunctionArray[1] = (APTR)AllocFunc;
584 FunctionArray[2] = (APTR)FreeFunc;
586 D(bug("LoadSeg_Overlay. table=%x fh=%x\n", hunktable, fh));
587 if (read_block(fh, &hunktype, sizeof(hunktype), (SIPTR*)FunctionArray, DosBase))
588 return BNULL;
589 hunktype = AROS_BE2LONG(hunktype);
590 if (hunktype != HUNK_HEADER)
591 return BNULL;
592 return InternalLoadSeg_AOS(fh, hunktable, (SIPTR*)FunctionArray, NULL, DosBase);
594 AROS_USERFUNC_EXIT
597 #endif