revert between 56095 -> 55830 in arch
[AROS.git] / arch / m68k-amiga / boot / start.c
blobae3cac4d0cec09c4a42fd06b9c4234e36eed4f27
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: m68k-amiga bootstrap to exec.
6 Lang: english
7 */
9 #define DEBUG 0
10 #include <aros/debug.h>
12 #include <aros/kernel.h>
13 #include <exec/memory.h>
14 #include <exec/resident.h>
15 #include <exec/execbase.h>
16 #include <proto/exec.h>
17 #include <hardware/cpu/memory.h>
19 #include "memory.h"
21 #include "kernel_romtags.h"
22 #include "kernel_base.h"
24 #define __AROS_KERNEL__
25 #include "exec_intern.h"
27 #include "amiga_hwreg.h"
28 #include "amiga_irq.h"
30 #include "early.h"
31 #include "debug.h"
33 #define SS_STACK_SIZE 0x02000
35 static BOOL iseven(APTR p)
37 return (((ULONG)p) & 1) == 0;
40 struct BootStruct *GetBootStruct(struct ExecBase *eb)
42 if (!iseven(eb))
43 return NULL;
44 ULONG *coldcapture = eb->ColdCapture;
45 if (coldcapture && iseven(coldcapture) && coldcapture[1] == AROS_MAKE_ID('F','A','K','E')) {
46 struct BootStruct *BootS = (struct BootStruct*)(coldcapture[2]);
47 if (BootS->magic == ABS_BOOT_MAGIC)
48 return BootS;
50 return NULL;
53 #if 0
54 static void dumpmemory(struct MemHeader *mh)
56 struct MemChunk *mc = mh->mh_First;
57 DEBUGPUTS(("\n"));
58 DEBUGPUTS((mh->mh_Node.ln_Name));
59 DEBUGPUTS(("\n"));
60 DEBUGPUTHEX(("Addr : ", (ULONG)mh));
61 DEBUGPUTHEX(("Attrs: ", (ULONG)mh->mh_Attributes));
62 DEBUGPUTHEX(("Lower: ", (ULONG)mh->mh_Lower));
63 DEBUGPUTHEX(("Upper: ", (ULONG)mh->mh_Upper));
64 DEBUGPUTHEX(("Free : ", (ULONG)mh->mh_Free));
65 DEBUGPUTHEX(("First: ", (ULONG)mc));
66 while (mc) {
67 DEBUGPUTHEX(("Next : ", (ULONG)mc->mc_Next));
68 DEBUGPUTHEX(("Bytes: ", (ULONG)mc->mc_Bytes));
69 mc = mc->mc_Next;
72 static void dumpallmemory(struct ExecBase *SysBase)
74 struct MemHeader *node;
75 ForeachNode (&SysBase->MemList, node) {
76 dumpmemory(node);
79 #endif
81 extern const struct Resident Exec_resident;
82 extern struct ExecBase *AbsExecBase;
84 extern void __attribute__((interrupt)) Exec_Supervisor_Trap (void);
85 extern void __attribute__((interrupt)) Exec_Supervisor_Trap_00 (void);
87 #define _AS_STRING(x) #x
88 #define AS_STRING(x) _AS_STRING(x)
90 /* Create a sign extending call stub:
91 * foo:
92 * jsr AROS_SLIB_ENTRY(funcname, libname, funcid)
93 * 0x4eb9 .... ....
94 * ext.w %d0 // EXT_BYTE only
95 * 0x4880
96 * ext.l %d0 // EXT_BYTE and EXT_WORD
97 * 0x48c0
98 * rts
99 * 0x4e75
101 #define EXT_BYTE(lib, libname, funcname, funcid) \
102 do { \
103 void libname##_##funcname##_Wrapper(void) \
104 { asm volatile ( \
105 "jsr " AS_STRING(AROS_SLIB_ENTRY(funcname, libname, funcid)) "\n" \
106 "ext.w %d0\n" \
107 "ext.l %d0\n" \
108 "rts\n"); } \
109 /* Insert into the library's jumptable */ \
110 __AROS_SETVECADDR(lib, funcid, libname##_##funcname##_Wrapper); \
111 } while (0)
112 #define EXT_WORD(lib, libname, funcname, funcid) \
113 do { \
114 void libname##_##funcname##_Wrapper(void) \
115 { asm volatile ( \
116 "jsr " AS_STRING(AROS_SLIB_ENTRY(funcname, libname, funcid)) "\n" \
117 "ext.l %d0\n" \
118 "rts\n"); } \
119 /* Insert into the library's jumptable */ \
120 __AROS_SETVECADDR(lib, funcid, libname##_##funcname##_Wrapper); \
121 } while (0)
123 * Create a register preserving call stub:
124 * foo:
125 * movem.l %d0-%d1/%a0-%a1,%sp@-
126 * 0x48e7 0xc0c0
127 * jsr AROS_SLIB_ENTRY(funcname, libname, funcid)
128 * 0x4eb9 .... ....
129 * movem.l %sp@+,%d0-%d1/%d0-%a1
130 * 0x4cdf 0x0303
131 * rts
132 * 0x4e75
134 #define PRESERVE_ALL(lib, libname, funcname, funcid) \
135 do { \
136 void libname##_##funcname##_Wrapper(void) \
137 { asm volatile ( \
138 "movem.l %d0-%d1/%a0-%a1,%sp@-\n" \
139 "jsr " AS_STRING(AROS_SLIB_ENTRY(funcname, libname, funcid)) "\n" \
140 "movem.l %sp@+,%d0-%d1/%a0-%a1\n" \
141 "rts\n" ); } \
142 /* Insert into the library's jumptable */ \
143 __AROS_SETVECADDR(lib, funcid, libname##_##funcname##_Wrapper); \
144 } while (0)
145 /* Inject arbitrary code into the jump table
146 * Used for GetCC and nano-stubs
148 #define FAKE_IT(lib, libname, funcname, funcid, ...) \
149 do { \
150 UWORD *asmcall = (UWORD *)__AROS_GETJUMPVEC(lib, funcid); \
151 const UWORD code[] = { __VA_ARGS__ }; \
152 asmcall[0] = code[0]; \
153 asmcall[1] = code[1]; \
154 asmcall[2] = code[2]; \
155 } while (0)
156 /* Inject a 'move.w #value,%d0; rts" sequence into the
157 * jump table, to fake an private syscall.
159 #define FAKE_ID(lib, libname, funcname, funcid, value) \
160 FAKE_IT(lib, libname, funcname, funcid, 0x303c, value, 0x4e75)
162 extern void SuperstackSwap(void);
163 /* This calls the register-ABI library
164 * routine Exec/InitCode, for use in NewStackSwap()
166 static LONG doInitCode(struct BootStruct *BootS)
168 /* Attempt to allocate a new supervisor stack */
169 do {
170 APTR ss_stack;
171 ULONG ss_stack_size;
172 if (BootS && BootS->ss_address) {
173 ss_stack = BootS->ss_address;
174 ss_stack_size = BootS->ss_size;
175 DEBUGPUTS(("Using AROSBootStrap SS Stack"));
176 } else {
177 ss_stack = AllocMem(SS_STACK_SIZE, MEMF_ANY | MEMF_CLEAR | MEMF_REVERSE);
178 if (ss_stack && ((ULONG)ss_stack & (PAGE_SIZE - 1))) {
179 /* Normally ss_stack is page aligned because it is first MEMF_REVERSE
180 * allocation. But we must check it because enabled mungwall or expansion
181 * boot rom code can allocate some memory.
183 FreeMem(ss_stack, SS_STACK_SIZE);
184 ss_stack = AllocMem(SS_STACK_SIZE + PAGE_SIZE - 1, MEMF_ANY | MEMF_CLEAR | MEMF_REVERSE);
185 ss_stack = (APTR)(((ULONG)ss_stack + PAGE_SIZE - 1) & PAGE_MASK);
187 ss_stack_size = SS_STACK_SIZE;
189 DEBUGPUTHEX(("SS lower", (ULONG)ss_stack));
190 DEBUGPUTHEX(("SS upper", (ULONG)ss_stack + ss_stack_size - 1));
191 if (ss_stack == NULL) {
192 DEBUGPUTS(("PANIC! Can't allocate a new system stack!\n"));
193 Early_Alert(CODE_ALLOC_FAIL);
194 break;
196 SysBase->SysStkLower = ss_stack;
197 SysBase->SysStkUpper = ss_stack + ss_stack_size;
198 SetSysBaseChkSum();
200 Supervisor((ULONG_FUNC)SuperstackSwap);
201 } while(0);
203 /* Move boot tags from temp supervisor stack. MMU debugging will detect access fault later if not moved. */
204 if (PrivExecBase(SysBase)->PlatformData.BootMsg && TypeOfMem(PrivExecBase(SysBase)->PlatformData.BootMsg) == 0) {
205 UWORD size = 0;
206 struct TagItem *bootmsg, *newbootmsg;
208 bootmsg = PrivExecBase(SysBase)->PlatformData.BootMsg;
209 while (bootmsg[size].ti_Tag)
210 size++;
211 newbootmsg = AllocMem(sizeof(struct TagItem) * (size + 1), MEMF_CLEAR | MEMF_PUBLIC);
212 if (newbootmsg) {
213 size = 0;
214 bootmsg = PrivExecBase(SysBase)->PlatformData.BootMsg;
215 while (bootmsg[size].ti_Tag) {
216 newbootmsg[size].ti_Tag = bootmsg[size].ti_Tag;
217 newbootmsg[size].ti_Data = bootmsg[size].ti_Data;
218 size++;
221 PrivExecBase(SysBase)->PlatformData.BootMsg = newbootmsg;
224 InitCode(RTF_COLDSTART, 0);
226 return 0;
229 extern BYTE _rom_start;
230 extern BYTE _rom_end;
231 extern BYTE _ext_start;
232 extern BYTE _ext_end;
233 extern BYTE _ss;
234 extern BYTE _ss_end;
236 static BOOL IsSysBaseValidNoVersion(struct ExecBase *sysbase)
238 if (!iseven(sysbase))
239 return FALSE;
240 if (sysbase == NULL || (((ULONG)sysbase) & 0x80000001))
241 return FALSE;
242 if (sysbase->ChkBase != ~(IPTR)sysbase)
243 return FALSE;
244 return GetSysBaseChkSum(sysbase) == 0xffff;
247 #define KICKMEM_MASK 0xc0000000
248 #define KICKMEM_ALLOCATED 0x80000000
249 /* Use following if loaded to memory that is not autoconfig or autodetect */
250 #define KICMMEM_DONOTALLOCATE 0x40000000
252 static void resetKickMem(struct BootStruct *bs)
254 struct MemList *ml;
255 WORD i;
257 if (bs == NULL)
258 return;
259 /* Mark as unallocated.
260 * This list is guaranteed to be located in memory
261 * that is immediately available after reset.
263 ForeachNode(bs->mlist, ml) {
264 for(i = 0; i < ml->ml_NumEntries; i++) {
265 ml->ml_ME[i].me_Length &= ~KICKMEM_ALLOCATED;
269 static void allocKickMem(struct ExecBase *SysBase, struct BootStruct *bs, struct MemHeader *mh, UWORD phase)
271 struct MemList *ml;
272 BOOL panic = FALSE;
273 WORD i;
275 if (phase > 0)
276 bs = GetBootStruct(SysBase);
277 if (bs == NULL)
278 return;
279 DEBUGPUTHEX(("KickMem allocation", phase));
280 ForeachNode(bs->mlist, ml) {
281 DEBUGPUTHEX(("Type ", ml->ml_Node.ln_Type));
282 for(i = 0; i < ml->ml_NumEntries; i++) {
283 WORD ok = -1;
284 APTR start = ml->ml_ME[i].me_Addr;
285 ULONG len = ml->ml_ME[i].me_Length;
286 DEBUGPUTHEX(("Address", (ULONG)start));
287 DEBUGPUTHEX(("Length ", len & ~KICKMEM_MASK));
288 if (len & KICKMEM_ALLOCATED) {
289 DEBUGPUTS(("-> already allocated\n"));
290 continue;
292 if (len & KICMMEM_DONOTALLOCATE) {
293 DEBUGPUTS(("-> pre-reserved\n"));
294 continue;
296 if (phase > 0) {
297 if (TypeOfMem(start) == 0) {
298 if (phase == 2) {
299 DEBUGPUTS(("PANIC! Allocation still not in system pool!\n"));
300 panic = TRUE;
301 } else {
302 DEBUGPUTS(("-> Not in system pool yet\n"));
304 ok = -2;
305 } else {
306 ok = InternalAllocAbs(start, len, SysBase) != 0 ? 1 : 0;
308 } else {
309 if (start >= mh->mh_Lower && start < mh->mh_Upper) {
310 ok = Early_AllocAbs(mh, start, len) != 0 ? 1 : 0;
313 if (ok > 0) {
314 DEBUGPUTS(("-> Allocated\n"));
315 ml->ml_ME[i].me_Length |= KICKMEM_ALLOCATED;
316 } else if (ok == 0) {
317 DEBUGPUTS(("PANIC! Early ROM memory allocation failed!\n"));
318 DEBUGPUTHEX(("LOWER ", (ULONG)mh->mh_Lower));
319 DEBUGPUTHEX(("UPPER ", (ULONG)mh->mh_Upper));
320 panic = TRUE;
321 } else if (ok == -1) {
322 DEBUGPUTS(("-> Not yet available\n"));
326 if (panic)
327 Early_Alert(AT_DeadEnd | AN_MemoryInsane);
328 if (phase == 2) {
329 DEBUGPUTS(("KickMem allocation complete\n"));
330 resetKickMem(bs);
334 static struct MemHeader *addmemoryregion(ULONG startaddr, ULONG size, struct BootStruct *bs, BOOL magicfast)
336 if (size < 65536)
337 return NULL;
338 if (magicfast) {
339 krnCreateMemHeader("magic fast memory", -8,
340 (APTR)startaddr, size,
341 MEMF_FAST | MEMF_PUBLIC | ((startaddr & 0xff000000) == 0 ? MEMF_24BITDMA : 0));
342 } else if (startaddr < 0x00c00000) {
343 krnCreateMemHeader("chip memory", -10,
344 (APTR)startaddr, size,
345 MEMF_CHIP | MEMF_KICK | MEMF_PUBLIC | MEMF_LOCAL | MEMF_24BITDMA);
346 } else {
347 krnCreateMemHeader("memory", -5,
348 (APTR)startaddr, size,
349 MEMF_FAST | MEMF_KICK | MEMF_PUBLIC | MEMF_LOCAL | ((startaddr & 0xff000000) == 0 ? MEMF_24BITDMA : 0));
351 DEBUGPUTS(("Added memory header:\n"));
352 DEBUGPUTHEX(("Lower", startaddr));
353 DEBUGPUTHEX(("Upper", startaddr + size));
354 allocKickMem(NULL, bs, (struct MemHeader*)startaddr, 0);
355 return (struct MemHeader*)startaddr;
358 /* Called after autoconfig. Autoconfig RAM is now available */
359 void InitKickMem(struct ExecBase *SysBase)
361 allocKickMem(SysBase, NULL, NULL, 1);
363 /* Called after diag module. Diag ROM enabled RAM is now available */
364 void InitKickMemDiag(struct ExecBase *SysBase)
366 allocKickMem(SysBase, NULL, NULL, 2);
369 static void dumpres(struct Resident **reslist)
371 #if AROS_SERIAL_DEBUG
372 while (*reslist) {
373 struct Resident *RomTag = *reslist++;
374 bug("* %p: %4d %02x %3d \"%s\"\n",
375 RomTag,
376 RomTag->rt_Pri,
377 RomTag->rt_Flags,
378 RomTag->rt_Version,
379 RomTag->rt_Name);
381 #endif
384 static ULONG countres(struct Resident **reslist)
386 ULONG cnt = 0;
387 while (*reslist) {
388 if (((ULONG)(*reslist)) & RESLIST_NEXT) {
389 reslist = (struct Resident**)(((ULONG)(*reslist)) & ~RESLIST_NEXT);
390 continue;
392 cnt++;
393 reslist++;
395 return cnt;
398 static struct Resident **copyres(struct Resident **start, struct Resident **newreslist, struct Resident **oldreslist)
400 while (*oldreslist) {
401 struct Resident *r;
402 if (((ULONG)(*oldreslist)) & RESLIST_NEXT) {
403 oldreslist = (struct Resident**)(((ULONG)(*oldreslist)) & ~RESLIST_NEXT);
404 continue;
406 r = *oldreslist;
407 /* Copy only if Resident appears to be accessible */
408 if (r->rt_MatchWord == RTC_MATCHWORD && r->rt_MatchTag == r) {
409 /* If same Resident is already in list, select higher version/priority */
410 BOOL skip = FALSE;
411 ULONG i;
412 for (i = 0; start[i] != NULL; i++) {
413 struct Resident *r2 = start[i];
414 if (!strcmp(r->rt_Name, r2->rt_Name)) {
415 if (r->rt_Version < r2->rt_Version ||
416 (r->rt_Version == r2->rt_Version && r->rt_Pri <= r2->rt_Pri)) {
417 skip = TRUE;
418 } else {
419 *oldreslist = r2;
420 skip = TRUE;
424 if (!skip) {
425 *newreslist++ = r;
426 *newreslist = NULL;
429 oldreslist++;
431 *newreslist = NULL;
432 return newreslist;
435 /* Find remaining residents after autoconfig because part of our ROM image
436 * may have been located in autoconfig RAM that disappeared after reset.
437 * Scan all memory lists, even if memory is not yet allocated, all memory
438 * is mapped at this point but it may not be in system memory list. Yet.
440 static void CollectKickResidents(struct BootStruct *BootS, struct ExecBase *SysBase)
442 ULONG oldtotal, newtotal, total;
443 BOOL sorted;
444 struct Resident **reslist, **resend;
446 newtotal = countres(BootS->reslist);
447 if (!newtotal)
448 return;
449 oldtotal = countres(SysBase->ResModules);
450 total = newtotal + oldtotal;
451 DEBUGPUTHEX(("OldRes", oldtotal));
452 DEBUGPUTHEX(("NewRes", newtotal));
453 DEBUGPUTHEX(("Total ", total));
454 reslist = AllocMem(sizeof(struct Resident*) * (total + 1), MEMF_PUBLIC);
455 if (!reslist)
456 return;
457 *reslist = NULL;
458 resend = copyres(reslist, reslist, SysBase->ResModules);
459 resend = copyres(reslist, resend, BootS->reslist);
460 total = resend - reslist;
461 DEBUGPUTHEX(("Total2", total));
464 WORD i;
465 sorted = TRUE;
466 for (i = 0; i < total - 1; i++) {
467 if (reslist[i]->rt_Pri < reslist[i + 1]->rt_Pri) {
468 struct Resident *tmp;
469 tmp = reslist[i + 1];
470 reslist[i + 1] = reslist[i];
471 reslist[i] = tmp;
472 sorted = FALSE;
475 } while (!sorted);
476 dumpres(reslist);
477 SysBase->ResModules = reslist;
480 #if 0 // debug stuff, do not remove
481 static ULONG SumKickDataX(struct ExecBase *sb)
483 ULONG chksum = 0;
484 BOOL isdata = FALSE;
485 struct ExecBase *sysbase = sb;
487 if (sysbase->KickTagPtr) {
488 IPTR *list = sysbase->KickTagPtr;
489 while(*list)
491 chksum += (ULONG)*list;
492 DEBUGPUTHEX(("LIST", (ULONG)list));
493 DEBUGPUTHEX(("LISTP", (ULONG)*list));
494 DEBUGPUTHEX(("CHK", chksum));
495 if(*list & RESLIST_NEXT) { list = (IPTR *)(*list & ~RESLIST_NEXT); continue; }
496 list++;
497 isdata = TRUE;
501 if (sysbase->KickMemPtr) {
502 struct MemList *ml = (struct MemList*)sysbase->KickMemPtr;
503 while (ml) {
504 UBYTE i;
505 ULONG *p = (ULONG*)ml;
506 for (i = 0; i < sizeof(struct MemList) / sizeof(ULONG); i++)
507 chksum += p[i];
508 DEBUGPUTHEX(("MEM", (ULONG)p));
509 DEBUGPUTHEX(("CHK", chksum));
510 ml = (struct MemList*)ml->ml_Node.ln_Succ;
511 isdata = TRUE;
514 if (isdata && !chksum)
515 chksum--;
516 return chksum;
518 #endif
520 void doColdCapture(void)
522 APTR ColdCapture = SysBase->ColdCapture;
524 if (ColdCapture == NULL)
525 return;
526 if (GetBootStruct(SysBase)) {
527 /* Fake SysBase installed by AROSBootstrap.
529 * In this case, ColdCapture is the trampoline executed
530 * by the AOS ROM to get into AROS. We need to keep
531 * ColdCapture around in AROS SysBase, but we don't
532 * want to execute it (and cause an infinite loop).
534 DEBUGPUTS(("[ColdCapture] Ignoring AOS->AROS trampoline\n"));
535 return;
538 SysBase->ColdCapture = NULL;
539 /* ColdCapture calling method is a little
540 * strange. It's in supervisor mode, requires
541 * the return location in A5, and SysBase in A6.
543 asm volatile (
544 "move.l %0,%%a0\n"
545 "move.l %1,%%a6\n"
546 "move.l #0f,%%a5\n"
547 "jmp (%%a0)\n"
548 "0:\n"
550 : "m" (ColdCapture), "m" (SysBase)
551 : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
552 "a0", "a1", "a2", "a3", "a4", "a5", "a6");
555 static void RomInfo(IPTR rom)
557 #if AROS_SERIAL_DEBUG && (DEBUG > 0)
558 APTR ptr = (APTR)rom;
559 CONST_STRPTR str;
561 if ((*(UWORD *)(ptr + 8) == 0x0000) &&
562 (*(UWORD *)(ptr + 10) == 0xffff) &&
563 (*(UWORD *)(ptr + 12) == *(UWORD *)(ptr + 16)) &&
564 (*(UWORD *)(ptr + 14) == *(UWORD *)(ptr + 18)) &&
565 (*(UWORD *)(ptr + 20) == 0xffff) &&
566 (*(UWORD *)(ptr + 22) == 0xffff)) {
567 DEBUGPUTHEX(("ROM Location", rom));
568 DEBUGPUTD((" Version", *(UWORD *)(ptr + 12)));
569 DEBUGPUTD((" Revision", *(UWORD *)(ptr + 14)));
570 str = (ptr + 24);
571 DEBUGPUTS((" ROM Type: ")); DEBUGPUTS((str)); DEBUGPUTS(("\n"));
572 str += strlen(str) + 1;
573 DEBUGPUTS((" Copyright: ")); DEBUGPUTS((str));
574 str += strlen(str) + 1;
575 DEBUGPUTS((str));
576 str += strlen(str) + 1;
577 DEBUGPUTS((str));
578 DEBUGPUTS(("\n"));
579 str += strlen(str) + 1;
580 DEBUGPUTS((" ROM Model: ")); DEBUGPUTS((str));
581 DEBUGPUTS(("\n"));
583 #endif
586 static UWORD GetAttnFlags(ULONG *cpupcr)
588 /* Convert CPU/FPU flags to AttnFlags */
589 UWORD attnflags = cpupcr[0] & 0xffff;
590 if (attnflags & (AFF_68030 | AFF_68040 | AFF_68060 | AFF_68080))
591 attnflags |= AFF_ADDR32;
592 if (cpupcr[0] & 0xffff0000) {
593 attnflags |= AFF_FPU;
594 if (attnflags & (AFF_68040 | AFF_68060))
595 attnflags |= AFF_FPU40;
596 // AFF_68881 | AFF_68882 set only if 040/060 math emulation running
597 else if (((cpupcr[0] >> 16) & 0xff) <= 0x1f)
598 attnflags |= AFF_68881;
599 else
600 attnflags |= AFF_68881 | AFF_68882;
603 #if AROS_SERIAL_DEBUG && (DEBUG > 0)
604 DEBUGPUTS(("CPU: "));
605 if (attnflags & AFF_68080)
606 DEBUGPUTS(("Apollo Core 68080"));
607 else if (attnflags & AFF_68060)
608 DEBUGPUTS(("68060"));
609 else if (attnflags & AFF_68040)
610 DEBUGPUTS(("68040"));
611 else if (attnflags & AFF_68030)
612 DEBUGPUTS(("68030"));
613 else if (attnflags & AFF_68020) {
614 if (attnflags & AFF_ADDR32)
615 DEBUGPUTS(("68020"));
616 else
617 DEBUGPUTS(("68EC020"));
618 } else if (attnflags & AFF_68010)
619 DEBUGPUTS(("68010"));
620 else
621 DEBUGPUTS(("68000"));
622 DEBUGPUTS((" FPU: "));
623 if (attnflags & AFF_FPU40) {
624 if (attnflags & AFF_68060)
625 DEBUGPUTS(("68060"));
626 else if (attnflags & AFF_68040)
627 DEBUGPUTS(("68040"));
628 else
629 DEBUGPUTS(("-"));
630 } else if (attnflags & AFF_68882)
631 DEBUGPUTS(("68882"));
632 else if (attnflags & AFF_68881)
633 DEBUGPUTS(("68881"));
634 else
635 DEBUGPUTS(("-"));
636 DEBUGPUTS(("\n"));
637 if (cpupcr[1])
638 DEBUGPUTHEX(("PCR", cpupcr[1]));
639 #endif
640 return attnflags;
643 void exec_boot(ULONG *membanks, ULONG *cpupcr)
645 struct TagItem bootmsg[] = {
646 /* nomonitors - Until we have working m68k PCI support,
647 * attempting to load the monitor drivers
648 * just wastes a lot of time during boot
650 #if AROS_SERIAL_DEBUG
651 { KRN_CmdLine, (IPTR)"nomonitors sysdebug=InitCode" },
652 // { KRN_CmdLine, (IPTR)"nomonitors sysdebug=InitCode,debugmmu,mungwall" },
653 #else
654 { KRN_CmdLine, (IPTR)"nomonitors" },
655 #endif
656 { KRN_KernelStackBase, (IPTR)&_ss },
657 { KRN_KernelStackSize, (IPTR)(&_ss_end - &_ss) },
658 { TAG_END },
660 struct TagItem *bootmsgptr = bootmsg;
661 volatile APTR *trap;
662 int i;
663 BOOL wasvalid, arosbootstrapmode;
664 UWORD *kickrom[8];
665 struct MemHeader *mh;
666 LONG oldLastAlert[4];
667 ULONG oldmem;
668 UWORD attnflags;
669 APTR ColdCapture = NULL, CoolCapture = NULL, WarmCapture = NULL;
670 APTR KickMemPtr = NULL, KickTagPtr = NULL, KickCheckSum = NULL;
671 struct BootStruct *BootS = NULL;
672 /* We can't use the global 'SysBase' symbol, since
673 * the compiler does not know that PrepareExecBase
674 * may change it out from under us.
676 struct ExecBase *oldSysBase = *(APTR *)4;
677 #define SysBase CANNOT_USE_SYSBASE_SYMBOL_HERE
679 #if AROS_SERIAL_DEBUG
680 DebugInit();
681 #endif
683 trap = (APTR *)(NULL);
685 /* Set all the exceptions to the Early_Exception */
686 for (i = 2; i < 64; i++) {
687 if (i != 31) // Do not overwrite NMI
688 trap[i] = Early_Exception;
691 /* Let the world know we exist */
692 DebugInit();
693 DEBUGPUTS(("[reset]\n"));
694 RomInfo(0xf80000);
695 RomInfo(0xe00000);
696 RomInfo(0xf00000);
698 attnflags = GetAttnFlags(cpupcr);
700 /* Zap out old SysBase if invalid */
701 arosbootstrapmode = FALSE;
702 wasvalid = IsSysBaseValid(oldSysBase);
703 if (wasvalid) {
704 DEBUGPUTHEX(("[SysBase] was at", (ULONG)oldSysBase));
705 } else {
706 wasvalid = IsSysBaseValidNoVersion(oldSysBase);
707 if (wasvalid) {
708 DEBUGPUTHEX(("[SysBase] fakebase at", (ULONG)oldSysBase));
709 BootS = GetBootStruct(oldSysBase);
710 if (BootS) {
711 DEBUGPUTHEX(("BootStruct at", (ULONG)BootS));
712 DEBUGPUTHEX(("Original SysBase at", (ULONG)BootS->RealBase));
713 DEBUGPUTHEX(("Secondary SysBase at", (ULONG)BootS->RealBase2));
714 bootmsgptr = BootS->kerneltags;
715 arosbootstrapmode = TRUE;
717 wasvalid = TRUE;
718 } else {
719 DEBUGPUTHEX(("[SysBase] invalid at", (ULONG)oldSysBase));
720 wasvalid = FALSE;
723 if (bootmsgptr[0].ti_Tag == KRN_CmdLine) {
724 DEBUGPUTS(("[SysBase] kernel commandline '"));
725 DEBUGPUTS(((CONST_STRPTR)bootmsgptr[0].ti_Data));
726 DEBUGPUTS(("'\n"));
729 if (wasvalid) {
730 /* Save reset proof vectors */
731 ColdCapture = oldSysBase->ColdCapture;
732 CoolCapture = oldSysBase->CoolCapture;
733 WarmCapture = oldSysBase->WarmCapture;
734 KickMemPtr = oldSysBase->KickMemPtr;
735 KickTagPtr = oldSysBase->KickTagPtr;
736 KickCheckSum = oldSysBase->KickCheckSum;
738 /* Mark the oldSysBase as processed */
739 oldSysBase = NULL;
742 if (BootS && BootS->magicfastmem) {
743 /* Add early magic fast ram pool
744 * Makes it possible to have execbase and others in fast ram even
745 * if fast ram is non-autocnfig diagrom type.
747 membanks -= 2;
748 membanks[0] = (ULONG)BootS->magicfastmem;
749 membanks[1] = BootS->magicfastmemsize;
752 /* Adjust to skip the first 1K/4K bytes of
753 * Chip RAM. It's reserved for the Trap area.
755 for (i = 0; membanks[i + 2 + 1]; i += 2);
756 if (arosbootstrapmode || (attnflags & AFF_68030))
757 membanks[i + 0] = 0x1000;
758 else
759 membanks[i + 0] = 0x400;
760 membanks[i + 1] -= membanks[i + 0];
762 #if AROS_SERIAL_DEBUG && (DEBUG > 0)
763 for (i = 0; membanks[i + 1]; i += 2) {
764 ULONG addr = membanks[i + 0];
765 ULONG size = membanks[i + 1];
766 DEBUGPUTHEX(("RAM lower", addr));
767 DEBUGPUTHEX(("RAM upper", addr + size - 1));
769 #endif
771 /* Look for 'HELP' at address 0 - we're recovering
772 * from a fatal alert
774 if (trap[0] == (APTR)0x48454c50) {
775 for (i = 0; i < 4; i++)
776 oldLastAlert[i] = (LONG)trap[64 + i];
778 DEBUGPUTHEX(("LastAlert Alert", oldLastAlert[0]));
779 DEBUGPUTHEX(("LastAlert Task", oldLastAlert[1]));
780 } else {
781 oldLastAlert[0] = (LONG)-1;
782 oldLastAlert[1] = 0;
783 oldLastAlert[2] = 0;
784 oldLastAlert[3] = 0;
787 /* Clear alert marker */
788 trap[0] = 0;
790 DEBUGPUTHEX(("SS lower", (ULONG)&_ss));
791 DEBUGPUTHEX(("SS upper", (ULONG)&_ss_end - 1));
793 Early_ScreenCode(CODE_RAM_CHECK);
795 if (arosbootstrapmode) {
796 /* Scan only first rom image.
797 * The rest is in BootStruct resident list
799 kickrom[0] = (UWORD*)&_rom_start;
800 kickrom[1] = (UWORD*)&_rom_end;
801 kickrom[2] = (UWORD*)0x00f00000;
802 kickrom[3] = (UWORD*)0x00f80000;
803 kickrom[4] = (UWORD*)~0;
804 kickrom[5] = (UWORD*)~0;
805 resetKickMem (BootS);
806 } else {
807 kickrom[0] = (UWORD*)&_rom_start;
808 kickrom[1] = (UWORD*)&_rom_end;
809 kickrom[2] = (UWORD*)0x00f00000;
810 kickrom[3] = (UWORD*)0x00f80000;
811 kickrom[4] = (UWORD*)&_ext_start;
812 kickrom[5] = (UWORD*)&_ext_end;
813 kickrom[6] = (UWORD*)~0;
814 kickrom[7] = (UWORD*)~0;
817 mh = addmemoryregion(membanks[0], membanks[1],
818 BootS, BootS && (ULONG)BootS->magicfastmem == membanks[0]);
819 if (mh == NULL) {
820 DEBUGPUTS(("Can't create initial memory header!\n"));
821 Early_Alert(AT_DeadEnd | AG_NoMemory);
824 #if AROS_SERIAL_DEBUG && (DEBUG > 0)
825 for (i = 0; kickrom [i] != (UWORD*)~0; i += 2) {
826 DEBUGPUTHEX(("Resident start", (ULONG)kickrom[i]));
827 DEBUGPUTHEX(("Resident end ", (ULONG)kickrom[i + 1]));
829 #endif
832 * Call the SysBase initialization.
834 Early_ScreenCode(CODE_EXEC_CHECK);
835 if (!krnPrepareExecBase(kickrom, mh, bootmsgptr))
836 Early_Alert(AT_DeadEnd | AG_MakeLib | AO_ExecLib);
838 /* From here on, we can reference SysBase */
839 #undef SysBase
840 DEBUGPUTHEX(("[SysBase] at", (ULONG)SysBase));
842 PrivExecBase(SysBase)->PlatformData.BootMsg = bootmsgptr;
843 SysBase->ThisTask->tc_SPLower = &_ss;
844 SysBase->ThisTask->tc_SPUpper = &_ss_end;
846 if (wasvalid) {
847 SysBase->ColdCapture = ColdCapture;
848 SysBase->CoolCapture = CoolCapture;
849 SysBase->WarmCapture = WarmCapture;
850 SysBase->ChkSum = 0;
851 SysBase->ChkSum = GetSysBaseChkSum(SysBase) ^ 0xffff;
852 SysBase->KickMemPtr = KickMemPtr;
853 SysBase->KickTagPtr = KickTagPtr;
854 SysBase->KickCheckSum = KickCheckSum;
857 SysBase->SysStkUpper = (APTR)&_ss_end;
858 SysBase->SysStkLower = (APTR)&_ss;
860 /* Mark what the last alert was */
861 for (i = 0; i < 4; i++)
862 SysBase->LastAlert[i] = oldLastAlert[i];
864 SysBase->AttnFlags = attnflags;
866 /* Inject code for GetCC, depending on CPU model */
867 if (SysBase->AttnFlags & AFF_68010) {
868 /* move.w %ccr,%d0; rts; nop */
869 FAKE_IT(SysBase, Exec, GetCC, 88, 0x42c0, 0x4e75, 0x4e71);
870 } else {
871 /* move.w %sr,%d0; rts; nop */
872 FAKE_IT(SysBase, Exec, GetCC, 88, 0x40c0, 0x4e75, 0x4e71);
875 #ifdef THESE_ARE_KNOWN_SAFE_ASM_ROUTINES
876 PRESERVE_ALL(SysBase, Exec, Disable, 20);
877 PRESERVE_ALL(SysBase, Exec, Enable, 21);
878 PRESERVE_ALL(SysBase, Exec, Forbid, 22);
879 #endif
880 PRESERVE_ALL(SysBase, Exec, Permit, 23);
881 PRESERVE_ALL(SysBase, Exec, ObtainSemaphore, 94);
882 PRESERVE_ALL(SysBase, Exec, ReleaseSemaphore, 95);
883 PRESERVE_ALL(SysBase, Exec, ObtainSemaphoreShared, 113);
885 /* Functions that need sign extension */
886 EXT_BYTE(SysBase, Exec, SetTaskPri, 50);
887 EXT_BYTE(SysBase, Exec, AllocSignal, 55);
889 /* Only add the 2 standard ROM locations, since
890 * we may get memory at 0x00f00000, or when we
891 * are ReKicked, at the rom-in-ram locations.
893 krnCreateROMHeader("Kickstart ROM", (APTR)0x00f80000, (APTR)0x00ffffff);
894 krnCreateROMHeader("Kickstart ROM", (APTR)0x00e00000, (APTR)0x00e7ffff);
896 /* Add remaining memory regions */
897 for (i = 2; membanks[i + 1]; i += 2) {
898 IPTR addr = membanks[i];
899 ULONG size = membanks[i + 1];
901 mh = addmemoryregion(addr, size, BootS, FALSE);
902 Enqueue(&SysBase->MemList, &mh->mh_Node);
904 /* Adjust MaxLocMem and MaxExtMem as needed */
905 if (addr < 0x00200000)
906 SysBase->MaxLocMem = (size + 0xffff) & 0xffff0000;
907 else if (addr < 0x00d00000)
908 SysBase->MaxExtMem = size ? (APTR)(((0xc00000 + (size + 0xffff)) & 0xffff0000)) : 0;
911 /* Now that we have a valid SysBase, we can call ColdCapture */
912 if (wasvalid)
913 doColdCapture();
915 /* Seal up SysBase's critical variables */
916 SetSysBaseChkSum();
918 /* Set privilege violation trap - we
919 * need this to support the Exec/Supervisor call
921 trap[8] = (SysBase->AttnFlags & AFF_68010) ? Exec_Supervisor_Trap : Exec_Supervisor_Trap_00;
923 /* SysBase is complete, now we can enable instruction caches safely. */
924 CacheControl(CACRF_EnableI, CACRF_EnableI);
925 CacheClearU();
927 oldmem = AvailMem(MEMF_FAST);
929 /* Ok, let's start the system. We have to
930 * do this in Supervisor context, since some
931 * expansions ROMs (Cyperstorm PPC) expect it.
933 DEBUGPUTS(("[start] InitCode(RTF_SINGLETASK, 0)\n"));
934 InitCode(RTF_SINGLETASK, 0);
936 /* Autoconfig ram expansions are now configured */
938 /* Our original AROS SysBase was in autoconfig RAM?
939 * ArosBootStrap needs special handling because AOS autoconfigs all boards
940 * before jumping to ColdCapture if SysBase is in autoconfig RAM
942 * Technically we don't need this but it saves KickTags and KickMems
943 * if someone decides to use them. ArosBootStrap does not anymore need them,
944 * it only needs ColdCapture.
946 if (BootS) {
947 if (BootS->RealBase2) /* SysBase in autoconfig hack */
948 BootS->RealBase = BootS->RealBase2;
949 if (BootS->RealBase && iseven(BootS->RealBase)) {
950 BootS->RealBase->ColdCapture = SysBase->ColdCapture;
951 if (IsSysBaseValid(BootS->RealBase)) {
952 oldSysBase = BootS->RealBase;
953 DEBUGPUTHEX(("[SysBase] Found original at", (ULONG)oldSysBase));
954 } else {
955 DEBUGPUTHEX(("[SysBase] Found original invalid at", (ULONG)BootS->RealBase));
957 BootS->RealBase = NULL;
958 BootS->RealBase2 = NULL;
962 /* If oldSysBase is not NULL, that means that it
963 * (a) wasn't valid before when we only had MEMF_LOCAL
964 * ram and (b) could possibly be in the MEMF_KICK memory
965 * we just got. Let's check it and find out if we
966 * can use it's capture vectors.
968 if (oldSysBase && IsSysBaseValidNoVersion(oldSysBase)) {
969 /* Save reset proof vectors */
970 SysBase->ColdCapture = oldSysBase->ColdCapture;
971 SysBase->CoolCapture = oldSysBase->CoolCapture;
972 SysBase->WarmCapture = oldSysBase->WarmCapture;
973 /* Save KickData */
974 SysBase->KickMemPtr = oldSysBase->KickMemPtr;
975 SysBase->KickTagPtr = oldSysBase->KickTagPtr;
976 SysBase->KickCheckSum = oldSysBase->KickCheckSum;
977 doColdCapture();
978 /* Re-seal SysBase */
979 SetSysBaseChkSum();
980 wasvalid = TRUE;
983 /* Before we allocate anything else, we need to
984 * lock down the mem entries in BootStruct.
986 * Diag module does final allocation attempt.
988 if (arosbootstrapmode) {
989 if (SysBase->KickCheckSum == (APTR)SumKickData()) {
990 InitKickMem(SysBase);
991 CollectKickResidents(BootS, SysBase);
992 } else {
993 DEBUGPUTS(("PANIC! KickCheckSum mismatch!\n"));
994 Early_Alert(AT_DeadEnd | AN_MemoryInsane);
998 if ((AvailMem(MEMF_FAST) > (oldmem + 256 * 1024)) &&
999 ((TypeOfMem(SysBase) & MEMF_CHIP) ||
1000 ((ULONG)SysBase >= 0x00a00000ul && (ULONG)SysBase < 0x01000000ul))) {
1001 /* Move execbase to real fast if available now */
1002 SysBase = PrepareExecBaseMove(SysBase);
1003 AbsExecBase = SysBase;
1004 DEBUGPUTHEX(("[Sysbase] now at", (ULONG)SysBase));
1007 /* Initialize IRQ subsystem */
1008 AmigaIRQInit(SysBase);
1010 /* Set privilege violation trap again.
1011 * AmigaIRQInit may have blown it away.
1013 trap[8] = (SysBase->AttnFlags & AFF_68010) ? Exec_Supervisor_Trap : Exec_Supervisor_Trap_00;
1015 /* Attempt to allocate a real stack, and switch to it. */
1016 do {
1017 const ULONG size = AROS_STACKSIZE;
1018 IPTR *usp;
1020 usp = AllocMem(size * sizeof(IPTR), MEMF_PUBLIC);
1021 if (usp == NULL) {
1022 DEBUGPUTS(("PANIC! Can't allocate a new stack for Exec!\n"));
1023 Early_Alert(CODE_ALLOC_FAIL);
1026 /* Leave supervisor mode, switch power led on */
1027 asm volatile (
1028 "or.b #2,0xbfe001\n"
1029 "move.l %0,%%usp\n"
1030 "move.w #0,%%sr\n"
1031 "move.l %2,%%sp@-\n"
1032 "pea 0f\n"
1033 "jmp %1@\n"
1034 "0:\n"
1036 : "a" (&usp[size-3]),
1037 "a" (doInitCode),
1038 "a" (BootS)
1040 } while (0);
1042 /* We shouldn't get here */
1043 DEBUGPUTS(("PANIC! doInitCode() returned!\n"));
1044 Early_Alert(CODE_EXEC_FAIL);