fix paths.
[AROS.git] / arch / m68k-amiga / c / AROSBootstrap.c
blob77e75747c80ac471f6b1f16900728a195980ee7b
1 /*
2 * Copyright (C) 2011, The AROS Development Team. All rights reserved.
4 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
5 */
7 /* This loads relocatable AROS ROM ELF images, and gzipped
8 * image. Use either the aros-amiga-m68k-reloc.elf or
9 * aros.elf.gz images. The fully linked aros-amiga-m68k.elf
10 * image cannot be loaded by this application.
12 * As you can probably guess, you will need at least 1MB of
13 * extra free RAM to get this to work.
15 * Also - no AROS specific code can go in here! We have to run
16 * on AOS 1.3 and up.
18 #define DEBUG 1
20 #include <proto/exec.h>
21 #include <proto/graphics.h>
22 #include <proto/dos.h>
23 #include <proto/expansion.h>
24 #include <exec/resident.h>
25 #include <aros/kernel.h>
26 #include <hardware/cpu/memory.h>
27 #include <libraries/configvars.h>
29 /* This much memory is wasted in single reset proof allocation */
30 #define ALLOCATION_EXTRA (sizeof(struct MemChunk))
31 #define ALLOCPADDING (sizeof(struct MemChunk) + 2 * sizeof(BPTR))
33 #define KERNELTAGS_TOTAL 16
34 #define CMDLINE_SIZE 512
36 #define SS_STACK_SIZE 0x2000
37 #define MAGIC_FAST_SIZE 65536
39 /* This structure must match with start.c! */
40 #define ABS_BOOT_MAGIC 0x4d363802
41 struct BootStruct
43 ULONG magic;
44 struct ExecBase *RealBase;
45 struct ExecBase *RealBase2;
46 struct List *mlist;
47 struct TagItem *kerneltags;
48 struct Resident **reslist;
49 struct ExecBase *FakeBase;
50 APTR bootcode;
51 APTR ss_address;
52 LONG ss_size;
53 APTR magicfastmem;
54 LONG magicfastmemsize;
57 #define BMC_NAME_SIZE 14
58 struct BootMemChunk
60 /* MemList must be first */
61 struct MemList ml;
62 BOOL inuse;
63 UBYTE name[BMC_NAME_SIZE];
66 #define BMC_MAX 32
67 #define RES_MAX 256
68 #define BOOTCODE 512
69 struct BootMemHeader
71 struct BootStruct boots;
72 APTR entrypoint;
73 struct Resident *res[RES_MAX];
74 struct ExecBase FakeBase;
75 UBYTE bootcode[BOOTCODE];
76 struct List mlist;
77 struct TagItem ktags[KERNELTAGS_TOTAL];
78 UBYTE kcmd[CMDLINE_SIZE];
79 UBYTE fakename[16];
80 struct BootMemChunk bmc[BMC_MAX];
83 #include <stddef.h> /* offsetof */
84 #include <string.h> /* memcpy, memset */
85 #include <zlib.h>
87 #if defined(DEBUG) && DEBUG > 1
88 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode mungwall"
89 #else
90 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode"
91 #endif
93 #define PROTO_KERNEL_H /* Don't pick up AROS kernel hooks */
95 #if DEBUG
96 #define AROS_DEBUG_H
97 #include <stdio.h>
98 #include <string.h>
99 static inline void bug(const char *fmt, ...)
101 static char buff[256];
102 va_list args;
104 va_start(args, fmt);
105 vsnprintf(buff, sizeof(buff), fmt, args);
106 va_end(args);
108 Write(Output(), buff, strlen(buff));
110 #define D(x) x
111 #else
112 #define D(x)
113 #endif
115 #include <loadseg.h>
117 struct ExecBase *SysBase;
118 struct DosLibrary *DOSBase;
119 struct Library *ExpansionBase;
121 static BOOL ROM_Loaded = FALSE;
122 static BOOL forceAROS = FALSE;
123 static BOOL forceCHIP = FALSE;
124 static BOOL forceFAST = FALSE;
125 static BOOL debug_enabled = FALSE;
127 static struct BootMemHeader *bmh;
129 /* KS 1.3 (and earlier) don't have a dos.library with
130 * niceties such as VFPrintf nor ReadArgs.
132 * We need to use the BCPL routines to be able
133 * to do these types of operations.
135 #define BCPL_WriteS 73
136 #define BCPL_WriteF 74
137 #define BCPL_RdArgs 78
139 #undef Printf
140 #define Printf __Printf_NOT_AVAILABLE_UNDER_KS1_3
141 #undef ReadArgs
142 #define ReadArgs __ReadArgs_NOT_AVAILABLE_UNDER_KS1_3
144 /* BCPL can trash D5-D7 and A3, evidently.
146 static void bcplWrapper(void)
148 asm volatile (
149 "movem.l %d5-%d7/%a3,%sp@-\n"
150 "jsr (%a5)\n"
151 "movem.l %sp@+,%d5-%d7/%a3\n"
155 static ULONG doBCPL(int index, ULONG d1, ULONG d2, ULONG d3, ULONG d4, const IPTR *arg, int args)
157 struct Process *pr = (APTR)FindTask(NULL);
158 APTR func;
159 ULONG *gv = pr->pr_GlobVec;
160 ULONG ret;
161 ULONG *BCPL_frame = AllocMem(1500, MEMF_ANY);
162 if (BCPL_frame == NULL)
163 return 0;
165 func = (APTR)gv[index];
167 if (args != 0)
168 CopyMem(arg, &BCPL_frame[3 + 4], args * sizeof(ULONG));
170 ret = AROS_UFC11(ULONG, bcplWrapper,
171 AROS_UFCA(ULONG, 0, D0), /* BCPL frame usage (args-3)*/
172 AROS_UFCA(ULONG, d1, D1),
173 AROS_UFCA(ULONG, d2, D2),
174 AROS_UFCA(ULONG, d3, D3),
175 AROS_UFCA(ULONG, d4, D4),
176 AROS_UFCA(ULONG, 0, A0), /* System memory base */
177 AROS_UFCA(ULONG *, &BCPL_frame[3], A1),
178 AROS_UFCA(APTR, gv, A2),
179 AROS_UFCA(APTR, func, A4),
180 AROS_UFCA(APTR, DOSBase->dl_A5, A5),
181 AROS_UFCA(APTR, DOSBase->dl_A6, A6));
183 FreeMem(BCPL_frame, 1500);
185 return ret;
188 #if DEBUG
189 static BSTR ConvertCSTR(const UBYTE *name)
191 UBYTE *bname = AllocMem(256 + 1, MEMF_CLEAR);
192 UWORD len = strlen(name), i;
194 if (len > 255)
195 len = 255;
196 bname[0] = len;
197 strcpy(bname + 1, name);
198 for (i = 0; i < len; i++) {
199 if (bname[1 + i] == 13 || bname[1 + i] == 10)
200 bname[i + 1] = ' ';
202 return MKBADDR(bname);
204 static void FreeBSTR(BSTR bstr)
206 FreeMem(BADDR(bstr), 256 + 1);
208 #endif
210 static UBYTE *ConvertBSTR(BSTR bname)
212 UBYTE *name = BADDR(bname);
213 UBYTE *s = AllocMem(256 + 1, MEMF_CLEAR);
214 if (!s)
215 return NULL;
216 CopyMem(name + 1, s, name[0]);
217 return s;
220 static void FreeString(UBYTE *cstr)
222 FreeMem(cstr, 256+1);
225 static void _WriteF(BPTR bfmt, ...)
227 IPTR *args = (IPTR *)&bfmt;
229 doBCPL(BCPL_WriteF, bfmt, args[1], args[2], args[3], &args[4], 26-3);
232 #if DEBUG
233 static void _DWriteF(BPTR bfmt, ...)
235 if (debug_enabled || DEBUG > 1) {
236 IPTR *args = (IPTR *)&bfmt;
238 doBCPL(BCPL_WriteF, bfmt, args[1], args[2], args[3], &args[4], 26-3);
241 #define DWriteF(fmt, args...) _DWriteF(AROS_CONST_BSTR(fmt) ,##args )
242 #endif
244 #define WriteF(fmt, args...) _WriteF(AROS_CONST_BSTR(fmt) ,##args )
246 /* For KS < 2.0, we need to call the BCPL ReadArgs,
247 * since DOS/ReadArgs doesn't exist.
249 static ULONG RdArgs(BSTR format, BPTR args, ULONG max_arg)
251 return doBCPL(BCPL_RdArgs, format, args, max_arg, 0, NULL, 0);
254 void meminfo(void)
256 struct MemHeader *mh;
257 ForeachNode(&SysBase->MemList, mh) {
258 char bstr[256];
259 bstr[0] = strlen(mh->mh_Node.ln_Name) & 0xff;
260 strncpy(&bstr[1], mh->mh_Node.ln_Name, bstr[0]);
261 WriteF("@$%X8-$%X8 ATTR $%X4 FREE $%X8 (%S)\n",
262 mh->mh_Lower, mh->mh_Upper, mh->mh_Attributes,
263 mh->mh_Free, MKBADDR(bstr));
267 /* Allocate MMU page aligned memory chunks */
269 static APTR AllocPageAligned(ULONG *psize, ULONG flags)
271 APTR ret;
272 ULONG size;
274 size = *psize;
275 size += ALLOCPADDING;
276 ret = AllocMem(size + 2 * PAGE_SIZE, flags);
277 D(DWriteF("AllocPageAligned: $%X8, %X4 => %X8\n", size + 2 * PAGE_SIZE, flags, ret));
278 if (ret == NULL)
279 return NULL;
280 Forbid();
281 FreeMem(ret, size + 2 * PAGE_SIZE);
282 size = (size + PAGE_SIZE - 1) & PAGE_MASK;
283 ret = AllocAbs(size, (APTR)(((((ULONG)ret) + PAGE_SIZE - 1) & PAGE_MASK)));
284 Permit();
285 if (ret == NULL)
286 return NULL;
287 *psize = size;
288 return ret;
290 static void FreePageAligned(APTR addr, ULONG size)
292 FreeMem(addr, (size + PAGE_SIZE - 1) & PAGE_MASK);
295 static BYTE getNodePri(APTR mem, ULONG flags)
297 BYTE pri = 0;
298 if (flags == 0xffffffff)
299 return 127;
300 if (flags & MEMF_CHIP)
301 pri = 10;
302 if (flags & MEMF_KICK)
303 pri++;
304 /* Check also addresses, some boards may lie */
305 /* Z2 */
306 if ((ULONG)mem >= 0x00200000 && (ULONG)mem < 0x00a00000)
307 pri = -10;
308 /* Z3 */
309 if ((ULONG)mem >= 0x10000000)
310 pri = -5;
311 return pri;
314 static BOOL addMemList(UBYTE *mem, ULONG size, ULONG flags, const char *name, BOOL resscan)
316 int i;
317 struct BootMemChunk *bmc = NULL;
318 struct MemList *ml;
320 D(WriteF("AddMemList %X8 %N\n", mem, size));
321 for (i = 0; i < BMC_MAX; i++) {
322 bmc = &bmh->bmc[i];
323 if (!bmc->inuse)
324 break;
326 if (i == BMC_MAX) {
327 D(WriteF("All MemList slots in use!\n"));
328 return FALSE;
330 bmc->inuse = TRUE;
331 ml = &bmc->ml;
332 ml->ml_Node.ln_Type = resscan ? NT_KICKMEM : NT_MEMORY;
333 ml->ml_Node.ln_Pri = getNodePri(mem, flags);
334 if (name) {
335 ml->ml_Node.ln_Name = bmc->name;
336 if (strlen(name) >= BMC_NAME_SIZE)
337 memcpy(ml->ml_Node.ln_Name, name, BMC_NAME_SIZE - 1);
338 else
339 strcpy(ml->ml_Node.ln_Name, name);
341 ml->ml_NumEntries = 1;
342 ml->ml_ME[0].me_Addr = (APTR)mem;
343 ml->ml_ME[0].me_Length = size;
344 Enqueue(&bmh->mlist, &ml->ml_Node);
345 return TRUE;
348 static void remMemList(UBYTE *mem)
350 int i;
352 D(DWriteF("RemMemList %X8\n", mem));
353 for (i = 0; i < BMC_MAX; i++) {
354 struct BootMemChunk *bmc = &bmh->bmc[i];
355 if (bmc->inuse && bmc->ml.ml_ME[0].me_Addr == mem) {
356 bmc->inuse = FALSE;
357 Remove(&bmc->ml.ml_Node);
358 return;
361 D(DWriteF("MemList slot not found!\n"));
364 static struct Resident *scanResidents(UBYTE *mem, ULONG size, BOOL loadseg)
366 struct Resident **resptr = NULL;
367 struct Resident *firstres = NULL;
368 UBYTE *ptr = mem;
369 UBYTE *end = mem + size;
370 ULONG rescnt = 0;
371 ULONG i;
373 D(WriteF("ScanResident %X8 %N\n", mem, size));
374 for (i = 0; i < RES_MAX - 1; i++) {
375 if (bmh->res[i] == NULL) {
376 resptr = &bmh->res[i];
377 break;
380 if (!resptr) {
381 D(WriteF("All Resident slots in use!\n"));
382 return NULL;
384 while (ptr <= end - 26) {
385 struct Resident *r = (struct Resident*)ptr;
386 if (r->rt_MatchWord == RTC_MATCHWORD && r->rt_MatchTag == r) {
387 resptr[rescnt++] = r;
388 if (!firstres)
389 firstres = r;
390 if (loadseg) {
391 /* Set RTF_COLDSTART if no initialization flags set */
392 if (!(r->rt_Flags & (RTF_COLDSTART | RTF_SINGLETASK | RTF_AFTERDOS)))
393 r->rt_Flags |= RTF_COLDSTART;
394 if (r->rt_Pri < 10)
395 r->rt_Pri = 10;
396 break;
398 if ((IPTR)r->rt_EndSkip > (IPTR)ptr)
399 ptr = (UBYTE*)r->rt_EndSkip - sizeof(UWORD);
401 ptr += sizeof(UWORD);
403 D(WriteF("%N residents found, start address %X8\n", rescnt, resptr));
404 return firstres;
407 static void scanMemLists(void)
409 int i;
410 struct BootMemChunk *bmc;
412 D(WriteF("Scanning for residents..\n"));
413 bmc = (struct BootMemChunk*)bmh->mlist.lh_Head;
414 while (bmc->ml.ml_Node.ln_Succ) {
415 struct MemList *ml = &bmc->ml;
416 if (ml->ml_Node.ln_Type == NT_KICKMEM) {
417 ml->ml_Node.ln_Type = NT_MEMORY;
418 for (i = 0; i < ml->ml_NumEntries; i++) {
419 if (scanResidents(ml->ml_ME[i].me_Addr, ml->ml_ME[i].me_Length, FALSE)) {
420 // Can be MMU write protected
421 ml->ml_Node.ln_Type = NT_KICKMEM;
425 bmc = (struct BootMemChunk*)bmc->ml.ml_Node.ln_Succ;
429 static BOOL initDataPool(void)
431 UBYTE *start;
432 ULONG size;
433 ULONG flags;
434 ULONG *p;
435 int i;
437 size = 2 * PAGE_SIZE + ((sizeof(struct BootMemHeader) + PAGE_SIZE - 1) & ~PAGE_SIZE);
438 /* Always in Chip RAM */
439 flags = MEMF_CHIP | (SysBase->LibNode.lib_Version >= 36 ? MEMF_REVERSE : 0) | MEMF_CLEAR;
440 start = AllocPageAligned (&size, flags);
441 if (!start)
442 return FALSE;
443 D(DWriteF("BootMemHeader allocated at %X8\n", start));
444 /* Fill with identifier strings. */
445 p = (ULONG*)start;
446 for (i = 0; i < PAGE_SIZE / 4; i++)
447 p[i] = 0x41524f53;
448 p = (ULONG*)(start + size - PAGE_SIZE);
449 for (i = 0; i < PAGE_SIZE / 4; i++)
450 p[i] = 0x534f5241;
451 bmh = (struct BootMemHeader*)(start + PAGE_SIZE);
452 /* Initialize Memory List */
453 NEWLIST(&bmh->mlist);
454 /* Add our memory to list, highest priority */
455 addMemList(start, size, 0xffffffff, "pool", FALSE);
456 return TRUE;
459 /* Define these here for zlib so that we don't
460 * pull in stdc.library.
462 * We can't use AllocVec, since it's only
463 * been around since KS v36
465 void *malloc(int size)
467 ULONG *vec;
469 size += sizeof(ULONG);
471 vec = AllocMem(size, MEMF_ANY);
472 if (vec == NULL) {
473 WriteF("libz: Failed to allocate %N bytes of type %X8\n", size, MEMF_ANY);
474 return NULL;
477 vec[0] = (ULONG)size;
478 return &vec[1];
481 void free(void *ptr)
483 ULONG *vec = ptr - sizeof(ULONG);
484 FreeMem(vec, vec[0]);
487 int open(const char *name, int mode)
489 return (int)Open(name, MODE_OLDFILE);
492 int close(int fd)
494 Close((BPTR)fd);
495 return 0;
498 ssize_t read(int fd, void *buff, size_t len)
500 return Read((BPTR)fd, buff, (LONG)len);
503 off_t lseek(int fd, off_t offset, int whence)
505 LONG mode = SEEK_SET;
506 LONG err;
508 switch (whence) {
509 case SEEK_CUR: mode = OFFSET_CURRENT; break;
510 case SEEK_SET: mode = OFFSET_BEGINNING; break;
511 case SEEK_END: mode = OFFSET_END; break;
512 default: return -1;
515 err = Seek((BPTR)fd, (LONG)offset, mode);
516 if (err < 0)
517 return -1;
519 return Seek((BPTR)fd, 0, OFFSET_CURRENT);
522 static AROS_UFH4(LONG, aosRead,
523 AROS_UFHA(BPTR, file, D1),
524 AROS_UFHA(void *, buf, D2),
525 AROS_UFHA(LONG, size, D3),
526 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
528 AROS_USERFUNC_INIT
530 return Read(file, buf, (unsigned)size);
532 AROS_USERFUNC_EXIT
534 static AROS_UFH4(LONG, aosSeek,
535 AROS_UFHA(BPTR, file, D1),
536 AROS_UFHA(LONG, pos, D2),
537 AROS_UFHA(LONG, mode, D3),
538 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
540 AROS_USERFUNC_INIT
541 int whence;
542 LONG ret;
543 LONG oldpos;
545 switch (mode) {
546 case OFFSET_CURRENT : whence = SEEK_CUR; break;
547 case OFFSET_END : whence = SEEK_END; break;
548 case OFFSET_BEGINNING: whence = SEEK_SET; break;
549 default: return -1;
552 oldpos = (LONG)Seek(file, 0, SEEK_CUR);
554 ret = (LONG)Seek(file, (z_off_t)pos, whence);
555 if (ret < 0)
556 return -1;
558 return oldpos;
560 AROS_USERFUNC_EXIT
563 static APTR aosAllocMem(ULONG size, ULONG flags, const char *name, BOOL resscan, struct ExecBase *SysBase)
565 UBYTE *mem;
567 /* Clear bits 15-0, we're setting memory class explicitly */
568 flags &= ~0x7fff;
570 if (SysBase->LibNode.lib_Version >= 36) {
571 flags |= MEMF_LOCAL | MEMF_REVERSE;
572 } else {
573 flags |= MEMF_CHIP;
576 size += 2 * ALLOCATION_EXTRA;
577 mem = AllocMem(size, flags | MEMF_CLEAR);
578 if (mem == NULL) {
579 WriteF("AOS: Failed to allocate %N bytes of type %X8\n", size, flags);
580 meminfo();
581 return NULL;
583 addMemList(mem, size, flags, name, resscan);
584 return mem + ALLOCATION_EXTRA;
587 static AROS_UFH3(APTR, aosAlloc,
588 AROS_UFHA(ULONG, size, D0),
589 AROS_UFHA(ULONG, flags, D1),
590 AROS_UFHA(struct ExecBase *, SysBase, A6))
592 AROS_USERFUNC_INIT
594 return aosAllocMem(size, flags, NULL, FALSE, SysBase);
596 AROS_USERFUNC_EXIT
598 static AROS_UFH3(void, aosFree,
599 AROS_UFHA(APTR, addr, A1),
600 AROS_UFHA(ULONG, size, D0),
601 AROS_UFHA(struct ExecBase *, SysBase, A6))
603 AROS_USERFUNC_INIT
605 addr -= ALLOCATION_EXTRA;
606 size += 2 * ALLOCATION_EXTRA;
607 remMemList(addr);
609 AROS_USERFUNC_EXIT
612 /* Backcalls for LoadSegment
613 * using the gzip backend.
615 static AROS_UFH4(LONG, elfRead,
616 AROS_UFHA(BPTR, file, D1),
617 AROS_UFHA(void *, buf, D2),
618 AROS_UFHA(LONG, size, D3),
619 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
621 AROS_USERFUNC_INIT
623 return gzread((gzFile)file, buf, (unsigned)size);
625 AROS_USERFUNC_EXIT
627 static AROS_UFH4(LONG, elfSeek,
628 AROS_UFHA(BPTR, file, D1),
629 AROS_UFHA(LONG, pos, D2),
630 AROS_UFHA(LONG, mode, D3),
631 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
633 AROS_USERFUNC_INIT
634 int whence;
635 LONG ret;
636 LONG oldpos;
638 switch (mode) {
639 case OFFSET_CURRENT : whence = SEEK_CUR; break;
640 case OFFSET_END : whence = SEEK_END; break;
641 case OFFSET_BEGINNING: whence = SEEK_SET; break;
642 default: return -1;
645 oldpos = (LONG)gzseek((gzFile)file, 0, SEEK_CUR);
647 ret = (LONG)gzseek((gzFile)file, (z_off_t)pos, whence);
648 if (ret < 0)
649 return -1;
651 return oldpos;
653 AROS_USERFUNC_EXIT
656 static APTR specialAlloc(ULONG size, ULONG flags, const char *name, BOOL resscan, struct ExecBase *SysBase)
658 APTR mem;
660 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
661 /* Since we don't know if we need to wrap the memory
662 * with the KickMem wrapper until after allocation,
663 * we always adjust the size as if we have to.
665 size += 2 * ALLOCATION_EXTRA;
667 if (flags & MEMF_KICK) {
668 D(DWriteF("MEMF_KICK %N\n", size));
669 if (forceCHIP) {
670 flags |= MEMF_CHIP;
671 } else {
672 /* Prefer MEMF_KICK | MEMF_FAST if available */
673 flags |= MEMF_FAST;
677 /* Hmm. MEMF_LOCAL is only available on v36 and later.
678 * Use MEMF_CHIP if we have to.
680 if (flags & MEMF_LOCAL) {
681 D(DWriteF("MEMF_LOCAL %N\n", size));
682 if (forceFAST) {
683 flags &= ~MEMF_LOCAL;
684 } else if (SysBase->LibNode.lib_Version < 36 || forceCHIP) {
685 flags &= ~MEMF_LOCAL;
686 flags |= MEMF_CHIP;
690 /* MEMF_31BIT is not available on AOS */
691 if ((flags & MEMF_31BIT)) {
692 flags &= ~MEMF_31BIT;
695 /* If ROM allocation, always allocate from top of memory if possible */
696 if ((flags & MEMF_PUBLIC) && SysBase->LibNode.lib_Version >= 36) {
697 flags |= MEMF_REVERSE;
700 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
701 mem = AllocPageAligned(&size, flags | MEMF_CLEAR);
702 if (mem == NULL) {
703 if ((flags & (MEMF_KICK | MEMF_FAST)) == (MEMF_KICK | MEMF_FAST)) {
704 /* Couldn't allocate MEMF_KICK | MEMF_FAST, fall back to any memory */
705 mem = AllocPageAligned(&size, (flags & MEMF_REVERSE) | MEMF_CLEAR);
707 if (mem == NULL) {
708 D(DWriteF("ELF: Failed to allocate %N bytes of type %X8\n", size, flags));
709 meminfo();
710 return NULL;
713 D(DWriteF("ELF: Got memory at %X8, size %N\n", (IPTR)mem, size));
715 addMemList(mem, size, flags, name, resscan);
716 return mem + ALLOCATION_EXTRA;
719 static AROS_UFH3(APTR, elfAlloc,
720 AROS_UFHA(ULONG, size, D0),
721 AROS_UFHA(ULONG, flags, D1),
722 AROS_UFHA(struct ExecBase *, SysBase, A6))
724 AROS_USERFUNC_INIT
726 return specialAlloc(size, flags, NULL, TRUE, SysBase);
728 AROS_USERFUNC_EXIT
731 static AROS_UFH3(void, elfFree,
732 AROS_UFHA(APTR, addr, A1),
733 AROS_UFHA(ULONG, size, D0),
734 AROS_UFHA(struct ExecBase *, SysBase, A6))
736 AROS_USERFUNC_INIT
738 /* If not page aligned, and the offset from the page boundary
739 * is the sizeof(MemChunk) + sizeof(MemList) then we can assume
740 * that it was a KickTag protected allocation
742 D(DWriteF("ELF: Free memory at %X8, size %N\n", (IPTR)addr, size));
743 addr -= ALLOCATION_EXTRA;
744 size += 2 * ALLOCATION_EXTRA;
745 remMemList(addr);
746 FreePageAligned(addr, size);
748 AROS_USERFUNC_EXIT
752 * This routine is called from within libloadseg.a's ELF loader.
753 * In dos.library it's responsible for collecting debug information from the loaded file.
754 * Here it does nothing (FIXME ???)
756 void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
760 void register_hunk(BPTR file, BPTR hunks, APTR header, struct DosLibrary *DOSBase)
765 static BPTR ROMLoad(BSTR bfilename)
767 gzFile gzf;
768 UBYTE *filename;
769 BPTR rom = BNULL;
770 SIPTR funcarray[] = {
771 (SIPTR)elfRead,
772 (SIPTR)elfAlloc,
773 (SIPTR)elfFree,
774 (SIPTR)elfSeek,
776 filename = ConvertBSTR(bfilename);
777 if (!filename)
778 return BNULL;
780 WriteF("Loading '%S' into RAM...\n", bfilename);
781 if ((gzf = gzopen(filename, "rb"))) {
782 gzbuffer(gzf, 65536);
784 rom = LoadSegment((BPTR)gzf, BNULL, funcarray, NULL);
785 if (rom == BNULL) {
786 WriteF("'%S': Can't parse, error %N\n", bfilename, IoErr());
789 gzclose_r(gzf);
790 } else {
791 WriteF("'%S': Can't open\n", bfilename);
793 FreeString(filename);
794 return rom;
797 /* Patch "picasso96/<driver>.chip" -> "<driver>.chip" so that OpenLibrary() finds it */
798 static void RTGPatch(struct Resident *r, BPTR seg)
800 BOOL patched = FALSE;
801 WORD len = strlen(r->rt_Name);
802 const UBYTE *name = r->rt_Name + len - 5;
803 if (len > 5 && (!stricmp(name, ".card") || !stricmp(name, ".chip"))) {
804 BPTR seglist = seg;
805 while (seglist) {
806 ULONG *ptr = BADDR(seglist);
807 LONG len = ptr[-1] - sizeof(BPTR);
808 UBYTE *p = (UBYTE*)(ptr + 1);
809 while (len > 0) {
810 if (len > 16 && !strnicmp(p, "libs:picasso96/", 15)) {
811 memmove(p, p + 15, strlen(p + 15) + 1);
812 patched = TRUE;
813 } else if (len > 10 && !strnicmp(p, "picasso96/", 10)) {
814 memmove(p, p + 10, strlen(p + 10) + 1);
815 patched = TRUE;
817 len--;
818 p++;
820 seglist = *((BPTR*)BADDR(seglist));
823 if (patched)
824 WriteF("Library path patched\n");
827 static void LoadResidents(BPTR *namearray)
829 UBYTE i;
830 SIPTR funcarray[] = {
831 (SIPTR)aosRead,
832 (SIPTR)aosAlloc,
833 (SIPTR)aosFree,
834 (SIPTR)aosSeek,
837 for (i = 0; namearray[i]; i++) {
838 LONG stack;
839 BPTR handle;
840 BPTR seglist = BNULL;
841 BPTR bname;
842 UBYTE *name;
844 bname = namearray[i];
845 name = ConvertBSTR(bname);
846 if (name) {
847 handle = Open(name, MODE_OLDFILE);
848 if (handle) {
849 seglist = LoadSegment(handle, BNULL, funcarray, &stack);
850 Close(handle);
852 if (seglist) {
853 struct Resident *res = NULL;
854 BPTR seg;
855 WriteF("Loaded '%S'\n", bname);
856 for (seg = seglist; seg != BNULL; seg = *((BPTR*)BADDR(seg))) {
857 ULONG *ptr = BADDR(seg);
858 ULONG len = ptr[-1];
859 res = scanResidents((UBYTE*)ptr, len, TRUE);
860 if (res)
861 break;
864 if (res)
865 RTGPatch(res, seg);
866 } else {
867 WriteF("Failed to load '%S', error %N\n", bname, IoErr());
869 FreeString(name);
874 #if DEBUG
876 #define SERDATR 0x18
877 #define SERDAT 0x30
878 #define INTREQ 0x9c
879 #define INTENA 0x9a
880 #define SERDATR_TBE (1 << 13) /* Tx Buffer Empty */
881 #define SERDAT_STP8 (1 << 8)
882 #define SERDAT_DB8(x) ((x) & 0xff)
883 #define SERPER_BASE_PAL 3546895
884 #define SERPER 0x32
885 #define SERPER_BAUD(base, x) ((((base + (x)/2))/(x)-1) & 0x7fff) /* Baud rate */
886 #define INTF_TBE 0x0001
888 static inline void reg_w(ULONG reg, UWORD val)
890 volatile UWORD *r = (void *)(0xdff000 + reg);
892 *r = val;
894 static inline UWORD reg_r(ULONG reg)
896 volatile UWORD *r = (void *)(0xdff000 + reg);
898 return *r;
900 static void DebugInit(void)
902 /* Set DTR, RTS, etc */
903 volatile UBYTE *ciab_pra = (APTR)0xBFD000;
904 volatile UBYTE *ciab_ddra = (APTR)0xBFD200;
905 if (!debug_enabled)
906 return;
907 *ciab_ddra = 0xc0; /* Only DTR and RTS are driven as outputs */
908 *ciab_pra = 0; /* Turn on DTR and RTS */
910 /* Set the debug UART to 115200 */
911 reg_w(SERPER, SERPER_BAUD(SERPER_BASE_PAL, 115200));
912 /* Disable serial transmit interrupt */
913 reg_w(INTENA, INTF_TBE);
915 static void DebugPutChar(register int chr)
917 if (!debug_enabled)
918 return;
919 if (chr == '\n')
920 DebugPutChar('\r');
921 while ((reg_r(SERDATR) & SERDATR_TBE) == 0);
922 reg_w(INTREQ, INTF_TBE);
923 /* Output a char to the debug UART */
924 reg_w(SERDAT, SERDAT_STP8 | SERDAT_DB8(chr));
926 static void DebugPutStr(register const char *buff)
928 if (!debug_enabled)
929 return;
930 for (; *buff != 0; buff++)
931 DebugPutChar(*buff);
933 #if 0
934 static void DebugPutDec(const char *what, ULONG val)
936 int i, num;
937 if (!debug_enabled)
938 return;
939 DebugPutStr(what);
940 DebugPutStr(": ");
941 if (val == 0) {
942 DebugPutChar('0');
943 DebugPutChar('\n');
944 return;
947 for (i = 1000000000; i > 0; i /= 10) {
948 if (val == 0) {
949 DebugPutChar('0');
950 continue;
953 num = val / i;
954 if (num == 0)
955 continue;
957 DebugPutChar("0123456789"[num]);
958 val -= num * i;
960 DebugPutChar('\n');
962 static void DebugPutHexVal(ULONG val)
964 int i;
965 if (!debug_enabled)
966 return;
967 for (i = 0; i < 8; i ++) {
968 DebugPutChar("0123456789abcdef"[(val >> (28 - (i * 4))) & 0xf]);
970 DebugPutChar(' ');
972 static void DebugPutHex(const char *what, ULONG val)
974 int i;
975 if (!debug_enabled)
976 return;
977 DebugPutStr(what);
978 DebugPutStr(": ");
979 for (i = 0; i < 8; i ++) {
980 DebugPutChar("0123456789abcdef"[(val >> (28 - (i * 4))) & 0xf]);
982 DebugPutChar('\n');
984 #endif
985 #endif
987 /* Theory of operation:
989 - create fake sysbase in chip memory (We can't use original because it is not binary compatible with AROS one)
990 - set correct checksum and point ColdCapture to our routine (also in low chip)
991 - reset the system (autoconfig devices disappear, including most expansion RAM and ROM overlay disables chip RAM)
992 - original ROM code runs, disables ROM overlay and checks KS checksum and jumps to our ColdCapture routine
993 - above step is needed because in worst case ALL RAM disappear at reset and there
994 are also accelerators that reset the CPU completely when reset instruction is executed.
995 - now we have control again, autoconfig devices are still unconfigured but at least we have chip ram.
996 - extra step if AROS build final SysBase in autoconfig RAM:
997 - AOS detects invalid SysBase (not accessible)
998 - builds temporary SysBase in Chip RAM
999 - autoconfig
1000 - checks if original SysBase is now valid. If it is, checks ColdCapture and jumps to it.
1001 - we have control now but autoconfig devices have been configured and we don't want it.
1002 - we store original SysBase, set fake sysbase back, reset system again
1003 - now we finally have control without autoconfig
1004 - jump to AROS ROM code entry point which detects romloader mode and automatically reserves RAM used by "ROM" code
1005 - AROS ROM creates new proper execbase and copies ColdCapture and other reset proof vectors from original SysBase
1006 - normal boot starts
1010 static UWORD GetSysBaseChkSum(struct ExecBase *sysbase)
1012 UWORD sum = 0;
1013 UWORD *p = (UWORD*)&sysbase->SoftVer;
1014 while (p <= &sysbase->ChkSum)
1015 sum += *p++;
1016 return sum;
1019 /* reset VBR and switch off MMU */
1020 static void setcpu(void)
1022 asm(
1023 ".chip 68040\n"
1024 "move.l 4,%a0\n"
1025 "move.w 296(%a0),%d1\n"
1026 "moveq #0,%d0\n"
1027 "btst #0,%d1\n"
1028 "beq.s cpudone\n"
1029 /* clear VBR */
1030 "movec %d0,%vbr\n"
1031 "btst #1,%d1\n"
1032 "beq.s cpudone\n"
1033 /* disable caches */
1034 "movec %d0,%cacr\n"
1035 "btst #3,%d1\n"
1036 "beq.s not040\n"
1037 /* 68040/060 MMU */
1038 "movec %d0,%tc\n"
1039 "movec %d0,%dtt0\n"
1040 "movec %d0,%dtt1\n"
1041 "movec %d0,%itt0\n"
1042 "movec %d0,%itt1\n"
1043 "cpusha %bc\n"
1044 "bra.s cpudone\n"
1045 "not040: btst #2,%d1\n"
1046 "beq.s cpudone\n"
1047 /* 68030 MMU */
1048 "lea zero(%pc),%a0\n"
1049 ".long 0xf0104000\n"
1050 ".long 0xf0100c00\n"
1051 ".long 0xf0100800\n"
1052 "bra.s cpudone\n"
1053 "zero: .long 0,0\n"
1054 "cpudone:\n"
1058 /* This is needed because KS clears ColdCapture before calling it
1059 * causing checksum mismatch in AROS exec check
1061 void coldcapturecode(void)
1063 asm(
1064 ".chip 68010\n"
1065 ".long end - start\n"
1066 "start:\n"
1067 "bra.s 0f\n"
1068 "nop\n" /* Align to start + 4 */
1069 ".long 0x46414b45\n" /* AROS_MAKE_ID('F','A','K','E') */
1070 ".long 0\n" // 0 BootStruct
1071 ".long 0\n" // 4 FakeBase
1072 ".long 0\n" // 8 Stored NMI
1073 ".long 0\n" // 12 ROM EntryPoint
1074 "0:\n"
1075 "move.w #0x440,0xdff180\n"
1076 "lea vbrexp(%pc),%a0\n"
1077 "move.l %a0,0x10.w\n" // illegal opcode exception
1078 "move.l #0x400,%sp\n"
1079 "moveq #0,%d0\n"
1080 "movec %d0,%vbr\n" // reset VBR
1081 "vbrexp:\n" // we get here if 68000 (no VBR)
1082 "lea start+8(%pc),%a4\n"
1083 "move.l 4.w,%d0\n"
1084 "clr.l 4.w\n"
1085 "btst #0,%d0\n"
1086 "bne.s basenok\n"
1087 "move.l %d0,%a0\n"
1088 // We need to check if autoconfig has already been done by
1089 // AOS expansion.library. It happens if SysBase is in autoconfig RAM
1090 // We need to get back to non-autoconfig state.
1091 "tst.l 10(%a0)\n" // ln_Name == NULL?
1092 "bne.s baseok\n"
1093 // It was AOS temp SysBase. Switch back to FakeBase.
1094 // Interestingly ChkBase contains original SysBase pointer in this situation!
1095 "move.l (%a4),%a1\n"
1096 "move.l 38(%a0),8(%a1)\n" // Original SysBase -> BootStruct->RealBase2
1097 "basenok:\n"
1098 "bsr.s fixbase\n"
1099 // and reset and try again.
1100 "lea 0x01000000,%a0\n"
1101 "sub.l %a0@(-0x14),%a0\n"
1102 "move.l %a0@(4),%a0\n"
1103 "subq.l #2,%a0\n"
1104 /* Force ULONG alignment of 'reset' */
1105 "bra 0f\n"
1106 ".balign 4,0xff\n"
1107 "0:\n"
1108 "reset\n"
1109 "jmp (%a0)\n"
1111 "baseok:\n"
1112 "not.l %d0\n"
1113 "cmp.l 38(%a0),%d0\n" // ChkBase
1114 "bne.s basenok\n"
1116 "move.l (%a4),%a1\n"
1117 "move.l %a0,4(%a1)\n" // Original SysBase -> BootStruct->RealBase
1119 // set early exceptions
1120 "move.w #8,%a1\n"
1121 "lea exception(%pc),%a0\n"
1122 "moveq #64-2-1,%d0\n"
1123 "1:\n"
1124 "move.l %a0,(%a1)+\n"
1125 "dbf %d0,1b\n"
1127 "bsr.s fixbase\n"
1129 "move.l 12(%a4),%a0\n" // Entrypoint
1130 "addq.l #2,%a0\n"
1131 "moveq #2,%d0\n"
1132 "cmp.w #0x4ef9,(%a0)\n"
1133 "beq.s .skip\n"
1134 // skip elf loader injected header
1135 "moveq #4,%d0\n"
1136 "move.l (%a0),%a0\n"
1137 ".skip:\n"
1138 "move.l 0(%a0,%d0.w),%a0\n"
1139 "jmp 4(%a0)\n"
1141 // Setup our temporary fake SysBase
1142 "fixbase:\n"
1143 "move.l 8(%a4),0x7c.w\n" // restore NMI
1144 "move.l 4(%a4),%a0\n" // FakeBase
1145 "move.l %a0,4.w\n"
1146 "move.w #50,34(%a0)\n" // SoftVer
1147 "lea start(%pc),%a1\n"
1148 "move.l %a1,42(%a0)\n" // ColdCapture
1149 "move.l %a0,%d0\n"
1150 "not.l %d0\n"
1151 "move.l %d0,38(%a0)\n" // ChkBase
1152 "moveq #0,%d1\n"
1153 "lea 34(%a0),%a0\n"
1154 "moveq #24-1,%d0\n"
1155 "chk1: add.w (%a0)+,%d1\n"
1156 "dbf %d0,chk1\n"
1157 "not.w %d1\n"
1158 "move.w %d1,(%a0)\n" // ChkSum
1159 "rts\n"
1161 "exception:\n"
1162 "move.w #0xff0,0xdff180\n"
1163 "move.w #0x000,0xdff180\n"
1164 "bra.s exception\n"
1165 "end:\n"
1169 /* Official reboot code from HRM
1170 * All CPUs have at least 1 word prefetch,
1171 * jmp (a0) has been prefetched even if
1172 * reset disables all memory
1174 static void doreboot(void)
1176 asm volatile (
1177 "lea 0x01000000,%a0\n"
1178 "sub.l %a0@(-0x14),%a0\n"
1179 "move.l %a0@(4),%a0\n"
1180 "subq.l #2,%a0\n"
1181 /* Force ULONG alignment of 'reset' */
1182 "bra 0f\n"
1183 ".balign 4,0xff\n"
1184 "0:\n"
1185 "reset\n"
1186 "jmp (%a0)\n"
1190 struct BootStruct *bs;
1192 static void supercode(void)
1194 ULONG *traps = 0;
1196 #if DEBUG
1197 DebugPutStr("Entered Supervisor mode.\n");
1198 #endif
1200 if ((SysBase->AttnFlags & 0xff) != 0)
1201 setcpu();
1202 #if DEBUG
1203 DebugPutStr("CPU setup done.\n");
1204 #endif
1206 traps[0] = 0;
1207 traps[1] = (ULONG)bs->FakeBase;
1209 // TODO: add custom cacheclear, can't call CacheClearU() because it may not work
1210 // anymore and KS 1.x does not even have it
1211 doreboot();
1214 static void BootROM(struct BootStruct *BootS)
1216 APTR GfxBase;
1217 struct ExecBase *sysbase = BootS->FakeBase;
1218 ULONG *colddata;
1219 ULONG *traps = 0;
1221 #if DEBUG
1222 WriteF("BootStruct %X8\n", BootS);
1223 WriteF("FakeBase %X8\n", sysbase);
1224 WriteF("Bootcode %X8\n", BootS->bootcode);
1225 #endif
1227 strcpy(bmh->fakename, "fakebase");
1228 sysbase->LibNode.lib_Node.ln_Name = bmh->fakename;
1229 sysbase->ColdCapture = BootS->bootcode;
1230 sysbase->MaxLocMem = 512 * 1024;
1231 sysbase->ChkBase =~(IPTR)sysbase;
1232 sysbase->ChkSum = GetSysBaseChkSum(sysbase) ^ 0xffff;
1233 memcpy(BootS->bootcode, coldcapturecode + 4, ((ULONG*)coldcapturecode)[0]);
1234 colddata = (ULONG*)(BootS->bootcode + 8);
1235 colddata[0] = (ULONG)BootS;
1236 colddata[1] = (ULONG)sysbase;
1237 colddata[2] = traps[31]; // NMI
1238 colddata[3] = (ULONG)bmh->entrypoint;
1240 bs = BootS;
1242 Delay(50);
1244 if ((GfxBase = OpenLibrary("graphics.library", 0))) {
1245 LoadView(NULL);
1246 WaitTOF();
1247 WaitTOF();
1248 CloseLibrary(GfxBase);
1251 /* We're off in the weeds now. */
1252 Disable();
1254 Supervisor((ULONG_FUNC)supercode);
1257 #if DEBUG
1258 static void DumpKickMems(ULONG num, struct MemList *ml)
1260 if (num == 0)
1261 DWriteF("Original KickMemList:\n");
1262 else
1263 DWriteF("AROS KickMemList:\n");
1264 /* List is single-linked but last link gets cleared later, so test ln_Succ too */
1265 while (ml && ml->ml_Node.ln_Succ) {
1266 WORD i;
1267 DWriteF("%X8:%N\n", ml, ml->ml_NumEntries);
1268 for (i = 0; i < ml->ml_NumEntries; i++) {
1269 DWriteF(" %N: %X8, %N\n", i, ml->ml_ME[i].me_Un.meu_Addr, ml->ml_ME[i].me_Length);
1271 ml = (struct MemList*)ml->ml_Node.ln_Succ;
1273 DWriteF("End of List\n");
1276 static void DumpKickTags(ULONG num, struct Resident **list)
1278 if (num == 0)
1279 DWriteF("Original KickTagList:\n");
1280 else
1281 DWriteF("AROS KickTagList:\n");
1282 while (*list) {
1283 BSTR bname;
1284 if ((ULONG)list & RESLIST_NEXT) {
1285 DWriteF("Redirected to %X8\n", (ULONG)list & ~RESLIST_NEXT);
1286 list = (struct Resident**)((ULONG)list & ~RESLIST_NEXT);
1287 continue;
1289 bname = ConvertCSTR((*list)->rt_IdString);
1290 DWriteF("%X8: %X8 %S\n", list, *list, bname);
1291 FreeBSTR(bname);
1292 list++;
1294 DWriteF("End of List\n");
1296 #endif
1298 #define HC_FORCEFAST 1
1299 struct HardwareConfig
1301 UWORD manufacturer;
1302 UBYTE product;
1303 const UBYTE *name;
1304 UBYTE flags;
1307 static const struct HardwareConfig hc[] =
1309 { 8512, 17, "Blizzard A1200 Accelerator", HC_FORCEFAST }, // Blizzard 1230 IV, 1240 or 1260.
1310 { 0 }
1313 static void DetectHardware(void)
1315 struct ConfigDev *cd = NULL;
1316 int i;
1318 ExpansionBase = (APTR)OpenLibrary("expansion.library", 0);
1319 if (!ExpansionBase)
1320 return;
1321 while((cd = FindConfigDev(cd, -1, -1))) {
1322 for (i = 0; hc[i].manufacturer; i++) {
1323 if (cd->cd_Rom.er_Manufacturer == hc[i].manufacturer && cd->cd_Rom.er_Product == hc[i].product) {
1324 BSTR bname;
1325 bname = ConvertCSTR(hc[i].name);
1326 WriteF("%S: ", bname);
1327 if (hc[i].flags & HC_FORCEFAST) {
1328 forceFAST = TRUE;
1329 WriteF("ForceFast enabled");
1331 WriteF("\n");
1332 FreeBSTR(bname);
1336 CloseLibrary(ExpansionBase);
1339 static struct BootStruct *CreateBootStruct(BPTR ROMSeg, UBYTE *cmdline)
1341 struct TagItem *tags;
1342 struct BootStruct *boots;
1344 boots = &bmh->boots;
1345 boots->mlist = &bmh->mlist;
1346 boots->reslist = bmh->res;
1347 boots->FakeBase = &bmh->FakeBase;
1348 boots->bootcode = &bmh->bootcode;
1349 bmh->entrypoint = BADDR(ROMSeg) + sizeof(ULONG);
1350 tags = bmh->ktags;
1351 /* cmdline is a BCPL string! */
1352 if (cmdline && cmdline[0])
1353 CopyMem(cmdline + 1, bmh->kcmd, cmdline[0]);
1354 else
1355 strcpy(bmh->kcmd, DEFAULT_KERNEL_CMDLINE);
1356 tags[0].ti_Tag = KRN_CmdLine;
1357 tags[0].ti_Data = (IPTR)bmh->kcmd;
1358 tags[1].ti_Tag = TAG_DONE;
1360 boots->magic = ABS_BOOT_MAGIC;
1361 boots->kerneltags = tags;
1362 if (forceFAST) {
1363 UBYTE *addr = specialAlloc(SS_STACK_SIZE + MAGIC_FAST_SIZE + 1, MEMF_FAST | MEMF_REVERSE, "magicfast", FALSE, SysBase); /* +1 = guaranteed extra page at the end */
1364 if (addr) {
1365 addr = (UBYTE*)(((ULONG)(addr + PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1));
1366 boots->ss_address = addr;
1367 boots->ss_size = SS_STACK_SIZE;
1368 /* magic fast mem pool for early allocations that normally can't be allocated from fast memory */
1369 boots->magicfastmem = boots->ss_address + SS_STACK_SIZE;
1370 boots->magicfastmemsize = MAGIC_FAST_SIZE;
1373 return boots;
1376 __startup static AROS_PROCH(startup, argstr, argsize, sysBase)
1378 AROS_PROCFUNC_INIT
1380 SysBase = sysBase;
1381 APTR lowmem;
1383 /* Allocate some low MEMF_CHIP ram, as a buffer
1384 * against overlapping allocations with the initial
1385 * stack.
1387 lowmem = AllocMem(PAGE_SIZE, MEMF_CHIP);
1389 DOSBase = (APTR)OpenLibrary("dos.library", 0);
1390 if (DOSBase != NULL) {
1391 BPTR ROMSegList;
1392 BSTR name = AROS_CONST_BSTR("aros.elf");
1393 enum { ARG_ROM = 16, ARG_CMD = 17, ARG_FORCECHIP = 18, ARG_FORCEFAST = 19, ARG_DEBUG = 20, ARG_FORCEAROS = 21, ARG_MODULES = 0 };
1394 /* It would be nice to use the '/M' switch, but that
1395 * is not supported under the AOS BCPL RdArgs routine.
1397 * So only 16 modules are supported
1399 BSTR format = AROS_CONST_BSTR(",,,,,,,,,,,,,,,,ROM/K,CMD/K,FORCECHIP/S,FORCEFAST/S,DEBUG/S,FORCEAROS/S");
1400 /* Make sure the args are in .bss, not stack */
1401 static ULONG args[16 + 6 + 256] __attribute__((aligned(4))) = { };
1403 args[0] = name;
1405 RdArgs(format, MKBADDR(args), sizeof(args)/sizeof(args[0]));
1406 #if DEBUG > 1
1407 DWriteF("ROM : %S\n", args[ARG_ROM]);
1408 DWriteF("CMD : %S\n", args[ARG_CMD]);
1409 DWriteF("FORCECHIP: %N\n", args[ARG_FORCECHIP]);
1410 DWriteF("FORCEFAST: %N\n", args[ARG_FORCEFAST]);
1411 DWriteF("MOD 0 : %S\n", args[0]);
1412 DWriteF(" 1 : %S\n", args[1]);
1413 DWriteF(" 2 : %S\n", args[2]);
1414 DWriteF(" 3 : %S\n", args[3]);
1415 #endif
1417 forceAROS = args[ARG_FORCEAROS] ? TRUE : FALSE;
1418 forceCHIP = args[ARG_FORCECHIP] ? TRUE : FALSE;
1419 forceFAST = args[ARG_FORCEFAST] ? TRUE : FALSE;
1420 debug_enabled = args[ARG_DEBUG] ? TRUE : FALSE;
1422 /* See if we're already running on AROS.
1424 if (OpenResource("kernel.resource") != NULL) {
1425 if (!forceAROS) {
1426 CloseLibrary(DOSBase);
1427 FreeMem(lowmem, PAGE_SIZE);
1428 return RETURN_OK;
1430 } else {
1431 forceAROS = FALSE;
1434 WriteF("AROSBootstrap " ADATE "\n");
1435 if (forceAROS)
1436 WriteF("Forcing load of AROS on existing AROS\n");
1438 /* Blizzard A1200 accelerator boards have strange MAP ROM
1439 * feature, even when it is disabled, ROM is copied to
1440 * last 512K of RAM, so we have to make sure all our
1441 * allocations ignore this region.
1442 * Blizzard Fast RAM memory type is plain MEMF_FAST.
1444 if (SysBase->LibNode.lib_Version >= 37 && !AvailMem(MEMF_KICK | MEMF_FAST)) {
1445 if (AvailMem(MEMF_FAST)) {
1446 WriteF("Reserving non-MEMF_KICK Fast RAM\n");
1447 int i;
1448 /* Allocate in PAGE_SIZE byte chunks, it is smallest allocated size */
1449 for (i = 0; i < 524288 / PAGE_SIZE; i++)
1450 AllocMem(PAGE_SIZE, MEMF_FAST | MEMF_REVERSE);
1454 meminfo();
1455 DetectHardware();
1456 initDataPool();
1458 #if DEBUG
1459 DebugInit();
1460 #endif
1462 if (!IoErr()) {
1463 /* Load ROM image */
1464 if (args[ARG_ROM] == BNULL)
1465 args[ARG_ROM] = name;
1467 ROMSegList = ROMLoad(args[ARG_ROM]);
1468 if (ROMSegList != BNULL) {
1469 struct BootStruct *BootS;
1470 WriteF("Successfully loaded ROM\n");
1471 ROM_Loaded = TRUE;
1473 scanMemLists();
1474 LoadResidents(&args[ARG_MODULES]);
1475 BootS = CreateBootStruct(ROMSegList, BADDR(args[ARG_CMD]));
1477 #if DEBUG
1478 WriteF("Debug info:\n");
1479 DumpKickTags(0, SysBase->KickTagPtr);
1480 DumpKickTags(1, BootS->reslist);
1481 DumpKickMems(0, SysBase->KickMemPtr);
1482 DumpKickMems(1, (struct MemList*)bmh->mlist.lh_Head);
1483 #endif
1484 WriteF("Booting...\n");
1486 BootROM(BootS);
1488 UnLoadSeg(ROMSegList);
1489 } else {
1490 WriteF("Can't load ROM ELF file %S\n", args[ARG_ROM]);
1492 } else {
1493 WriteF("Can't parse arguments, error %N\n", IoErr());
1496 CloseLibrary((APTR)DOSBase);
1499 FreeMem(lowmem, PAGE_SIZE);
1501 return IoErr();
1503 AROS_PROCFUNC_EXIT
1506 /* Provide dummy implementation of strerror for gzip code */
1507 char *strerror(int errnum)
1509 return "Error";