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