get the cache sizes in bytes
[AROS.git] / arch / m68k-amiga / c / AROSBootstrap.c
blob18a72e2d48cc5e4f932a0fcdb0c8cd5c64da831f
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) + sizeof(struct MemList))
31 #define ALLOCPADDING (sizeof(struct MemChunk) + 2 * sizeof(BPTR))
33 #define SS_STACK_SIZE 0x2000
34 #define MAGIC_FAST_SIZE 65536
35 /* This must match with start.c! */
36 #define ABS_BOOT_MAGIC 0x4d363802
37 struct BootStruct
39 ULONG magic;
40 struct TagItem *kerneltags;
41 APTR ss_address;
42 LONG ss_size;
43 APTR magicfastmem;
44 LONG magicfastmemsize;
47 #include <stddef.h> /* offsetof */
48 #include <string.h> /* memcpy, memset */
49 #include <zlib.h>
51 #if defined(DEBUG) && DEBUG > 1
52 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode mungwall"
53 #else
54 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode"
55 #endif
57 #define PROTO_KERNEL_H /* Don't pick up AROS kernel hooks */
59 #if DEBUG
60 #define AROS_DEBUG_H
61 #include <stdio.h>
62 #include <string.h>
63 static inline void bug(const char *fmt, ...)
65 static char buff[256];
66 va_list args;
68 va_start(args, fmt);
69 vsnprintf(buff, sizeof(buff), fmt, args);
70 va_end(args);
72 Write(Output(), buff, strlen(buff));
74 #define D(x) x
75 #else
76 #define D(x)
77 #endif
79 #include <loadseg.h>
81 struct ExecBase *SysBase;
82 struct DosLibrary *DOSBase;
83 struct Library *ExpansionBase;
85 static BOOL ROM_Loaded = FALSE;
86 static BOOL forceAROS = FALSE;
87 static BOOL forceCHIP = FALSE;
88 static BOOL forceFAST = FALSE;
89 static BOOL debug_enabled = FALSE;
90 static struct List mlist;
92 /* KS 1.3 (and earlier) don't have a dos.library with
93 * niceties such as VFPrintf nor ReadArgs.
95 * We need to use the BCPL routines to be able
96 * to do these types of operations.
98 #define BCPL_WriteS 73
99 #define BCPL_WriteF 74
100 #define BCPL_RdArgs 78
102 #undef Printf
103 #define Printf __Printf_NOT_AVAILABLE_UNDER_KS1_3
104 #undef ReadArgs
105 #define ReadArgs __ReadArgs_NOT_AVAILABLE_UNDER_KS1_3
107 /* BCPL can trash D5-D7 and A3, evidently.
109 static void bcplWrapper(void)
111 asm volatile (
112 "movem.l %d5-%d7/%a3,%sp@-\n"
113 "jsr (%a5)\n"
114 "movem.l %sp@+,%d5-%d7/%a3\n"
118 static ULONG doBCPL(int index, ULONG d1, ULONG d2, ULONG d3, ULONG d4, const IPTR *arg, int args)
120 struct Process *pr = (APTR)FindTask(NULL);
121 APTR func;
122 ULONG *gv = pr->pr_GlobVec;
123 ULONG ret;
124 ULONG *BCPL_frame = AllocMem(1500, MEMF_ANY);
125 if (BCPL_frame == NULL)
126 return 0;
128 func = (APTR)gv[index];
130 if (args != 0)
131 CopyMem(arg, &BCPL_frame[3 + 4], args * sizeof(ULONG));
133 ret = AROS_UFC11(ULONG, bcplWrapper,
134 AROS_UFCA(ULONG, 0, D0), /* BCPL frame usage (args-3)*/
135 AROS_UFCA(ULONG, d1, D1),
136 AROS_UFCA(ULONG, d2, D2),
137 AROS_UFCA(ULONG, d3, D3),
138 AROS_UFCA(ULONG, d4, D4),
139 AROS_UFCA(ULONG, 0, A0), /* System memory base */
140 AROS_UFCA(ULONG *, &BCPL_frame[3], A1),
141 AROS_UFCA(APTR, gv, A2),
142 AROS_UFCA(APTR, func, A4),
143 AROS_UFCA(APTR, DOSBase->dl_A5, A5),
144 AROS_UFCA(APTR, DOSBase->dl_A6, A6));
146 FreeMem(BCPL_frame, 1500);
148 return ret;
151 #if DEBUG
152 static BSTR ConvertCSTR(const UBYTE *name)
154 UBYTE *bname = AllocMem(256 + 1, MEMF_CLEAR);
155 UWORD len = strlen(name), i;
157 if (len > 255)
158 len = 255;
159 bname[0] = len;
160 strcpy(bname + 1, name);
161 for (i = 0; i < len; i++) {
162 if (bname[1 + i] == 13 || bname[1 + i] == 10)
163 bname[i + 1] = ' ';
165 return MKBADDR(bname);
167 static void FreeBSTR(BSTR bstr)
169 FreeMem(BADDR(bstr), 256 + 1);
171 #endif
173 static UBYTE *ConvertBSTR(BSTR bname)
175 UBYTE *name = BADDR(bname);
176 UBYTE *s = AllocMem(256 + 1, MEMF_CLEAR);
177 if (!s)
178 return NULL;
179 CopyMem(name + 1, s, name[0]);
180 return s;
183 static void FreeString(UBYTE *cstr)
185 FreeMem(cstr, 256+1);
188 static void _WriteF(BPTR bfmt, ...)
190 IPTR *args = (IPTR *)&bfmt;
192 doBCPL(BCPL_WriteF, bfmt, args[1], args[2], args[3], &args[4], 26-3);
195 #if DEBUG
196 static void _DWriteF(BPTR bfmt, ...)
198 if (debug_enabled || DEBUG > 1) {
199 IPTR *args = (IPTR *)&bfmt;
201 doBCPL(BCPL_WriteF, bfmt, args[1], args[2], args[3], &args[4], 26-3);
204 #define DWriteF(fmt, args...) _DWriteF(AROS_CONST_BSTR(fmt) ,##args )
205 #endif
207 #define WriteF(fmt, args...) _WriteF(AROS_CONST_BSTR(fmt) ,##args )
209 /* For KS < 2.0, we need to call the BCPL ReadArgs,
210 * since DOS/ReadArgs doesn't exist.
212 static ULONG RdArgs(BSTR format, BPTR args, ULONG max_arg)
214 return doBCPL(BCPL_RdArgs, format, args, max_arg, 0, NULL, 0);
217 void meminfo(void)
219 struct MemHeader *mh;
220 ForeachNode(&SysBase->MemList, mh) {
221 char bstr[256];
222 bstr[0] = strlen(mh->mh_Node.ln_Name) & 0xff;
223 strncpy(&bstr[1], mh->mh_Node.ln_Name, bstr[0]);
224 WriteF("@$%X8-$%X8 ATTR $%X4 FREE $%X8 (%S)\n",
225 mh->mh_Lower, mh->mh_Upper, mh->mh_Attributes,
226 mh->mh_Free, MKBADDR(bstr));
230 /* Allocate MMU page aligned memory chunks */
232 static APTR AllocPageAligned(ULONG *psize, ULONG flags)
234 APTR ret;
235 ULONG size;
237 size = *psize;
238 size += ALLOCPADDING;
239 ret = AllocMem(size + 2 * PAGE_SIZE, flags);
240 D(DWriteF("AllocPageAligned: $%X8, %X4 => %X8\n", size + 2 * PAGE_SIZE, flags, ret));
241 if (ret == NULL)
242 return NULL;
243 Forbid();
244 FreeMem(ret, size + 2 * PAGE_SIZE);
245 size = (size + PAGE_SIZE - 1) & PAGE_MASK;
246 ret = AllocAbs(size, (APTR)(((((ULONG)ret) + PAGE_SIZE - 1) & PAGE_MASK)));
247 Permit();
248 if (ret == NULL)
249 return NULL;
250 *psize = size;
251 return ret;
253 static void FreePageAligned(APTR addr, ULONG size)
255 FreeMem(addr, (size + PAGE_SIZE - 1) & PAGE_MASK);
258 /* Define these here for zlib so that we don't
259 * pull in arosc.library.
261 * We can't use AllocVec, since it's only
262 * been around since KS v36
264 void *malloc(int size)
266 ULONG *vec;
268 size += sizeof(ULONG);
270 vec = AllocMem(size, MEMF_ANY);
271 if (vec == NULL) {
272 WriteF("libz: Failed to allocate %N bytes of type %X8\n", size, MEMF_ANY);
273 return NULL;
276 vec[0] = (ULONG)size;
277 return &vec[1];
280 void free(void *ptr)
282 ULONG *vec = ptr - sizeof(ULONG);
283 FreeMem(vec, vec[0]);
286 int open(const char *name, int mode)
288 return (int)Open(name, MODE_OLDFILE);
291 int close(int fd)
293 Close((BPTR)fd);
294 return 0;
297 ssize_t read(int fd, void *buff, size_t len)
299 return Read((BPTR)fd, buff, (LONG)len);
302 off_t lseek(int fd, off_t offset, int whence)
304 LONG mode = SEEK_SET;
305 LONG err;
307 switch (whence) {
308 case SEEK_CUR: mode = OFFSET_CURRENT; break;
309 case SEEK_SET: mode = OFFSET_BEGINNING; break;
310 case SEEK_END: mode = OFFSET_END; break;
311 default: return -1;
314 err = Seek((BPTR)fd, (LONG)offset, mode);
315 if (err < 0)
316 return -1;
318 return Seek((BPTR)fd, 0, OFFSET_CURRENT);
321 static AROS_UFH4(LONG, aosRead,
322 AROS_UFHA(BPTR, file, D1),
323 AROS_UFHA(void *, buf, D2),
324 AROS_UFHA(LONG, size, D3),
325 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
327 AROS_USERFUNC_INIT
329 return Read(file, buf, (unsigned)size);
331 AROS_USERFUNC_EXIT
333 static AROS_UFH4(LONG, aosSeek,
334 AROS_UFHA(BPTR, file, D1),
335 AROS_UFHA(LONG, pos, D2),
336 AROS_UFHA(LONG, mode, D3),
337 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
339 AROS_USERFUNC_INIT
340 int whence;
341 LONG ret;
342 LONG oldpos;
344 switch (mode) {
345 case OFFSET_CURRENT : whence = SEEK_CUR; break;
346 case OFFSET_END : whence = SEEK_END; break;
347 case OFFSET_BEGINNING: whence = SEEK_SET; break;
348 default: return -1;
351 oldpos = (LONG)Seek(file, 0, SEEK_CUR);
353 ret = (LONG)Seek(file, (z_off_t)pos, whence);
354 if (ret < 0)
355 return -1;
357 return oldpos;
359 AROS_USERFUNC_EXIT
362 static APTR aosAllocMem(ULONG size, ULONG flags, struct ExecBase *SysBase)
364 struct MemList *ml;
365 UBYTE *mem;
367 /* Clear bits 15-0, we're setting memory class explicitly */
368 flags &= ~0x7fff;
370 if (SysBase->LibNode.lib_Version >= 36) {
371 flags |= MEMF_LOCAL | MEMF_REVERSE;
372 } else {
373 flags |= MEMF_CHIP;
376 size += ALLOCATION_EXTRA;
377 mem = AllocMem(size, flags | MEMF_CLEAR);
378 if (mem == NULL) {
379 WriteF("AOS: Failed to allocate %N bytes of type %X8\n", size, flags);
380 meminfo();
381 return NULL;
384 ml = (struct MemList*)(mem + sizeof(struct MemChunk));
385 ml->ml_NumEntries = 1;
386 ml->ml_ME[0].me_Addr = (APTR)mem;
387 ml->ml_ME[0].me_Length = size;
388 AddTail(&mlist, (struct Node*)ml);
390 return &ml[1];
393 static AROS_UFH3(APTR, aosAlloc,
394 AROS_UFHA(ULONG, size, D0),
395 AROS_UFHA(ULONG, flags, D1),
396 AROS_UFHA(struct ExecBase *, SysBase, A6))
398 AROS_USERFUNC_INIT
400 return aosAllocMem(size, flags, SysBase);
402 AROS_USERFUNC_EXIT
404 static AROS_UFH3(void, aosFree,
405 AROS_UFHA(APTR, addr, A1),
406 AROS_UFHA(ULONG, size, D0),
407 AROS_UFHA(struct ExecBase *, SysBase, A6))
409 AROS_USERFUNC_INIT
411 addr -= sizeof(struct MemList);
412 Remove((struct Node*)addr);
413 addr -= sizeof(struct MemChunk);
414 size += ALLOCATION_EXTRA;
415 FreeMem(addr, size);
417 AROS_USERFUNC_EXIT
420 /* Backcalls for LoadSegment
421 * using the gzip backend.
423 static AROS_UFH4(LONG, elfRead,
424 AROS_UFHA(BPTR, file, D1),
425 AROS_UFHA(void *, buf, D2),
426 AROS_UFHA(LONG, size, D3),
427 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
429 AROS_USERFUNC_INIT
431 return gzread((gzFile)file, buf, (unsigned)size);
433 AROS_USERFUNC_EXIT
435 static AROS_UFH4(LONG, elfSeek,
436 AROS_UFHA(BPTR, file, D1),
437 AROS_UFHA(LONG, pos, D2),
438 AROS_UFHA(LONG, mode, D3),
439 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
441 AROS_USERFUNC_INIT
442 int whence;
443 LONG ret;
444 LONG oldpos;
446 switch (mode) {
447 case OFFSET_CURRENT : whence = SEEK_CUR; break;
448 case OFFSET_END : whence = SEEK_END; break;
449 case OFFSET_BEGINNING: whence = SEEK_SET; break;
450 default: return -1;
453 oldpos = (LONG)gzseek((gzFile)file, 0, SEEK_CUR);
455 ret = (LONG)gzseek((gzFile)file, (z_off_t)pos, whence);
456 if (ret < 0)
457 return -1;
459 return oldpos;
461 AROS_USERFUNC_EXIT
464 static APTR specialAlloc(ULONG size, ULONG flags, struct ExecBase *SysBase)
466 APTR mem;
467 struct MemList *ml;
469 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
470 /* Since we don't know if we need to wrap the memory
471 * with the KickMem wrapper until after allocation,
472 * we always adjust the size as if we have to.
474 size += ALLOCATION_EXTRA;
476 if (flags & MEMF_KICK) {
477 D(DWriteF("MEMF_KICK %N\n", size));
478 if (forceCHIP) {
479 flags |= MEMF_CHIP;
480 } else {
481 /* Prefer MEMF_KICK | MEMF_FAST if available */
482 flags |= MEMF_FAST;
486 /* Hmm. MEMF_LOCAL is only available on v36 and later.
487 * Use MEMF_CHIP if we have to.
489 if (flags & MEMF_LOCAL) {
490 D(DWriteF("MEMF_LOCAL %N\n", size));
491 if (forceFAST) {
492 flags &= ~MEMF_LOCAL;
493 } else if (SysBase->LibNode.lib_Version < 36 || forceCHIP) {
494 flags &= ~MEMF_LOCAL;
495 flags |= MEMF_CHIP;
499 /* MEMF_31BIT is not available on AOS */
500 if ((flags & MEMF_31BIT)) {
501 flags &= ~MEMF_31BIT;
504 /* If ROM allocation, always allocate from top of memory if possible */
505 if ((flags & MEMF_PUBLIC) && SysBase->LibNode.lib_Version >= 36) {
506 flags |= MEMF_REVERSE;
509 D(DWriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
510 mem = AllocPageAligned(&size, flags | MEMF_CLEAR);
511 if (mem == NULL) {
512 if ((flags & (MEMF_KICK | MEMF_FAST)) == (MEMF_KICK | MEMF_FAST)) {
513 /* Couldn't allocate MEMF_KICK | MEMF_FAST, fall back to any memory */
514 mem = AllocPageAligned(&size, (flags & MEMF_REVERSE) | MEMF_CLEAR);
516 if (mem == NULL) {
517 D(DWriteF("ELF: Failed to allocate %N bytes of type %X8\n", size, flags));
518 meminfo();
519 return NULL;
522 D(DWriteF("ELF: Got memory at %X8, size %N\n", (IPTR)mem, size));
524 ml = (struct MemList*)(mem + sizeof(struct MemChunk));
525 ml->ml_NumEntries = 1;
526 ml->ml_ME[0].me_Addr = (APTR)mem;
527 ml->ml_ME[0].me_Length = size;
529 /* Add to the KickMem list */
530 AddTail(&mlist, (struct Node*)ml);
532 return &ml[1];
536 static AROS_UFH3(APTR, elfAlloc,
537 AROS_UFHA(ULONG, size, D0),
538 AROS_UFHA(ULONG, flags, D1),
539 AROS_UFHA(struct ExecBase *, SysBase, A6))
541 AROS_USERFUNC_INIT
543 return specialAlloc(size, flags, SysBase);
545 AROS_USERFUNC_EXIT
548 static AROS_UFH3(void, elfFree,
549 AROS_UFHA(APTR, addr, A1),
550 AROS_UFHA(ULONG, size, D0),
551 AROS_UFHA(struct ExecBase *, SysBase, A6))
553 AROS_USERFUNC_INIT
555 /* If not page aligned, and the offset from the page boundary
556 * is the sizeof(MemChunk) + sizeof(MemList) then we can assume
557 * that it was a KickTag protected allocation
559 D(DWriteF("ELF: Free memory at %X8, size %N\n", (IPTR)addr, size));
560 addr -= sizeof(struct MemList);
561 Remove((struct Node*)addr);
562 addr -= sizeof(struct MemChunk);
563 size += ALLOCATION_EXTRA;
564 D(DWriteF("ELF: FREE memory at %X8, size %N\n", (IPTR)addr, size));
565 FreePageAligned(addr, size);
567 AROS_USERFUNC_EXIT
571 * This routine is called from within libloadseg.a's ELF loader.
572 * In dos.library it's responsible for collecting debug information from the loaded file.
573 * Here it does nothing (FIXME ???)
575 void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
580 static BPTR ROMLoad(BSTR bfilename)
582 gzFile gzf;
583 UBYTE *filename;
584 BPTR rom = BNULL;
585 SIPTR funcarray[] = {
586 (SIPTR)elfRead,
587 (SIPTR)elfAlloc,
588 (SIPTR)elfFree,
589 (SIPTR)elfSeek,
591 filename = ConvertBSTR(bfilename);
592 if (!filename)
593 return BNULL;
595 WriteF("Loading '%S' into RAM...\n", bfilename);
596 if ((gzf = gzopen(filename, "rb"))) {
597 gzbuffer(gzf, 65536);
599 rom = LoadSegment((BPTR)gzf, BNULL, funcarray, NULL);
600 if (rom == BNULL) {
601 WriteF("'%S': Can't parse, error %N\n", bfilename, IoErr());
604 gzclose_r(gzf);
605 } else {
606 WriteF("'%S': Can't open\n", bfilename);
608 FreeString(filename);
609 return rom;
612 /* Patch "picasso96/<driver>.chip" -> "<driver>.chip" so that OpenLibrary() finds it */
613 static void RTGPatch(struct Resident *r, BPTR seg)
615 BOOL patched = FALSE;
616 WORD len = strlen(r->rt_Name);
617 const UBYTE *name = r->rt_Name + len - 5;
618 if (len > 5 && (!stricmp(name, ".card") || !stricmp(name, ".chip"))) {
619 BPTR seglist = seg;
620 while (seglist) {
621 ULONG *ptr = BADDR(seglist);
622 LONG len = ptr[-1] - sizeof(BPTR);
623 UBYTE *p = (UBYTE*)(ptr + 1);
624 while (len > 0) {
625 if (len > 16 && !strnicmp(p, "libs:picasso96/", 15)) {
626 memmove(p, p + 15, strlen(p + 15) + 1);
627 patched = TRUE;
628 } else if (len > 10 && !strnicmp(p, "picasso96/", 10)) {
629 memmove(p, p + 10, strlen(p + 10) + 1);
630 patched = TRUE;
632 len--;
633 p++;
635 seglist = *((BPTR*)BADDR(seglist));
638 if (patched)
639 WriteF("Library path patched\n");
642 static BOOL PatchResidents(BPTR seg)
644 const LONG ressize = offsetof(struct Resident, rt_Init) + sizeof(APTR);
645 while(seg) {
646 ULONG *ptr = BADDR(seg);
647 UWORD *res;
648 UWORD *end = (UWORD*)((ULONG)ptr + ptr[-1] - ressize);
650 res = (UWORD*)(ptr + 1);
651 while (res < end) {
652 if (*res == RTC_MATCHWORD && ((ULONG*)(res + 1))[0] == (ULONG)res) {
653 struct Resident *r = (struct Resident*)res;
654 r->rt_Flags |= 1 << 5;
655 if (r->rt_EndSkip <= (APTR)res) {
656 #if DEBUG > 1
657 WriteF("Invalid rt_EndSkip: %X8, Resident: %X8\n", r->rt_EndSkip, r);
658 #endif
659 res += ressize / sizeof(WORD) - 1;
660 } else {
661 res = (UWORD*)r->rt_EndSkip - 1;
664 res++;
666 seg = (BPTR)ptr[0];
668 return TRUE;
671 #define RESLIST_CHUNK 100
672 #define LRF_NOPATCH (1 << 0) /* If set, don't patch the struct Resident */
674 static struct Resident **LoadResident(BPTR seg, struct Resident **reslist, ULONG *resleft, ULONG flags)
676 const LONG ressize = offsetof(struct Resident, rt_Init) + sizeof(APTR);
677 ULONG *ptr = BADDR(seg);
678 UWORD *res;
679 UWORD *end = (UWORD*)((ULONG)ptr + ptr[-1] - ressize);
681 res = (UWORD*)(ptr + 1);
682 while (res < end) {
683 if (*res == RTC_MATCHWORD && ((ULONG*)(res + 1))[0] == (ULONG)res) {
684 struct Resident *r = (struct Resident*)res;
685 if (!(flags & LRF_NOPATCH)) {
686 /* Set RTF_COLDSTART if no initialization flags set */
687 if (!(r->rt_Flags & (RTF_COLDSTART | RTF_SINGLETASK | RTF_AFTERDOS)))
688 r->rt_Flags |= RTF_COLDSTART;
689 if (r->rt_Pri < 10)
690 r->rt_Pri = 10;
691 RTGPatch(r, seg);
694 if (*resleft == 0) {
695 struct Resident **resnew;
696 resnew = aosAllocMem(RESLIST_CHUNK * sizeof(struct Resident*), MEMF_CLEAR, SysBase);
697 if (!resnew)
698 return 0;
700 *reslist = (APTR)((IPTR)resnew | RESLIST_NEXT);
701 reslist = resnew;
702 *resleft = RESLIST_CHUNK - 1;
704 D(DWriteF("Resident structure found @%X8\n", r));
705 *(reslist++) = r;
706 (*resleft)--;
708 if (r->rt_EndSkip <= (APTR)res)
709 res += ressize / sizeof(WORD) - 1;
710 else
711 res = (UWORD*)r->rt_EndSkip - 1;
713 res++;
716 return reslist;
719 static struct Resident **LoadResidents(BPTR *namearray, struct Resident **resnext, ULONG *resleft)
721 UBYTE i;
722 SIPTR funcarray[] = {
723 (SIPTR)aosRead,
724 (SIPTR)aosAlloc,
725 (SIPTR)aosFree,
726 (SIPTR)aosSeek,
729 for (i = 0; namearray[i]; i++) {
730 LONG stack;
731 BPTR handle;
732 BPTR seglist = BNULL;
733 BPTR bname;
734 UBYTE *name;
736 bname = namearray[i];
737 name = ConvertBSTR(bname);
738 if (name) {
739 handle = Open(name, MODE_OLDFILE);
740 if (handle) {
741 seglist = LoadSegment(handle, BNULL, funcarray, &stack);
742 Close(handle);
744 if (seglist) {
745 BPTR seg;
746 WriteF("Loaded '%S'\n", bname);
747 for (seg = seglist; seg != BNULL; seg = *((BPTR*)BADDR(seg)))
748 resnext = LoadResident(seg, resnext, resleft, 0);
749 } else {
750 WriteF("Failed to load '%S', error %N\n", bname, IoErr());
752 FreeString(name);
756 return resnext;
759 #if DEBUG
761 #define SERDATR 0x18
762 #define SERDAT 0x30
763 #define INTREQ 0x9c
764 #define INTENA 0x9a
765 #define SERDATR_TBE (1 << 13) /* Tx Buffer Empty */
766 #define SERDAT_STP8 (1 << 8)
767 #define SERDAT_DB8(x) ((x) & 0xff)
768 #define SERPER_BASE_PAL 3546895
769 #define SERPER 0x32
770 #define SERPER_BAUD(base, x) ((((base + (x)/2))/(x)-1) & 0x7fff) /* Baud rate */
771 #define INTF_TBE 0x0001
773 static inline void reg_w(ULONG reg, UWORD val)
775 volatile UWORD *r = (void *)(0xdff000 + reg);
777 *r = val;
779 static inline UWORD reg_r(ULONG reg)
781 volatile UWORD *r = (void *)(0xdff000 + reg);
783 return *r;
785 static void DebugInit(void)
787 /* Set DTR, RTS, etc */
788 volatile UBYTE *ciab_pra = (APTR)0xBFD000;
789 volatile UBYTE *ciab_ddra = (APTR)0xBFD200;
790 if (!debug_enabled)
791 return;
792 *ciab_ddra = 0xc0; /* Only DTR and RTS are driven as outputs */
793 *ciab_pra = 0; /* Turn on DTR and RTS */
795 /* Set the debug UART to 115200 */
796 reg_w(SERPER, SERPER_BAUD(SERPER_BASE_PAL, 115200));
797 /* Disable serial transmit interrupt */
798 reg_w(INTENA, INTF_TBE);
800 static void DebugPutChar(register int chr)
802 if (!debug_enabled)
803 return;
804 if (chr == '\n')
805 DebugPutChar('\r');
806 while ((reg_r(SERDATR) & SERDATR_TBE) == 0);
807 reg_w(INTREQ, INTF_TBE);
808 /* Output a char to the debug UART */
809 reg_w(SERDAT, SERDAT_STP8 | SERDAT_DB8(chr));
811 static void DebugPutStr(register const char *buff)
813 if (!debug_enabled)
814 return;
815 for (; *buff != 0; buff++)
816 DebugPutChar(*buff);
818 #if 0
819 static void DebugPutDec(const char *what, ULONG val)
821 int i, num;
822 if (!debug_enabled)
823 return;
824 DebugPutStr(what);
825 DebugPutStr(": ");
826 if (val == 0) {
827 DebugPutChar('0');
828 DebugPutChar('\n');
829 return;
832 for (i = 1000000000; i > 0; i /= 10) {
833 if (val == 0) {
834 DebugPutChar('0');
835 continue;
838 num = val / i;
839 if (num == 0)
840 continue;
842 DebugPutChar("0123456789"[num]);
843 val -= num * i;
845 DebugPutChar('\n');
847 static void DebugPutHex(const char *what, ULONG val)
849 int i;
850 if (!debug_enabled)
851 return;
852 DebugPutStr(what);
853 DebugPutStr(": ");
854 for (i = 0; i < 8; i ++) {
855 DebugPutChar("0123456789abcdef"[(val >> (28 - (i * 4))) & 0xf]);
857 DebugPutChar('\n');
859 static void DebugPutHexVal(ULONG val)
861 int i;
862 if (!debug_enabled)
863 return;
864 for (i = 0; i < 8; i ++) {
865 DebugPutChar("0123456789abcdef"[(val >> (28 - (i * 4))) & 0xf]);
867 DebugPutChar(' ');
869 #endif
870 #endif
873 #define FAKEBASE 0x200
874 #define FAKEBASESIZE 558
875 #define COLDCAPTURE (FAKEBASE + FAKEBASESIZE + 16)
877 /* Theory of operation:
879 - create fake sysbase in low chip memory (We can't use original because it is not binary compatible with AROS one)
880 - set correct checksum and point ColdCapture to our routine (also in low chip)
881 - reset the system (autoconfig devices disappear, including most expansion RAM and ROM overlay disables chip RAM)
882 - original ROM code now disables ROM overlay and checks KS checksum and jumps to our ColdCapture routine
883 - above step is needed because in worst case ALL RAM disappear at reset and there
884 are also accelerators that reset the CPU completely when reset instruction is executed.
885 - now we have control again, autoconfig devices are still unconfigured but at least we have chip ram.
886 - jump to AROS ROM code entry point which detects romloader mode and automatically reserves RAM used by "ROM" code
887 - AROS ROM creates new proper execbase and copies ColdCapture
888 - normal boot starts
892 static UWORD GetSysBaseChkSum(struct ExecBase *sysbase)
894 UWORD sum = 0;
895 UWORD *p = (UWORD*)&sysbase->SoftVer;
896 while (p <= &sysbase->ChkSum)
897 sum += *p++;
898 return sum;
901 static ULONG mySumKickData(struct ExecBase *sysbase, BOOL output)
903 ULONG chksum = 0;
904 BOOL isdata = FALSE;
906 if (sysbase->KickTagPtr) {
907 IPTR *list = sysbase->KickTagPtr;
908 while(*list)
910 chksum += (ULONG)*list;
911 #if 0
912 if (output) {
913 WriteF("%X8 %X8\n", list, *list);
914 WriteF("CHK %X8\n", chksum);
916 #endif
918 /* on amiga, if bit 31 is set then this points to another list of
919 * modules rather than pointing to a single module. bit 31 is
920 * inconvenient on architectures where code may be loaded above
921 * 2GB. on these platforms we assume aligned pointers and use bit
922 * 0 instead */
923 #ifdef __mc68000__
924 if(*list & 0x80000000) { list = (IPTR *)(*list & 0x7fffffff); continue; }
925 #else
926 if(*list & 0x1) { list = (IPTR *)(*list & ~(IPTR)0x1); continue; }
927 #endif
928 list++;
929 isdata = TRUE;
933 if (sysbase->KickMemPtr) {
934 struct MemList *ml = (struct MemList*)sysbase->KickMemPtr;
935 while (ml) {
936 UBYTE i;
937 ULONG *p = (ULONG*)ml;
938 for (i = 0; i < sizeof(struct MemList) / sizeof(ULONG); i++)
939 chksum += p[i];
941 #if 0
942 if (output) {
943 WriteF("ML %X8 %X8\n", ml, chksum);
944 WriteF("NODE0 %X8 %X8\n", p[0], p[1]);
945 WriteF("NODE2 %X8 %X8\n", p[2], p[3]);
946 WriteF("ADDR %X8 %X8\n", ml->ml_ME[0].me_Un.meu_Addr, ml->ml_ME[0].me_Length);
947 WriteF("DATA0 %X8 %X8\n", p[6], p[7]);
949 #endif
951 ml = (struct MemList*)ml->ml_Node.ln_Succ;
952 isdata = TRUE;
955 if (isdata && !chksum)
956 chksum--;
957 return chksum;
961 /* reset VBR and switch off MMU */
962 static void setcpu(void)
964 asm(
965 ".chip 68040\n"
966 "move.l 4,%a0\n"
967 "move.w 296(%a0),%d1\n"
968 "moveq #0,%d0\n"
969 "btst #0,%d1\n"
970 "beq.s cpudone\n"
971 /* clear VBR */
972 "movec %d0,%vbr\n"
973 "btst #1,%d1\n"
974 "beq.s cpudone\n"
975 /* disable caches */
976 "movec %d0,%cacr\n"
977 "btst #3,%d1\n"
978 "beq.s not040\n"
979 /* 68040/060 MMU */
980 "movec %d0,%tc\n"
981 "movec %d0,%dtt0\n"
982 "movec %d0,%dtt1\n"
983 "movec %d0,%itt0\n"
984 "movec %d0,%itt1\n"
985 "cpusha %bc\n"
986 "bra.s cpudone\n"
987 "not040: btst #2,%d1\n"
988 "beq.s cpudone\n"
989 /* 68030 MMU */
990 "lea zero(%pc),%a0\n"
991 ".long 0xf0104000\n"
992 ".long 0xf0100c00\n"
993 ".long 0xf0100800\n"
994 "bra.s cpudone\n"
995 "zero: .long 0,0\n"
996 "cpudone:\n"
1000 /* This is needed because KS clears ColdCapture before calling it
1001 * causing checksum mismatch in AROS exec check
1003 void coldcapturecode(void)
1005 asm(
1006 ".long end - start\n"
1007 "start:\n"
1008 "bra.s 0f\n"
1009 "nop\n" /* Align to start + 4 */
1010 ".long 0x46414b45\n" /* AROS_MAKE_ID('F','A','K','E') */
1011 "0:\n"
1012 "move.w #0x440,0xdff180\n"
1013 "clr.l 0.w\n"
1014 "clr.l 4.w\n"
1016 // set early exceptions
1017 "move.w #8,%a1\n"
1018 "lea exception(%pc),%a0\n"
1019 "moveq #64-2-1,%d0\n"
1020 "1:\n"
1021 "move.l %a0,(%a1)+\n"
1022 "dbf %d0,1b\n"
1024 "lea 0x200,%a0\n"
1025 "move.l (%a0),0x7c.w\n" // restore NMI
1026 "lea 12(%a0),%a0\n"
1027 "move.l %a0,4.w\n"
1028 "lea start(%pc),%a1\n"
1029 "move.l %a1,42(%a0)\n" // ColdCapture
1030 "move.l %a0,%d0\n"
1031 "not.l %d0\n"
1032 "move.l %d0,38(%a0)\n" // ChkBase
1033 "moveq #0,%d1\n"
1034 "lea 34(%a0),%a0\n"
1035 "moveq #24-1,%d0\n"
1036 "chk1: add.w (%a0)+,%d1\n"
1037 "dbf %d0,chk1\n"
1038 "not.w %d1\n"
1039 "move.w %d1,(%a0)\n" // ChkSum
1040 "move.l start-4(%pc),%a0\n"
1041 "addq.l #2,%a0\n"
1042 "moveq #2,%d0\n"
1043 "cmp.w #0x4ef9,(%a0)\n"
1044 "beq.s .skip\n"
1045 // skip elf loader injected header
1046 "moveq #4,%d0\n"
1047 "move.l (%a0),%a0\n"
1048 ".skip:\n"
1049 "move.l 0(%a0,%d0.w),%a0\n"
1050 "jmp 4(%a0)\n"
1051 "exception:\n"
1052 "move.w #0xff0,0xdff180\n"
1053 "move.w #0x000,0xdff180\n"
1054 "bra.s exception\n"
1055 "end:\n"
1059 /* Official reboot code from HRM
1060 * All CPUs have at least 1 word prefetch,
1061 * jmp (a0) has been prefetched even if
1062 * reset disables all memory
1064 static void doreboot(void)
1066 asm volatile (
1067 "lea 0x01000000,%a0\n"
1068 "sub.l %a0@(-0x14),%a0\n"
1069 "move.l %a0@(4),%a0\n"
1070 "subq.l #2,%a0\n"
1071 ".balign 8\n" /* Workaround for E-UAE emulation bug */
1072 "reset\n"
1073 "jmp (%a0)\n"
1077 APTR entry, kicktags;
1078 struct BootStruct *bootstruct;
1080 static void supercode(void)
1082 ULONG *fakesys, *coldcapture, *coldcapturep;
1083 struct ExecBase *sysbase;
1084 ULONG *traps = 0;
1085 ULONG len;
1087 #if DEBUG
1088 DebugPutStr("Entered Supervisor mode.\n");
1089 #endif
1091 if ((SysBase->AttnFlags & 0xff) != 0)
1092 setcpu();
1094 #if DEBUG
1095 DebugPutStr("CPU setup done.\n");
1096 #endif
1098 fakesys = (ULONG*)FAKEBASE;
1099 coldcapture = (ULONG*)COLDCAPTURE;
1100 coldcapture[-1] = (ULONG)entry;
1101 coldcapturep = (ULONG*)coldcapturecode;
1102 len = *coldcapturep++;
1103 memcpy (coldcapture, coldcapturep, len);
1105 *fakesys++ = traps[31]; // Level 7
1106 *fakesys++ = 0x4ef9 | (COLDCAPTURE >> 16);
1107 *fakesys++ = (COLDCAPTURE << 16) | 0x4e75;
1108 sysbase = (struct ExecBase*)fakesys;
1110 memset(sysbase, 0, FAKEBASESIZE);
1111 /* Misuse DebugData as a kernel tag pointer,
1113 if (bootstruct)
1114 sysbase->DebugData = bootstruct;
1116 /* Detached node */
1117 sysbase->LibNode.lib_Node.ln_Pred = &sysbase->LibNode.lib_Node;
1118 sysbase->LibNode.lib_Node.ln_Succ = &sysbase->LibNode.lib_Node;
1120 /* Set up cold capture */
1121 sysbase->ColdCapture = coldcapture;
1122 sysbase->MaxLocMem = 512 * 1024;
1123 sysbase->ChkBase =~(IPTR)sysbase;
1124 sysbase->ChkSum = GetSysBaseChkSum(sysbase) ^ 0xffff;
1126 /* Propogate the existing OS's Kick Data */
1127 if (mlist.lh_Head->ln_Succ) {
1128 sysbase->KickMemPtr = (APTR)mlist.lh_Head;
1129 mlist.lh_TailPred->ln_Succ = SysBase->KickMemPtr;
1130 } else {
1131 sysbase->KickMemPtr = (APTR)SysBase->KickMemPtr;
1133 if (kicktags) {
1134 sysbase->KickTagPtr = kicktags;
1135 if (SysBase->KickTagPtr) {
1136 ULONG *p = kicktags;
1137 while (*p)
1138 p++;
1139 *p = 0x80000000 | (ULONG)SysBase->KickTagPtr;
1141 } else {
1142 sysbase->KickTagPtr = SysBase->KickTagPtr;
1144 sysbase->KickCheckSum = (APTR)mySumKickData(sysbase, FALSE);
1146 traps[1] = (IPTR)sysbase;
1148 #if DEBUG
1149 DebugPutStr("Rebooting.\n");
1150 #endif
1152 // TODO: add custom cacheclear, can't call CacheClearU() because it may not work
1153 // anymore and KS 1.x does not even have it
1154 doreboot();
1157 void BootROM(BPTR romlist, struct Resident **reslist, struct BootStruct *BootS)
1159 APTR GfxBase;
1161 entry = BADDR(romlist)+sizeof(ULONG);
1162 kicktags = reslist;
1163 bootstruct = BootS;
1165 #if DEBUG
1166 DebugPutStr("Booting..\n");
1167 #endif
1169 #if 0
1170 /* Debug testing code */
1171 if (mlist.lh_Head->ln_Succ) {
1172 SysBase->KickMemPtr = (APTR)mlist.lh_Head;
1173 mlist.lh_TailPred->ln_Succ = NULL;
1175 if (kicktags) {
1176 SysBase->KickTagPtr = kicktags;
1178 mySumKickData(SysBase, TRUE);
1179 SysBase->KickTagPtr = 0;
1180 SysBase->KickMemPtr = 0;
1181 Delay(200);
1182 #endif
1184 if ((GfxBase = OpenLibrary("graphics.library", 0))) {
1185 LoadView(NULL);
1186 WaitTOF();
1187 WaitTOF();
1188 CloseLibrary(GfxBase);
1191 /* We're off in the weeds now. */
1192 Disable();
1194 Supervisor((ULONG_FUNC)supercode);
1197 #if DEBUG
1198 static void DumpKickMems(ULONG num, struct MemList *ml)
1200 if (num == 0)
1201 DWriteF("Original KickMemList:\n");
1202 else
1203 DWriteF("AROS KickMemList:\n");
1204 /* List is single-linked but last link gets cleared later, so test ln_Succ too */
1205 while (ml && ml->ml_Node.ln_Succ) {
1206 WORD i;
1207 DWriteF("%X8:%N\n", ml, ml->ml_NumEntries);
1208 for (i = 0; i < ml->ml_NumEntries; i++) {
1209 DWriteF(" %N: %X8, %N\n", i, ml->ml_ME[i].me_Un.meu_Addr, ml->ml_ME[i].me_Length);
1211 ml = (struct MemList*)ml->ml_Node.ln_Succ;
1213 DWriteF("End of List\n");
1216 static void DumpKickTags(ULONG num, struct Resident **list)
1218 if (num == 0)
1219 DWriteF("Original KickTagList:\n");
1220 else
1221 DWriteF("AROS KickTagList:\n");
1222 while (*list) {
1223 BSTR bname;
1224 if ((ULONG)list & 0x80000000) {
1225 DWriteF("Redirected to %X8\n", (ULONG)list & ~0x80000000);
1226 list = (struct Resident**)((ULONG)list & ~0x80000000);
1227 continue;
1229 bname = ConvertCSTR((*list)->rt_IdString);
1230 DWriteF("%X8: %X8 %S\n", list, *list, bname);
1231 FreeBSTR(bname);
1232 list++;
1234 DWriteF("End of List\n");
1236 #endif
1238 #define HC_FORCEFAST 1
1239 struct HardwareConfig
1241 UWORD manufacturer;
1242 UBYTE product;
1243 const UBYTE *name;
1244 UBYTE flags;
1247 static const struct HardwareConfig hc[] =
1249 { 8512, 17, "Blizzard A1200 Accelerator", HC_FORCEFAST }, // Blizzard 1230 IV, 1240 or 1260.
1250 { 0 }
1253 static void DetectHardware(void)
1255 struct ConfigDev *cd = NULL;
1256 int i;
1258 ExpansionBase = (APTR)OpenLibrary("expansion.library", 0);
1259 if (!ExpansionBase)
1260 return;
1261 while((cd = FindConfigDev(cd, -1, -1))) {
1262 for (i = 0; hc[i].manufacturer; i++) {
1263 if (cd->cd_Rom.er_Manufacturer == hc[i].manufacturer && cd->cd_Rom.er_Product == hc[i].product) {
1264 BSTR bname;
1265 bname = ConvertCSTR(hc[i].name);
1266 WriteF("%S: ", bname);
1267 if (hc[i].flags & HC_FORCEFAST) {
1268 forceFAST = TRUE;
1269 WriteF("ForceFast enabled");
1271 WriteF("\n");
1272 FreeBSTR(bname);
1276 CloseLibrary(ExpansionBase);
1279 static struct Resident **ScanROMSegment(BPTR ROMSegList, struct Resident **resnext, ULONG *resleft)
1281 BPTR seg;
1282 /* Only scan 2nd ROM section */
1283 seg = *((BPTR*)BADDR(ROMSegList));
1284 return LoadResident(seg, resnext, resleft, LRF_NOPATCH);
1287 #define KERNELTAGS_SIZE 10
1288 #define CMDLINE_SIZE 512
1290 static struct BootStruct *AllocBootStruct(UBYTE *cmdline)
1292 struct TagItem *tags;
1293 struct BootStruct *boots;
1294 UBYTE *cmd;
1296 boots = aosAllocMem(sizeof(struct BootStruct) + sizeof(struct TagItem) * KERNELTAGS_SIZE + CMDLINE_SIZE, MEMF_CLEAR, SysBase);
1297 if (!boots)
1298 return NULL;
1299 tags = (struct TagItem*)(boots + 1);
1300 cmd = (UBYTE*)(tags + KERNELTAGS_SIZE);
1301 /* cmdline is a BCPL string! */
1302 if (cmdline && cmdline[0])
1303 CopyMem(cmdline + 1, cmd, cmdline[0]);
1304 else
1305 strcpy(cmd, DEFAULT_KERNEL_CMDLINE);
1306 tags[0].ti_Tag = KRN_CmdLine;
1307 tags[0].ti_Data = (IPTR)cmd;
1308 tags[1].ti_Tag = TAG_DONE;
1310 boots->magic = ABS_BOOT_MAGIC;
1311 boots->kerneltags = tags;
1312 if (forceFAST) {
1313 UBYTE *addr = specialAlloc(SS_STACK_SIZE + MAGIC_FAST_SIZE + 1, MEMF_FAST | MEMF_REVERSE, SysBase); /* +1 = guaranteed extra page at the end */
1314 if (addr) {
1315 addr = (UBYTE*)(((ULONG)(addr + PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1));
1316 boots->ss_address = addr;
1317 boots->ss_size = SS_STACK_SIZE;
1318 /* magic fast mem pool for early allocations that normally can't be allocated from fast memory */
1319 boots->magicfastmem = boots->ss_address + SS_STACK_SIZE;
1320 boots->magicfastmemsize = MAGIC_FAST_SIZE;
1323 return boots;
1326 __startup static AROS_PROCH(startup, argstr, argsize, sysBase)
1328 AROS_PROCFUNC_INIT
1330 SysBase = sysBase;
1331 APTR lowmem;
1333 /* Allocate some low MEMF_CHIP ram, as a buffer
1334 * against overlapping allocations with the initial
1335 * stack.
1337 lowmem = AllocMem(PAGE_SIZE, MEMF_CHIP);
1339 NEWLIST(&mlist);
1340 DOSBase = (APTR)OpenLibrary("dos.library", 0);
1341 if (DOSBase != NULL) {
1342 BPTR ROMSegList;
1343 BSTR name = AROS_CONST_BSTR("aros.elf");
1344 enum { ARG_ROM = 16, ARG_CMD = 17, ARG_FORCECHIP = 18, ARG_FORCEFAST = 19, ARG_DEBUG = 20, ARG_FORCEAROS = 21, ARG_MODULES = 0 };
1345 /* It would be nice to use the '/M' switch, but that
1346 * is not supported under the AOS BCPL RdArgs routine.
1348 * So only 16 modules are supported
1350 BSTR format = AROS_CONST_BSTR(",,,,,,,,,,,,,,,,ROM/K,CMD/K,FORCECHIP/S,FORCEFAST/S,DEBUG/S,FORCEAROS/S");
1351 /* Make sure the args are in .bss, not stack */
1352 static ULONG args[16 + 6 + 256] __attribute__((aligned(4))) = { };
1354 args[0] = name;
1356 RdArgs(format, MKBADDR(args), sizeof(args)/sizeof(args[0]));
1357 #if DEBUG > 1
1358 DWriteF("ROM: %S\n", args[ARG_ROM]);
1359 DWriteF("CMD: %S\n", args[ARG_CMD]);
1360 DWriteF("FORCECHIP: %N\n", args[ARG_FORCECHIP]);
1361 DWriteF("FORCEFAST: %N\n", args[ARG_FORCEFAST]);
1362 DWriteF("MOD: %S\n", args[0]);
1363 DWriteF(" : %S\n", args[1]);
1364 DWriteF(" : %S\n", args[2]);
1365 DWriteF(" : %S\n", args[3]);
1367 #endif
1368 forceAROS = args[ARG_FORCEAROS] ? TRUE : FALSE;
1369 forceCHIP = args[ARG_FORCECHIP] ? TRUE : FALSE;
1370 forceFAST = args[ARG_FORCEFAST] ? TRUE : FALSE;
1371 debug_enabled = args[ARG_DEBUG] ? TRUE : FALSE;
1373 /* See if we're already running on AROS.
1375 if (OpenResource("kernel.resource") != NULL) {
1376 if (!forceAROS) {
1377 CloseLibrary(DOSBase);
1378 FreeMem(lowmem, PAGE_SIZE);
1379 return RETURN_OK;
1381 } else {
1382 forceAROS = FALSE;
1385 WriteF("AROSBootstrap " ADATE "\n");
1386 if (forceAROS)
1387 WriteF("Forcing load of AROS on existing AROS\n");
1389 /* Blizzard A1200 accelerator boards have strange MAP ROM
1390 * feature, even when it is disabled, ROM is copied to
1391 * last 512K of RAM, so we have to make sure all our
1392 * allocations ignore this region.
1393 * Blizzard Fast RAM memory type is plain MEMF_FAST.
1395 if (SysBase->LibNode.lib_Version >= 37 && !AvailMem(MEMF_KICK | MEMF_FAST)) {
1396 if (AvailMem(MEMF_FAST)) {
1397 WriteF("Reserving non-MEMF_KICK Fast RAM\n");
1398 int i;
1399 /* Allocate in PAGE_SIZE byte chunks, it is smallest allocated size */
1400 for (i = 0; i < 524288 / PAGE_SIZE; i++)
1401 AllocMem(PAGE_SIZE, MEMF_FAST | MEMF_REVERSE);
1405 meminfo();
1406 DetectHardware();
1408 #if DEBUG
1409 DebugInit();
1410 #endif
1412 if (!IoErr()) {
1413 /* Load ROM image */
1414 if (args[ARG_ROM] == BNULL)
1415 args[ARG_ROM] = name;
1417 ROMSegList = ROMLoad(args[ARG_ROM]);
1418 if (ROMSegList != BNULL) {
1419 ULONG resleft = 0;
1420 struct Resident **ResidentList;
1421 struct BootStruct *BootS;
1422 WriteF("Successfully loaded ROM\n");
1423 ROM_Loaded = TRUE;
1424 struct Resident **resnext, *reshead = NULL;
1426 PatchResidents(ROMSegList);
1427 resnext = &reshead;
1428 resnext = ScanROMSegment(ROMSegList, resnext, &resleft);
1429 resnext = LoadResidents(&args[ARG_MODULES], resnext, &resleft);
1430 BootS = AllocBootStruct(BADDR(args[ARG_CMD]));
1431 ResidentList = (APTR)((IPTR)reshead & ~RESLIST_NEXT);
1433 #if DEBUG
1434 DumpKickMems(0, SysBase->KickMemPtr);
1435 DumpKickMems(1, (struct MemList*)mlist.lh_Head);
1436 DumpKickTags(0, SysBase->KickTagPtr);
1437 DumpKickTags(1, ResidentList);
1438 #endif
1439 WriteF("Booting...\n");
1440 Delay(50);
1442 BootROM(ROMSegList, ResidentList, BootS);
1444 UnLoadSeg(ROMSegList);
1445 } else {
1446 WriteF("Can't load ROM ELF file %S\n", args[ARG_ROM]);
1448 } else {
1449 WriteF("Can't parse arguments, error %N\n", IoErr());
1452 CloseLibrary((APTR)DOSBase);
1455 FreeMem(lowmem, PAGE_SIZE);
1457 return IoErr();
1459 AROS_PROCFUNC_EXIT