Bring back sam build into life.
[AROS.git] / arch / ppc-sam440 / exec / exec_init.c
blob25f54fa8b8a975e38d6fe5ac2db7402ab6d63375
1 #include <asm/amcc440.h>
2 #include <aros/libcall.h>
3 #include <aros/asmcall.h>
4 #include <aros/arossupportbase.h>
5 #include <exec/execbase.h>
6 #include <exec/types.h>
7 #include <exec/resident.h>
8 #include <dos/bptr.h>
9 #include <dos/dosextens.h>
10 #include <hardware/custom.h>
11 #include <hardware/intbits.h>
13 #include <proto/exec.h>
14 #include <proto/kernel.h>
16 #include <stdarg.h>
17 #include <strings.h>
18 #include <inttypes.h>
20 #include "etask.h"
21 #include "exec_util.h"
23 #include "exec_intern.h"
24 #include "memory.h"
26 #undef KernelBase
27 #include "../kernel/kernel_intern.h"
29 D(extern void debugmem(void));
31 void exec_main(struct TagItem *msg, void *entry);
32 extern CONST_APTR Exec_FuncTable[];
33 extern ULONG Exec_15_MakeFunctions(APTR, CONST_APTR, CONST_APTR, struct ExecBase *);
34 void exec_DefaultTaskExit();
35 IPTR **exec_RomTagScanner(struct TagItem *msg);
36 extern struct Library * PrepareAROSSupportBase (void);
38 AROS_UFP5(void, SoftIntDispatch,
39 AROS_UFPA(ULONG, intReady, D1),
40 AROS_UFPA(struct Custom *, custom, A0),
41 AROS_UFPA(IPTR, intData, A1),
42 AROS_UFPA(IPTR, intCode, A5),
43 AROS_UFPA(struct ExecBase *, SysBase, A6));
45 AROS_UFP5S(void, IntServer,
46 AROS_UFPA(ULONG, intMask, D0),
47 AROS_UFPA(struct Custom *, custom, A0),
48 AROS_UFPA(struct List *, intList, A1),
49 AROS_UFPA(APTR, intCode, A5),
50 AROS_UFPA(struct ExecBase *, SysBase, A6));
52 const char exec_name[] = "exec.library";
53 const char exec_idstring[] = "$VER: exec 41.11 (16.12.2000)\r\n";
54 const char exec_chipname[] = "Chip Memory";
55 const char exec_fastname[] = "Fast Memory";
57 const short exec_Version = 41;
58 const short exec_Revision = 11;
60 const struct __attribute__((section(".text"))) Resident Exec_resident =
62 RTC_MATCHWORD, /* Magic value used to find resident */
63 &Exec_resident, /* Points to Resident itself */
64 (APTR)&Exec_resident+1, /* Where could we find next Resident? */
65 0, /* There are no flags!! */
66 41, /* Version */
67 NT_LIBRARY, /* Type */
68 126, /* Very high startup priority. */
69 (STRPTR)exec_name, /* Pointer to name string */
70 (STRPTR)exec_idstring, /* Ditto */
71 exec_main /* Library initializer (for exec this value is irrelevant since we've jumped there at the begining to bring the system up */
74 static uint32_t exec_SelectMbs(uint32_t bcr)
76 switch (bcr & SDRAM_SDSZ_MASK)
78 case SDRAM_SDSZ_256MB: return 256;
79 case SDRAM_SDSZ_128MB: return 128;
80 case SDRAM_SDSZ_64MB: return 64;
81 case SDRAM_SDSZ_32MB: return 32;
82 case SDRAM_SDSZ_16MB: return 16;
83 case SDRAM_SDSZ_8MB: return 8;
86 return 0;
89 /* Detect and report amount of available memory in mega bytes via device control register bus */
90 static uint32_t exec_GetMemory()
92 uint32_t mem;
93 wrdcr(SDRAM0_CFGADDR, SDRAM0_B0CR);
94 mem = exec_SelectMbs(rddcr(SDRAM0_CFGDATA));
95 //D(bug("[exec] B0CR %08x %uM\n", rddcr(SDRAM0_CFGDATA), mem));
97 wrdcr(SDRAM0_CFGADDR, SDRAM0_B1CR);
98 mem += exec_SelectMbs(rddcr(SDRAM0_CFGDATA));
99 //D(bug("[exec] B1CR %08x %uM\n", rddcr(SDRAM0_CFGDATA), mem));
101 wrdcr(SDRAM0_CFGADDR, SDRAM0_B2CR);
102 mem += exec_SelectMbs(rddcr(SDRAM0_CFGDATA));
103 //D(bug("[exec] B2CR %08x %uM\n", rddcr(SDRAM0_CFGDATA), mem));
105 wrdcr(SDRAM0_CFGADDR, SDRAM0_B3CR);
106 mem += exec_SelectMbs(rddcr(SDRAM0_CFGDATA));
107 //D(bug("[exec] B3CR %08x %uM\n", rddcr(SDRAM0_CFGDATA), mem));
109 return mem;
112 void exec_main(struct TagItem *msg, void *entry)
114 struct ExecBase *SysBase = NULL;
115 uintptr_t lowmem = 0;
116 uint32_t mem;
117 int i;
119 D(bug("[exec] AROS for Sam440 - The AROS Research OS\n"));
121 /* Prepare the exec base */
123 ULONG negsize = LIB_VECTSIZE; /* size of vector table */
124 CONST_APTR *fp = Exec_FuncTable; /* pointer to a function in the table */
126 D(bug("[exec] Preparing the ExecBase...\n"));
128 /* Calculate the size of the vector table */
129 while (*fp++ != (APTR) -1) negsize += LIB_VECTSIZE;
131 /* Align the offset for SysBase to the cache line */
132 negsize = (negsize + 31) & ~31;
134 /* Get the lowest usable memory location */
135 lowmem = (krnGetTagData(KRN_KernelHighest, 0, msg) + 0xffff) & 0xffff0000;
137 /* And now let's have the SysBase */
138 SysBase = (struct ExecBase *)(lowmem + negsize);
139 wrspr(SPRG5, SysBase);
140 lowmem = (lowmem + negsize + sizeof(struct IntExecBase) + 4095) & ~4095;
142 D(bug("[exec] ExecBase at %08x\n", SysBase));
144 D(bug("[exec] Clearing ExecBase\n"));
146 /* How about clearing most of ExecBase structure? */
147 bzero(&SysBase->IntVects[0], sizeof(struct IntExecBase) - offsetof(struct ExecBase, IntVects[0]));
149 SysBase->KickMemPtr = NULL;
150 SysBase->KickTagPtr = NULL;
151 SysBase->KickCheckSum = NULL;
154 * Now everything is prepared to store ExecBase at the location 4UL and set
155 * it complement in ExecBase structure
158 D(bug("[exec] Initializing library...\n"));
160 SysBase->ChkBase = ~(ULONG)SysBase;
162 /* Store memory configuration */
163 SysBase->MaxLocMem = (IPTR)0; //locmem;
164 SysBase->MaxExtMem = (APTR)0; //extmem;
167 * Initialize exec lists. This is done through information table which consist
168 * of offset from begining of ExecBase and type of the list.
170 NEWLIST(&SysBase->MemList);
171 SysBase->MemList.lh_Type = NT_MEMORY;
172 NEWLIST(&SysBase->ResourceList);
173 SysBase->ResourceList.lh_Type = NT_RESOURCE;
174 NEWLIST(&SysBase->DeviceList);
175 SysBase->DeviceList.lh_Type = NT_DEVICE;
176 NEWLIST(&SysBase->LibList);
177 SysBase->LibList.lh_Type = NT_LIBRARY;
178 NEWLIST(&SysBase->PortList);
179 SysBase->PortList.lh_Type = NT_MSGPORT;
180 NEWLIST(&SysBase->TaskReady);
181 SysBase->TaskReady.lh_Type = NT_TASK;
182 NEWLIST(&SysBase->TaskWait);
183 SysBase->TaskWait.lh_Type = NT_TASK;
184 NEWLIST(&SysBase->IntrList);
185 SysBase->IntrList.lh_Type = NT_INTERRUPT;
186 NEWLIST(&SysBase->SemaphoreList);
187 SysBase->SemaphoreList.lh_Type = NT_SIGNALSEM;
188 NEWLIST(&SysBase->ex_MemHandlers);
190 for (i=0; i<5; i++)
192 NEWLIST(&SysBase->SoftInts[i].sh_List);
193 SysBase->SoftInts[i].sh_List.lh_Type = NT_SOFTINT;
197 * Exec.library initializer. Prepares exec.library for future use. All
198 * lists have to be initialized, some values from ROM are copied.
201 SysBase->TaskTrapCode = NULL; //exec_DefaultTrap;
202 SysBase->TaskExceptCode = NULL; //exec_DefaultTrap;
203 SysBase->TaskExitCode = exec_DefaultTaskExit;
204 SysBase->TaskSigAlloc = 0x0000ffff;
205 SysBase->TaskTrapAlloc = 0x8000;
207 /* Prepare values for execBase (like name, type, pri and other) */
209 SysBase->LibNode.lib_Node.ln_Type = NT_LIBRARY;
210 SysBase->LibNode.lib_Node.ln_Pri = 0;
211 SysBase->LibNode.lib_Node.ln_Name = (char *)exec_name;
212 SysBase->LibNode.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
213 SysBase->LibNode.lib_PosSize = sizeof(struct IntExecBase);
214 SysBase->LibNode.lib_OpenCnt = 1;
215 SysBase->LibNode.lib_IdString = (char *)exec_idstring;
216 SysBase->LibNode.lib_Version = exec_Version;
217 SysBase->LibNode.lib_Revision = exec_Revision;
219 SysBase->Quantum = 4;
220 SysBase->VBlankFrequency = 50;
221 SysBase->PowerSupplyFrequency = 1;
223 NEWLIST(&PrivExecBase(SysBase)->ResetHandlers);
224 NEWLIST(&PrivExecBase(SysBase)->AllocMemList);
226 #if AROS_MUNGWALL_DEBUG
228 * TODO: implement command line parsing instead of this awkward hack
229 * Or, even better, merge this init code with arch-independent one
231 PrivExecBase(SysBase)->IntFlags = EXECF_MungWall;
232 #endif
234 /* Build the jumptable */
235 SysBase->LibNode.lib_NegSize =
236 Exec_15_MakeFunctions(SysBase, Exec_FuncTable, NULL, SysBase);
238 SumLibrary((struct Library *)SysBase);
240 InitSemaphore(&PrivExecBase(SysBase)->MemListSem);
241 InitSemaphore(&PrivExecBase(SysBase)->LowMemSem);
243 mem = exec_GetMemory();
244 D(bug("[exec] Adding memory (%uM)\n", mem));
246 AddMemList(0x01000000 - lowmem,
247 MEMF_CHIP | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA,
248 -10,
249 (APTR)lowmem,
250 (STRPTR)exec_chipname);
252 AddMemList((mem - 16) * 1024*1024,
253 MEMF_FAST | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL,
255 (APTR)0x01000000,
256 (STRPTR)exec_fastname);
258 SumLibrary((struct Library *)SysBase);
260 Enqueue(&SysBase->LibList,&SysBase->LibNode.lib_Node);
262 SysBase->DebugAROSBase = PrepareAROSSupportBase();
264 /* Scan for valid RomTags */
265 SysBase->ResModules = exec_RomTagScanner(msg);
267 D(bug("[exec] InitCode(RTF_SINGLETASK)\n"));
268 InitCode(RTF_SINGLETASK, 0);
270 PrivExecBase(SysBase)->KernelBase = OpenResource("kernel.resource");
271 PrivExecBase(SysBase)->PageSize = MEMCHUNK_TOTAL;
273 /* Install the interrupt servers */
274 for (i=0; i<16; i++)
276 if( (1<<i) & (INTF_PORTS|INTF_COPER|INTF_VERTB|INTF_EXTER|INTF_SETCLR))
278 struct Interrupt *is;
279 struct SoftIntList *sil;
280 is = AllocMem
282 sizeof(struct Interrupt) + sizeof(struct SoftIntList),
283 MEMF_CLEAR | MEMF_PUBLIC
285 if( is == NULL )
287 D(bug("[exec] ERROR: Cannot install Interrupt Servers!\n"));
289 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
291 is->is_Code = &IntServer;
292 is->is_Data = sil;
293 NEWLIST((struct List *)sil);
294 SetIntVector(i,is);
296 else
298 struct Interrupt *is;
299 switch (i)
301 case INTB_SOFTINT :
302 is = AllocMem
304 sizeof(struct Interrupt),
305 MEMF_CLEAR | MEMF_PUBLIC
307 if (is == NULL)
309 D(bug("[exec] Error: Cannot install Interrupt Servers!\n"));
310 // Alert(AT_DeadEnd | AN_IntrMem);
312 is->is_Node.ln_Type = NT_SOFTINT; //INTERRUPT;
313 is->is_Node.ln_Pri = 0;
314 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
315 is->is_Data = NULL;
316 is->is_Code = (void *)SoftIntDispatch;
317 SetIntVector(i,is);
318 break;
323 /* Now it's time to calculate exec checksum. It will be used
324 * in future to distinguish whether we'd had proper execBase
325 * before restart */
327 UWORD sum=0, *ptr = &SysBase->SoftVer;
328 int i=((IPTR)&SysBase->IntVects[0] - (IPTR)&SysBase->SoftVer) / 2,
331 /* Calculate sum for every static part from SoftVer to ChkSum */
332 for (j=0;j < i;j++)
334 sum+=*(ptr++);
337 SysBase->ChkSum = ~sum;
340 /* Create boot task. Sigh, we actually create a Process sized Task,
341 since DOS needs to call things which think it has a Process and
342 we don't want to overwrite memory with something strange do we?
344 We do this until at least we can boot dos more cleanly.
347 struct Task *t;
348 struct MemList *ml;
350 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
351 t = (struct Task *) AllocMem(sizeof(struct Process), MEMF_PUBLIC|MEMF_CLEAR);
353 if( !ml || !t )
355 D(bug("[exec] ERROR: Cannot create Boot Task!\n"));
357 ml->ml_NumEntries = 1;
358 ml->ml_ME[0].me_Addr = t;
359 ml->ml_ME[0].me_Length = sizeof(struct Process);
361 NEWLIST(&t->tc_MemEntry);
362 NEWLIST(&((struct Process *)t)->pr_MsgPort.mp_MsgList);
364 /* It's the boot process that RunCommand()s the boot shell, so we
365 must have this list initialized */
366 NEWLIST((struct List *)&((struct Process *)t)->pr_LocalVars);
368 AddHead(&t->tc_MemEntry,&ml->ml_Node);
370 t->tc_Node.ln_Name = (char *)exec_name;
371 t->tc_Node.ln_Pri = 0;
372 t->tc_Node.ln_Type = NT_TASK;
373 t->tc_State = TS_RUN;
374 t->tc_SigAlloc = 0xFFFF;
375 t->tc_SPLower = 0; /* This is the system's stack */
376 t->tc_SPUpper = (APTR)~0UL;
377 t->tc_Flags |= TF_ETASK;
379 if (t->tc_Flags & TF_ETASK)
381 t->tc_UnionETask.tc_ETask = AllocVec
383 sizeof(struct IntETask),
384 MEMF_ANY|MEMF_CLEAR
387 if (!t->tc_UnionETask.tc_ETask)
389 D(bug("[exec] Not enough memory for first task\n"));
392 /* Initialise the ETask data. */
393 InitETask(t, t->tc_UnionETask.tc_ETask);
395 GetIntETask(t)->iet_Context = AllocMem(SIZEOF_ALL_REGISTERS
396 , MEMF_PUBLIC|MEMF_CLEAR
399 if (!GetIntETask(t)->iet_Context)
401 D(bug("[exec] Not enough memory for first task\n"));
405 SysBase->ThisTask = t;
408 D(bug("[exec] Done. SysBase->ThisTask = %08p\n", SysBase->ThisTask));
410 /* We now start up the interrupts */
411 Permit();
412 Enable();
414 D(debugmem());
416 D(bug("[exec] InitCode(RTF_COLDSTART)\n"));
417 InitCode(RTF_COLDSTART, 0);
419 D(bug("[exec] I should never get here...\n"));
424 * RomTag scanner.
426 * This function scans kernel for existing Resident modules. If two modules
427 * with the same name are found, the one with higher version or priority wins.
429 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
430 * checksummed. If checksum is proper and all memory pointed in KickMemPtr may
431 * be allocated, then all modules from KickTagPtr are added to RT list
433 * Afterwards the proper RomTagList is created (see InitCode() for details) and
434 * memory after list and nodes is freed.
437 struct rt_node
439 struct Node node;
440 struct Resident *module;
444 void exec_DefaultTaskExit()
446 struct ExecBase *SysBase = getSysBase();
447 RemTask(SysBase->ThisTask);
450 IPTR **exec_RomTagScanner(struct TagItem *msg)
452 struct ExecBase *SysBase = getSysBase();
454 struct List rtList; /* List of modules */
455 UWORD *ptr = (UWORD*)(krnGetTagData(KRN_KernelLowest, 0, msg) + 0xff000000); /* Start looking here */
456 UWORD *maxptr = (UWORD*)(krnGetTagData(KRN_KernelHighest, 0, msg) + 0xff000000);
457 struct Resident *res; /* module found */
459 int i;
460 IPTR **RomTag;
462 /* Initialize list */
463 NEWLIST(&rtList);
465 D(bug("[exec] Resident modules (addr: pri version name):\n"));
467 /* Look in whole kernel for resident modules */
470 /* Do we have RTC_MATCHWORD? */
471 if (*ptr == RTC_MATCHWORD)
473 /* Yes, assume we have Resident */
474 res = (struct Resident *)ptr;
476 /* Does rt_MatchTag point to Resident? */
477 if (res == res->rt_MatchTag)
479 /* Yes, it is Resident module */
480 struct rt_node *node;
482 /* Check if there is module with such name already */
483 node = (struct rt_node*)FindName(&rtList, res->rt_Name);
484 if (node)
486 /* Yes, there was such module. It it had lower pri then replace it */
487 if (node->node.ln_Pri <= res->rt_Pri)
489 /* If they have the same Pri but new one has higher Version, replace */
490 if ((node->node.ln_Pri == res->rt_Pri) &&
491 (node->module->rt_Version < res->rt_Version))
493 node->node.ln_Pri = res->rt_Pri;
494 node->module = res;
498 else
500 /* New module. Allocate some memory for it */
501 node = (struct rt_node *)
502 AllocMem(sizeof(struct rt_node),MEMF_PUBLIC|MEMF_CLEAR);
504 if (node)
506 node->node.ln_Name = (char *)res->rt_Name;
507 node->node.ln_Pri = res->rt_Pri;
508 node->module = res;
510 Enqueue(&rtList,(struct Node*)node);
513 ptr+=sizeof(struct Resident)/sizeof(UWORD);
514 continue;
518 /* Get next address... */
519 ptr++;
520 } while (ptr < maxptr);
523 * By now we have valid (and sorted) list of kernel resident modules.
525 * Now, we will have to analyze used-defined RomTags (via KickTagPtr and
526 * KickMemPtr)
528 #warning "TODO: Implement external modules!"
530 * Everything is done now. Allocate buffer for normal RomTag and convert
531 * list to RomTag
534 ListLength(&rtList,i); /* Get length of the list */
536 RomTag = AllocMem((i+1)*sizeof(IPTR),MEMF_PUBLIC | MEMF_CLEAR);
538 if (RomTag)
540 int j;
541 struct rt_node *n;
543 for (j=0; j<i; j++)
545 n = (struct rt_node *)RemHead(&rtList);
546 D(bug("[exec] + 0x%08lx: %4d %3d \"%s\"\n",
547 n->module,
548 n->node.ln_Pri,
549 n->module->rt_Version,
550 n->node.ln_Name));
551 RomTag[j] = (IPTR*)n->module;
552 FreeMem(n, sizeof(struct rt_node));
554 RomTag[i] = 0;
557 return RomTag;
560 AROS_LH1(struct ExecBase *, open,
561 AROS_LHA(ULONG, version, D0),
562 struct ExecBase *, SysBase, 1, Exec)
564 AROS_LIBFUNC_INIT
566 /* I have one more opener. */
567 SysBase->LibNode.lib_OpenCnt++;
568 return SysBase;
570 AROS_LIBFUNC_EXIT
573 AROS_LH0(BPTR, close,
574 struct ExecBase *, SysBase, 2, Exec)
576 AROS_LIBFUNC_INIT
578 /* I have one fewer opener. */
579 SysBase->LibNode.lib_OpenCnt--;
580 return 0;
581 AROS_LIBFUNC_EXIT
584 AROS_LH0I(int, null,
585 struct ExecBase *, SysBase, 4, Exec)
587 AROS_LIBFUNC_INIT
588 return 0;
589 AROS_LIBFUNC_EXIT
593 We temporarily redefine kprintf() so we use the real version in case
594 we have one of these two fn's called before AROSSupportBase is ready.
597 #undef kprintf
598 #undef rkprintf
599 #undef vkprintf
600 #undef KernelBase
602 static int __kprintf(const UBYTE *fmt, ...)
604 va_list ap;
605 int result = 0;
606 void *KernelBase = getKernelBase();
608 if (KernelBase)
610 va_start(ap,fmt);
611 result = KrnBug(fmt, ap);
612 va_end(ap);
614 return result;
617 static int __vkprintf(const UBYTE *fmt, va_list args)
619 void *KernelBase = getKernelBase();
621 if (KernelBase)
622 return KrnBug(fmt, args);
623 else
624 return 0;
627 static int __rkprintf(const STRPTR mainSystem, const STRPTR subSystem, int level, const UBYTE *fmt, ...)
629 va_list ap;
630 int result = 0;
631 void *KernelBase = getKernelBase();
633 if (KernelBase)
635 va_start(ap,fmt);
636 result = KrnBug(fmt, ap);
637 va_end(ap);
639 return result;
642 struct Library * PrepareAROSSupportBase(void)
644 struct ExecBase *SysBase = getSysBase();
646 struct AROSSupportBase *AROSSupportBase =
647 AllocMem(sizeof(struct AROSSupportBase), MEMF_CLEAR);
649 AROSSupportBase->kprintf = (void *)__kprintf;
650 AROSSupportBase->rkprintf = (void *)__rkprintf;
651 AROSSupportBase->vkprintf = (void *)__vkprintf;
653 return (struct Library *)AROSSupportBase;
656 /* IntServer:
657 This interrupt handler will send an interrupt to a series of queued
658 interrupt servers. Servers should return D0 != 0 (Z clear) if they
659 believe the interrupt was for them, and no further interrupts will
660 be called. This will only check the value in D0 for non-m68k systems,
661 however it SHOULD check the Z-flag on 68k systems.
663 Hmm, in that case I would have to separate it from this file in order
664 to replace it...
666 AROS_UFH5S(void, IntServer,
667 AROS_UFHA(ULONG, intMask, D0),
668 AROS_UFHA(struct Custom *, custom, A0),
669 AROS_UFHA(struct List *, intList, A1),
670 AROS_UFHA(APTR, intCode, A5),
671 AROS_UFHA(struct ExecBase *, SysBase, A6))
673 AROS_USERFUNC_INIT
675 struct Interrupt * irq;
677 ForeachNode(intList, irq)
679 if( AROS_UFC4(int, irq->is_Code,
680 AROS_UFCA(struct Custom *, custom, A0),
681 AROS_UFCA(APTR, irq->is_Data, A1),
682 AROS_UFCA(APTR, irq->is_Code, A5),
683 AROS_UFCA(struct ExecBase *, SysBase, A6)
685 break;
688 AROS_USERFUNC_EXIT
691 void _aros_not_implemented(char *string) {}