arch/m68k-amiga: AROSBootstrap workaround for buggy E-UAE m68k emulation
[AROS.git] / arch / m68k-amiga / c / AROSBootstrap.c
blob105e230aa935f01f17720b807bede9822143e8e9
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 * MEMF_LOCAL RAM to get this to work.
15 * We also use MEMF_KICK, since some MEMF_KICK ram may will
16 * be available after expansion.library processing.
18 * Also - no AROS specific code can go in here! We have to run
19 * on AOS 1.3 and up.
21 #define DEBUG 0
23 #include <proto/exec.h>
24 #include <proto/graphics.h>
25 #include <proto/dos.h>
26 #include <exec/resident.h>
27 #include <aros/kernel.h>
28 #include <hardware/cpu/memory.h>
30 #include <stddef.h> /* offsetof */
31 #include <string.h> /* memcpy, memset */
32 #include <zlib.h>
34 #if defined(DEBUG) && DEBUG
35 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode mungwall"
36 #else
37 #define DEFAULT_KERNEL_CMDLINE "sysdebug=InitCode"
38 #endif
40 #define PROTO_KERNEL_H /* Don't pick up AROS kernel hooks */
41 #define NO_SYSBASE_REMAP
43 #if DEBUG
44 #define AROS_DEBUG_H
45 #include <stdio.h>
46 #include <string.h>
47 static inline void bug(const char *fmt, ...)
49 static char buff[256];
50 va_list args;
52 va_start(args, fmt);
53 vsnprintf(buff, sizeof(buff), fmt, args);
54 va_end(args);
56 Write(Output(), buff, strlen(buff));
58 #define D(x) x
59 #else
60 #define D(x)
61 #endif
63 #include <loadseg.h>
65 struct DosLibrary *DOSBase;
67 static BOOL ROM_Loaded = FALSE;
68 static struct List mlist;
70 /* KS 1.3 (and earlier) don't have a dos.library with
71 * niceties such as VFPrintf nor ReadArgs.
73 * We need to use the BCPL routines to be able
74 * to do these types of operations.
76 #define BCPL_WriteS 73
77 #define BCPL_WriteF 74
78 #define BCPL_RdArgs 78
80 #undef Printf
81 #define Printf __Printf_NOT_AVAILABLE_UNDER_KS1_3
82 #undef ReadArgs
83 #define ReadArgs __ReadArgs_NOT_AVAILABLE_UNDER_KS1_3
85 /* BCPL can trash D5-D7 and A3, evidently.
87 static void bcplWrapper(void)
89 asm volatile (
90 "movem.l %d5-%d7/%a3,%sp@-\n"
91 "jsr (%a5)\n"
92 "movem.l %sp@+,%d5-%d7/%a3\n"
96 static ULONG doBCPL(int index, ULONG d1, ULONG d2, ULONG d3, ULONG d4, const IPTR *arg, int args)
98 struct Process *pr = (APTR)FindTask(NULL);
99 APTR func;
100 ULONG *gv = pr->pr_GlobVec;
101 ULONG ret;
102 ULONG *BCPL_frame = AllocMem(1500, MEMF_ANY);
103 if (BCPL_frame == NULL)
104 return 0;
106 func = (APTR)gv[index];
108 if (args != 0)
109 CopyMem(arg, &BCPL_frame[3 + 4], args * sizeof(ULONG));
111 ret = AROS_UFC11(ULONG, bcplWrapper,
112 AROS_UFCA(ULONG, 0, D0), /* BCPL frame usage (args-3)*/
113 AROS_UFCA(ULONG, d1, D1),
114 AROS_UFCA(ULONG, d2, D2),
115 AROS_UFCA(ULONG, d3, D3),
116 AROS_UFCA(ULONG, d4, D4),
117 AROS_UFCA(ULONG, 0, A0), /* System memory base */
118 AROS_UFCA(ULONG *, &BCPL_frame[3], A1),
119 AROS_UFCA(APTR, gv, A2),
120 AROS_UFCA(APTR, func, A4),
121 AROS_UFCA(APTR, DOSBase->dl_A5, A5),
122 AROS_UFCA(APTR, DOSBase->dl_A6, A6));
124 FreeMem(BCPL_frame, 1500);
126 return ret;
129 static UBYTE *ConvertBSTR(BSTR bname)
131 UBYTE *name = BADDR(bname);
132 UBYTE *s = AllocMem(256 + 1, MEMF_CLEAR);
133 if (!s)
134 return NULL;
135 CopyMem(name + 1, s, name[0]);
136 return s;
139 static void FreeString(UBYTE *cstr)
141 FreeMem(cstr, 256+1);
144 static void _WriteF(BPTR bfmt, ...)
146 IPTR *args = (IPTR *)&bfmt;
148 doBCPL(BCPL_WriteF, bfmt, args[1], args[2], args[3], &args[4], 26-3);
151 #define WriteF(fmt, args...) _WriteF(AROS_CONST_BSTR(fmt) ,##args )
153 /* For KS < 2.0, we need to call the BCPL ReadArgs,
154 * since DOS/ReadArgs doesn't exist.
156 static ULONG RdArgs(BSTR format, BPTR args, ULONG max_arg)
158 return doBCPL(BCPL_RdArgs, format, args, max_arg, 0, NULL, 0);
161 void meminfo(void)
163 struct MemHeader *mh;
164 ForeachNode(&SysBase->MemList, mh) {
165 char bstr[256];
166 bstr[0] = strlen(mh->mh_Node.ln_Name) & 0xff;
167 strncpy(&bstr[1], mh->mh_Node.ln_Name, bstr[0]);
168 WriteF("@$%X8-$%X8 ATTR $%X4 FREE $%X8 (%S)\n",
169 mh->mh_Lower, mh->mh_Upper, mh->mh_Attributes,
170 mh->mh_Free, MKBADDR(bstr));
174 /* Allocate MMU page aligned memory chunks */
176 #define ALLOCPADDING (sizeof(struct MemChunk) + 2 * sizeof(BPTR))
178 static APTR AllocPageAligned(ULONG *psize, ULONG flags)
180 APTR ret;
181 ULONG size;
183 size = *psize;
184 size += ALLOCPADDING;
185 ret = AllocMem(size + 2 * PAGE_SIZE, flags);
186 D(WriteF("AllocPageAligned: $%X8, %X4 => %X8\n", size + 2 * PAGE_SIZE, flags, ret));
187 if (ret == NULL)
188 return NULL;
189 Forbid();
190 FreeMem(ret, size + 2 * PAGE_SIZE);
191 size = (size + PAGE_SIZE - 1) & PAGE_MASK;
192 ret = AllocAbs(size, (APTR)(((((ULONG)ret) + PAGE_SIZE - 1) & PAGE_MASK)));
193 Permit();
194 if (ret == NULL)
195 return NULL;
196 *psize = size;
197 return ret;
199 static void FreePageAligned(APTR addr, ULONG size)
201 FreeMem(addr, (size + PAGE_SIZE - 1) & PAGE_MASK);
204 /* Define these here for zlib so that we don't
205 * pull in arosc.library.
207 * We can't use AllocVec, since it's only
208 * been around since KS v36
210 void *malloc(int size)
212 ULONG *vec;
214 size += sizeof(ULONG);
216 vec = AllocMem(size, MEMF_ANY);
217 if (vec == NULL) {
218 WriteF("libz: Failed to allocate %N bytes of type %X8\n", size, MEMF_ANY);
219 return NULL;
222 vec[0] = (ULONG)size;
223 return &vec[1];
226 void free(void *ptr)
228 ULONG *vec = ptr - sizeof(ULONG);
229 FreeMem(vec, vec[0]);
232 int open(const char *name, int mode)
234 return (int)Open(name, MODE_OLDFILE);
237 void close(int fd)
239 Close((BPTR)fd);
242 int read(int fd, void *buff, size_t len)
244 return Read((BPTR)fd, buff, (LONG)len);
247 off_t lseek(int fd, off_t offset, int whence)
249 LONG mode = SEEK_SET;
250 LONG err;
252 switch (whence) {
253 case SEEK_CUR: mode = OFFSET_CURRENT; break;
254 case SEEK_SET: mode = OFFSET_BEGINNING; break;
255 case SEEK_END: mode = OFFSET_END; break;
256 default: return -1;
259 err = Seek((BPTR)fd, (LONG)offset, mode);
260 if (err < 0)
261 return -1;
263 return Seek((BPTR)fd, 0, OFFSET_CURRENT);
266 static AROS_UFH4(LONG, aosRead,
267 AROS_UFHA(BPTR, file, D1),
268 AROS_UFHA(void *, buf, D2),
269 AROS_UFHA(LONG, size, D3),
270 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
272 AROS_USERFUNC_INIT
274 return Read(file, buf, (unsigned)size);
276 AROS_USERFUNC_EXIT
278 static AROS_UFH4(LONG, aosSeek,
279 AROS_UFHA(BPTR, file, D1),
280 AROS_UFHA(LONG, pos, D2),
281 AROS_UFHA(LONG, mode, D3),
282 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
284 AROS_USERFUNC_INIT
285 int whence;
286 LONG ret;
287 LONG oldpos;
289 switch (mode) {
290 case OFFSET_CURRENT : whence = SEEK_CUR; break;
291 case OFFSET_END : whence = SEEK_END; break;
292 case OFFSET_BEGINNING: whence = SEEK_SET; break;
293 default: return -1;
296 oldpos = (LONG)Seek(file, 0, SEEK_CUR);
298 ret = (LONG)Seek(file, (z_off_t)pos, whence);
299 if (ret < 0)
300 return -1;
302 return oldpos;
304 AROS_USERFUNC_EXIT
307 static APTR aosAllocMem(ULONG size, ULONG flags, struct ExecBase *SysBase)
309 struct MemList *ml;
310 UBYTE *mem;
312 /* Clear bits 15-0, we're setting memory class explicitly */
313 flags &= ~0x7fff;
315 if (SysBase->LibNode.lib_Version >= 36) {
316 flags |= MEMF_LOCAL | MEMF_REVERSE;
317 } else {
318 flags |= MEMF_CHIP;
321 size += sizeof(struct MemChunk) + sizeof(struct MemList);
322 mem = AllocMem(size, flags);
323 if (mem == NULL) {
324 WriteF("AOS: Failed to allocate %N bytes of type %X8\n", size, flags);
325 meminfo();
326 return NULL;
329 ml = (struct MemList*)(mem + sizeof(struct MemChunk));
330 ml->ml_NumEntries = 1;
331 ml->ml_ME[0].me_Addr = (APTR)mem;
332 ml->ml_ME[0].me_Length = size;
333 AddTail(&mlist, (struct Node*)ml);
335 return &ml[1];
338 static AROS_UFH3(APTR, aosAlloc,
339 AROS_UFHA(ULONG, size, D0),
340 AROS_UFHA(ULONG, flags, D1),
341 AROS_UFHA(struct ExecBase *, SysBase, A6))
343 AROS_USERFUNC_INIT
345 return aosAllocMem(size, flags, SysBase);
347 AROS_USERFUNC_EXIT
349 static AROS_UFH3(void, aosFree,
350 AROS_UFHA(APTR, addr, A1),
351 AROS_UFHA(ULONG, size, D0),
352 AROS_UFHA(struct ExecBase *, SysBase, A6))
354 AROS_USERFUNC_INIT
356 addr -= sizeof(struct MemList);
357 Remove((struct Node*)addr);
358 addr -= sizeof(struct MemChunk);
359 size += sizeof(struct MemChunk) + sizeof(struct MemList);
360 FreeMem(addr, size);
362 AROS_USERFUNC_EXIT
365 /* Backcalls for LoadSegment
366 * using the gzip backend.
368 static AROS_UFH4(LONG, elfRead,
369 AROS_UFHA(BPTR, file, D1),
370 AROS_UFHA(void *, buf, D2),
371 AROS_UFHA(LONG, size, D3),
372 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
374 AROS_USERFUNC_INIT
376 return gzread((gzFile)file, buf, (unsigned)size);
378 AROS_USERFUNC_EXIT
380 static AROS_UFH4(LONG, elfSeek,
381 AROS_UFHA(BPTR, file, D1),
382 AROS_UFHA(LONG, pos, D2),
383 AROS_UFHA(LONG, mode, D3),
384 AROS_UFHA(struct DosLibrary *, DOSBase, A6))
386 AROS_USERFUNC_INIT
387 int whence;
388 LONG ret;
389 LONG oldpos;
391 switch (mode) {
392 case OFFSET_CURRENT : whence = SEEK_CUR; break;
393 case OFFSET_END : whence = SEEK_END; break;
394 case OFFSET_BEGINNING: whence = SEEK_SET; break;
395 default: return -1;
398 oldpos = (LONG)gzseek((gzFile)file, 0, SEEK_CUR);
400 ret = (LONG)gzseek((gzFile)file, (z_off_t)pos, whence);
401 if (ret < 0)
402 return -1;
404 return oldpos;
406 AROS_USERFUNC_EXIT
409 static AROS_UFH3(APTR, elfAlloc,
410 AROS_UFHA(ULONG, size, D0),
411 AROS_UFHA(ULONG, flags, D1),
412 AROS_UFHA(struct ExecBase *, SysBase, A6))
414 AROS_USERFUNC_INIT
415 APTR mem;
416 struct MemList *ml;
418 D(WriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
419 /* Since we don't know if we need to wrap the memory
420 * with the KickMem wrapper until after allocation,
421 * we always adjust the size as if we have to.
423 size += sizeof(struct MemChunk) + sizeof(struct MemList);
425 /* If it's MEMF_LOCAL or MEMF_CHIP, our Exec init
426 * will automatically protect it from allocation after reset.
428 if (flags & MEMF_KICK) {
429 if (SysBase->LibNode.lib_Version < 39) {
430 /* Ok, can't use MEMF_KICK.
431 * Hope and pray that MEMF_FAST is available
432 * after expansion.library is done.
434 flags &= ~MEMF_KICK;
435 flags |= MEMF_FAST;
439 /* Hmm. MEMF_LOCAL is only available on v36 and later.
440 * Use MEMF_CHIP if we have to.
442 if ((flags & MEMF_LOCAL) && (SysBase->LibNode.lib_Version < 36)) {
443 flags &= ~MEMF_LOCAL;
444 flags |= MEMF_CHIP;
447 /* MEMF_31BIT is not available on AOS */
448 if ((flags & MEMF_31BIT)) {
449 flags &= ~MEMF_31BIT;
452 /* If ROM allocation, always allocate from top of memory if possible */
453 if ((flags & MEMF_PUBLIC) && SysBase->LibNode.lib_Version >= 36) {
454 flags |= MEMF_REVERSE;
457 D(WriteF("ELF: Attempt to allocate %N bytes of type %X8\n", size, flags));
458 mem = AllocPageAligned(&size, flags);
459 if (mem == NULL) {
460 D(WriteF("ELF: Failed to allocate %N bytes of type %X8\n", size, flags));
461 meminfo();
462 return NULL;
464 D(WriteF("ELF: Got memory at %X8, size %N\n", (IPTR)mem, size));
466 ml = (struct MemList*)(mem + sizeof(struct MemChunk));
467 ml->ml_NumEntries = 1;
468 ml->ml_ME[0].me_Addr = (APTR)mem;
469 ml->ml_ME[0].me_Length = size;
471 /* Add to the KickMem list */
472 AddTail(&mlist, (struct Node*)ml);
473 D(WriteF("ELF: Got memory at %X8, size %N\n", (IPTR)(&ml[1]), size));
475 return &ml[1];
477 AROS_USERFUNC_EXIT
480 static AROS_UFH3(void, elfFree,
481 AROS_UFHA(APTR, addr, A1),
482 AROS_UFHA(ULONG, size, D0),
483 AROS_UFHA(struct ExecBase *, SysBase, A6))
485 AROS_USERFUNC_INIT
487 /* If not page aligned, and the offset from the page boundary
488 * is the sizeof(MemChunk) + sizeof(MemList) then we can assume
489 * that it was a KickTag protected allocation
491 D(WriteF("ELF: Free memory at %X8, size %N\n", (IPTR)addr, size));
492 addr -= sizeof(struct MemList);
493 Remove((struct Node*)addr);
494 addr -= sizeof(struct MemChunk);
495 size += sizeof(struct MemChunk) + sizeof(struct MemList);
496 D(WriteF("ELF: FREE memory at %X8, size %N\n", (IPTR)addr, size));
497 FreePageAligned(addr, size);
499 AROS_USERFUNC_EXIT
503 * This routine is called from within libloadseg.a's ELF loader.
504 * In dos.library it's responsible for collecting debug information from the loaded file.
505 * Here it does nothing (FIXME ???)
507 void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
512 static BPTR ROMLoad(BSTR bfilename)
514 gzFile gzf;
515 UBYTE *filename;
516 BPTR rom = BNULL;
517 SIPTR funcarray[] = {
518 (SIPTR)elfRead,
519 (SIPTR)elfAlloc,
520 (SIPTR)elfFree,
521 (SIPTR)elfSeek,
523 filename = ConvertBSTR(bfilename);
524 if (!filename)
525 return BNULL;
527 WriteF("Loading '%S' into RAM...\n", bfilename);
528 if ((gzf = gzopen(filename, "rb"))) {
529 gzbuffer(gzf, 65536);
531 rom = LoadSegment((BPTR)gzf, BNULL, funcarray, NULL);
532 if (rom == BNULL) {
533 WriteF("'%S': Can't parse, error %N\n", bfilename, IoErr());
536 gzclose_r(gzf);
537 } else {
538 WriteF("'%S': Can't open\n", bfilename);
540 FreeString(filename);
541 return rom;
544 /* Patch "picasso96/<driver>.chip" -> "<driver>.chip" so that OpenLibrary() finds it */
545 static void RTGPatch(struct Resident *r, BPTR seg)
547 BOOL patched = FALSE;
548 WORD len = strlen(r->rt_Name);
549 const UBYTE *name = r->rt_Name + len - 5;
550 if (len > 5 && (!stricmp(name, ".card") || !stricmp(name, ".chip"))) {
551 BPTR seglist = seg;
552 while (seglist) {
553 ULONG *ptr = BADDR(seglist);
554 LONG len = ptr[-1] - sizeof(BPTR);
555 UBYTE *p = (UBYTE*)(ptr + 1);
556 while (len > 0) {
557 if (len > 16 && !strnicmp(p, "libs:picasso96/", 15)) {
558 memmove(p, p + 15, strlen(p + 15) + 1);
559 patched = TRUE;
560 } else if (len > 10 && !strnicmp(p, "picasso96/", 10)) {
561 memmove(p, p + 10, strlen(p + 10) + 1);
562 patched = TRUE;
564 len--;
565 p++;
567 seglist = *((BPTR*)BADDR(seglist));
570 if (patched)
571 WriteF("Library path patched\n");
574 #define RESLIST_CHUNK 100
575 #define LRF_NOPATCH (1 << 0) /* If set, don't patch the struct Resident */
577 static struct Resident **LoadResident(BPTR seg, struct Resident **reslist, ULONG *resleft, ULONG flags)
579 ULONG *ptr = BADDR(seg);
580 UWORD *res;
581 LONG len = ptr[-1] - sizeof(BPTR);
583 res = (UWORD*)(ptr + 1);
584 while (len >= offsetof(struct Resident, rt_Init) + sizeof(APTR)) {
585 if (*res == RTC_MATCHWORD && ((ULONG*)(res + 1))[0] == (ULONG)res) {
586 struct Resident *r = (struct Resident*)res;
587 if (!(flags & LRF_NOPATCH)) {
588 /* Set RTF_COLDSTART if no initialization flags set */
589 if (!(r->rt_Flags & (RTF_COLDSTART | RTF_SINGLETASK | RTF_AFTERDOS)))
590 r->rt_Flags |= RTF_COLDSTART;
591 if (r->rt_Pri < 10)
592 r->rt_Pri = 10;
593 RTGPatch(r, seg);
596 if (*resleft == 0) {
597 struct Resident **resnew;
598 resnew = aosAllocMem(RESLIST_CHUNK * sizeof(struct Resident*), MEMF_CLEAR, SysBase);
599 if (!resnew)
600 return 0;
602 *reslist = (APTR)((IPTR)resnew | RESLIST_NEXT);
603 reslist = resnew;
604 *resleft = RESLIST_CHUNK - 1;
606 D(WriteF("Resident structure found @%X8\n", r));
607 *(reslist++) = r;
608 (*resleft)--;
610 res++;
611 len -= 2;
614 return reslist;
617 static struct Resident **LoadResidents(BPTR *namearray, struct Resident **resnext, ULONG *resleft)
619 UBYTE i;
620 SIPTR funcarray[] = {
621 (SIPTR)aosRead,
622 (SIPTR)aosAlloc,
623 (SIPTR)aosFree,
624 (SIPTR)aosSeek,
627 for (i = 0; namearray[i]; i++) {
628 LONG stack;
629 BPTR handle;
630 BPTR seglist = BNULL;
631 BPTR bname;
632 UBYTE *name;
634 bname = namearray[i];
635 name = ConvertBSTR(bname);
636 if (name) {
637 handle = Open(name, MODE_OLDFILE);
638 if (handle) {
639 seglist = LoadSegment(handle, BNULL, funcarray, &stack);
640 Close(handle);
642 if (seglist) {
643 BPTR seg;
644 WriteF("Loaded '%S'\n", bname);
645 for (seg = seglist; seg != BNULL; seg = *((BPTR*)BADDR(seg)))
646 resnext = LoadResident(seg, resnext, resleft, 0);
647 } else {
648 WriteF("Failed to load '%S', error %N\n", bname, IoErr());
650 FreeString(name);
654 return resnext;
657 #define FAKEBASE 0x200
658 #define FAKEBASESIZE 558
659 #define COLDCAPTURE (FAKEBASE + FAKEBASESIZE + 16)
661 /* Theory of operation:
663 - create fake sysbase in low chip memory (We can't use original because it is not binary compatible with AROS one)
664 - set correct checksum and point ColdCapture to our routine (also in low chip)
665 - reset the system (autoconfig devices disappear, including most expansion RAM and ROM overlay disables chip RAM)
666 - original ROM code now disables ROM overlay and checks KS checksum and jumps to our ColdCapture routine
667 - above step is needed because in worst case ALL RAM disappear at reset and there
668 are also accelerators that reset the CPU completely when reset instruction is executed.
669 - now we have control again, autoconfig devices are still unconfigured but at least we have chip ram.
670 - jump to AROS ROM code entry point which detects romloader mode and automatically reserves RAM used by "ROM" code
671 - AROS ROM creates new proper execbase and copies ColdCapture
672 - normal boot starts
676 static UWORD GetSysBaseChkSum(struct ExecBase *sysbase)
678 UWORD sum = 0;
679 UWORD *p = (UWORD*)&sysbase->SoftVer;
680 while (p <= &sysbase->ChkSum)
681 sum += *p++;
682 return sum;
685 static ULONG mySumKickData(struct ExecBase *sysbase, BOOL output)
687 ULONG chksum = 0;
688 BOOL isdata = FALSE;
690 if (sysbase->KickTagPtr) {
691 IPTR *list = sysbase->KickTagPtr;
692 while(*list)
694 chksum += (ULONG)*list;
695 #if 0
696 if (output) {
697 WriteF("%X8 %X8\n", list, *list);
698 WriteF("CHK %X8\n", chksum);
700 #endif
702 /* on amiga, if bit 31 is set then this points to another list of
703 * modules rather than pointing to a single module. bit 31 is
704 * inconvenient on architectures where code may be loaded above
705 * 2GB. on these platforms we assume aligned pointers and use bit
706 * 0 instead */
707 #ifdef __mc68000__
708 if(*list & 0x80000000) { list = (IPTR *)(*list & 0x7fffffff); continue; }
709 #else
710 if(*list & 0x1) { list = (IPTR *)(*list & ~(IPTR)0x1); continue; }
711 #endif
712 list++;
713 isdata = TRUE;
717 if (sysbase->KickMemPtr) {
718 struct MemList *ml = (struct MemList*)sysbase->KickMemPtr;
719 while (ml) {
720 UBYTE i;
721 ULONG *p = (ULONG*)ml;
722 for (i = 0; i < sizeof(struct MemList) / sizeof(ULONG); i++)
723 chksum += p[i];
725 #if 0
726 if (output) {
727 WriteF("ML %X8 %X8\n", ml, chksum);
728 WriteF("NODE0 %X8 %X8\n", p[0], p[1]);
729 WriteF("NODE2 %X8 %X8\n", p[2], p[3]);
730 WriteF("ADDR %X8 %X8\n", ml->ml_ME[0].me_Un.meu_Addr, ml->ml_ME[0].me_Length);
731 WriteF("DATA0 %X8 %X8\n", p[6], p[7]);
733 #endif
735 ml = (struct MemList*)ml->ml_Node.ln_Succ;
736 isdata = TRUE;
739 if (isdata && !chksum)
740 chksum--;
741 return chksum;
745 /* reset VBR and switch off MMU */
746 static void setcpu(void)
748 asm(
749 ".chip 68040\n"
750 "move.l 4,%a0\n"
751 "move.w 296(%a0),%d1\n"
752 "moveq #0,%d0\n"
753 "btst #0,%d1\n"
754 "beq.s cpudone\n"
755 /* clear VBR */
756 "movec %d0,%vbr\n"
757 "btst #1,%d1\n"
758 "beq.s cpudone\n"
759 /* disable caches */
760 "movec %d0,%cacr\n"
761 "btst #3,%d1\n"
762 "beq.s not040\n"
763 /* 68040/060 MMU */
764 "movec %d0,%tc\n"
765 "movec %d0,%dtt0\n"
766 "movec %d0,%dtt1\n"
767 "movec %d0,%itt0\n"
768 "movec %d0,%itt1\n"
769 "cpusha %bc\n"
770 "bra.s cpudone\n"
771 "not040: btst #2,%d1\n"
772 "beq.s cpudone\n"
773 /* 68030 MMU */
774 "lea zero(%pc),%a0\n"
775 ".long 0xf0104000\n"
776 ".long 0xf0100c00\n"
777 ".long 0xf0100800\n"
778 "bra.s cpudone\n"
779 "zero: .long 0,0\n"
780 "cpudone:\n"
784 /* This is needed because KS clears ColdCapture before calling it
785 * causing checksum mismatch in AROS exec check
787 void coldcapturecode(void)
789 asm(
790 ".long end - start\n"
791 "start:\n"
792 "bra.s 0f\n"
793 "nop\n" /* Align to start + 4 */
794 ".long 0x46414b45\n" /* AROS_MAKE_ID('F','A','K','E') */
795 "0:\n"
796 "move.w #0x440,0xdff180\n"
797 "clr.l 0.w\n"
798 "lea 0x200,%a0\n"
799 "move.l (%a0),0x7c.w\n" // restore NMI
800 "lea 12(%a0),%a0\n"
801 "move.l %a0,4.w\n"
802 "lea start(%pc),%a1\n"
803 "move.l %a1,42(%a0)\n" // ColdCapture
804 "move.l %a0,%d0\n"
805 "not.l %d0\n"
806 "move.l %d0,38(%a0)\n" // ChkBase
807 "moveq #0,%d1\n"
808 "lea 34(%a0),%a0\n"
809 "moveq #24-1,%d0\n"
810 "chk1: add.w (%a0)+,%d1\n"
811 "dbf %d0,chk1\n"
812 "not.w %d1\n"
813 "move.w %d1,(%a0)\n" // ChkSum
814 "move.l start-4(%pc),%a0\n"
815 "jmp (%a0)\n"
816 "end:\n"
820 /* Official reboot code from HRM
821 * All CPUs have at least 1 word prefetch,
822 * jmp (a0) has been prefetched even if
823 * reset disables all memory
825 static void doreboot(void)
827 asm volatile (
828 "lea 0x01000000,%a0\n"
829 "sub.l %a0@(-0x14),%a0\n"
830 "move.l %a0@(4),%a0\n"
831 "subq.l #2,%a0\n"
832 ".balign 8\n" /* Workaround for E-UAE emulation bug */
833 "reset\n"
834 "jmp (%a0)\n"
838 APTR entry, kicktags;
839 struct TagItem *kerneltags;
841 static void supercode(void)
843 ULONG *fakesys, *coldcapture, *coldcapturep;
844 struct ExecBase *sysbase;
845 ULONG *traps = 0;
846 ULONG len;
848 if ((SysBase->AttnFlags & 0xff) != 0)
849 setcpu();
851 fakesys = (ULONG*)FAKEBASE;
852 coldcapture = (ULONG*)COLDCAPTURE;
853 coldcapture[-1] = (ULONG)entry;
854 coldcapturep = (ULONG*)coldcapturecode;
855 len = *coldcapturep++;
856 memcpy (coldcapture, coldcapturep, len);
858 *fakesys++ = traps[31]; // Level 7
859 *fakesys++ = 0x4ef9 | (COLDCAPTURE >> 16);
860 *fakesys++ = (COLDCAPTURE << 16) | 0x4e75;
861 sysbase = (struct ExecBase*)fakesys;
863 memset(sysbase, 0, FAKEBASESIZE);
864 /* Misuse DebugData as a kernel tag pointer,
866 if (kerneltags)
867 sysbase->DebugData = kerneltags;
869 /* Detached node */
870 sysbase->LibNode.lib_Node.ln_Pred = &sysbase->LibNode.lib_Node;
871 sysbase->LibNode.lib_Node.ln_Succ = &sysbase->LibNode.lib_Node;
873 /* Set up cold capture */
874 sysbase->ColdCapture = coldcapture;
875 sysbase->MaxLocMem = 512 * 1024;
876 sysbase->ChkBase =~(IPTR)sysbase;
877 sysbase->ChkSum = GetSysBaseChkSum(sysbase) ^ 0xffff;
879 /* Propogate the existing OS's Kick Data */
880 if (mlist.lh_Head->ln_Succ) {
881 sysbase->KickMemPtr = (APTR)mlist.lh_Head;
882 mlist.lh_TailPred->ln_Succ = SysBase->KickMemPtr;
883 } else {
884 sysbase->KickMemPtr = (APTR)SysBase->KickMemPtr;
886 if (kicktags) {
887 sysbase->KickTagPtr = kicktags;
888 if (SysBase->KickTagPtr) {
889 ULONG *p = kicktags;
890 while (*p)
891 p++;
892 *p = 0x80000000 | (ULONG)SysBase->KickTagPtr;
894 } else {
895 sysbase->KickTagPtr = SysBase->KickTagPtr;
897 sysbase->KickCheckSum = (APTR)mySumKickData(sysbase, FALSE);
899 traps[1] = (IPTR)sysbase;
900 // TODO: add custom cacheclear, can't call CacheClearU() because it may not work
901 // anymore and KS 1.x does not even have it
902 doreboot();
905 void BootROM(BPTR romlist, struct Resident **reslist, struct TagItem *tags)
907 APTR GfxBase;
909 entry = BADDR(romlist)+sizeof(ULONG);
910 kicktags = reslist;
911 kerneltags = tags;
913 #if 0
914 /* Debug testing code */
915 if (mlist.lh_Head->ln_Succ) {
916 SysBase->KickMemPtr = (APTR)mlist.lh_Head;
917 mlist.lh_TailPred->ln_Succ = NULL;
919 if (kicktags) {
920 SysBase->KickTagPtr = kicktags;
922 mySumKickData(SysBase, TRUE);
923 SysBase->KickTagPtr = 0;
924 SysBase->KickMemPtr = 0;
925 Delay(200);
926 #endif
928 if ((GfxBase = OpenLibrary("graphics.library", 0))) {
929 LoadView(NULL);
930 WaitTOF();
931 WaitTOF();
932 CloseLibrary(GfxBase);
935 /* We're off in the weeds now. */
936 Disable();
938 Supervisor((ULONG_FUNC)supercode);
941 #define KERNELTAGS_SIZE 10
942 #define CMDLINE_SIZE 512
944 static struct TagItem *AllocKernelTags(UBYTE *cmdline)
946 struct TagItem *tags;
947 UBYTE *cmd;
949 tags = aosAllocMem(sizeof(struct TagItem) * KERNELTAGS_SIZE + CMDLINE_SIZE, MEMF_CLEAR, SysBase);
950 if (!tags)
951 return NULL;
952 cmd = (UBYTE*)(tags + KERNELTAGS_SIZE);
953 /* cmdline is a BCPL string! */
954 if (cmdline && cmdline[0])
955 CopyMem(cmdline + 1, cmd, cmdline[0]);
956 else
957 strcpy(cmd, DEFAULT_KERNEL_CMDLINE);
958 tags[0].ti_Tag = KRN_CmdLine;
959 tags[0].ti_Data = (IPTR)cmd;
960 tags[1].ti_Tag = TAG_DONE;
961 return tags;
964 __startup static AROS_ENTRY(int, startup,
965 AROS_UFHA(char *, argstr, A0),
966 AROS_UFHA(ULONG, argsize, D0),
967 struct ExecBase *, SysBase)
969 AROS_USERFUNC_INIT
971 /* See if we're already running on AROS.
973 if (OpenResource("kernel.resource"))
974 return RETURN_OK;
976 NEWLIST(&mlist);
977 DOSBase = (APTR)OpenLibrary("dos.library", 0);
978 if (DOSBase != NULL) {
979 BPTR ROMSegList;
980 BSTR name = AROS_CONST_BSTR("aros.elf.gz");
981 enum { ARG_ROM = 16, ARG_CMD = 17, ARG_MODULES = 0 };
982 /* It would be nice to use the '/M' switch, but that
983 * is not supported under the AOS BCPL RdArgs routine.
985 * So only 16 modules are supported
987 BSTR format = AROS_CONST_BSTR(",,,,,,,,,,,,,,,,ROM/K,CMD/K");
988 /* Make sure the args are in .bss, not stack */
989 static ULONG args[16 + 2 + 256] __attribute__((aligned(4))) = { };
991 WriteF("AROSBootstrap " ADATE "\n");
992 args[0] = name;
994 RdArgs(format, MKBADDR(args), sizeof(args)/sizeof(args[0]));
995 #if DEBUG
996 WriteF("ROM: %S\n", args[ARG_ROM]);
997 WriteF("CMD: %S\n", args[ARG_CMD]);
998 WriteF("MOD: %S\n", args[0]);
999 WriteF(" : %S\n", args[1]);
1000 WriteF(" : %S\n", args[2]);
1001 WriteF(" : %S\n", args[3]);
1003 #endif
1004 meminfo();
1006 if (!IoErr()) {
1007 /* Load ROM image */
1008 if (args[ARG_ROM] == BNULL)
1009 args[ARG_ROM] = name;
1011 ROMSegList = ROMLoad(args[ARG_ROM]);
1012 if (ROMSegList != BNULL) {
1013 ULONG resleft = 0;
1014 struct Resident **ResidentList;
1015 struct TagItem *KernelTags;
1016 WriteF("Successfully loaded ROM\n");
1017 ROM_Loaded = TRUE;
1018 struct Resident **resnext, *reshead = NULL;
1020 resnext = &reshead;
1021 /* Only scan the 2nd section of the ROM segment */
1022 resnext = LoadResident(*((BPTR *)BADDR(ROMSegList)), resnext, &resleft, LRF_NOPATCH);
1023 resnext = LoadResidents(&args[ARG_MODULES], resnext, &resleft);
1024 KernelTags = AllocKernelTags(BADDR(args[ARG_CMD]));
1026 WriteF("Booting...\n");
1027 Delay(50);
1029 ResidentList = (APTR)((IPTR)reshead & ~RESLIST_NEXT);
1030 BootROM(ROMSegList, ResidentList, KernelTags);
1032 UnLoadSeg(ROMSegList);
1033 } else {
1034 WriteF("Can't load ROM ELF file %S\n", args[ARG_ROM]);
1036 } else {
1037 WriteF("Can't parse arguments, error %N\n", IoErr());
1040 CloseLibrary((APTR)DOSBase);
1043 return IoErr();
1045 AROS_USERFUNC_EXIT