Forward compatibility: build relative-base link libraries where needed
[AROS.git] / arch / ppc-chrp / exec / exec_init.c
bloba943e24f2dfda703838796c9cbd618a8aa598444
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 1
8 #include <asm/mpc5200b.h>
9 #include <aros/config.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/arossupportbase.h>
13 #include <aros/symbolsets.h>
14 #include <exec/execbase.h>
15 #include <exec/types.h>
16 #include <exec/resident.h>
17 #include <dos/bptr.h>
18 #include <dos/dosextens.h>
19 #include <hardware/custom.h>
20 #include <hardware/intbits.h>
22 #include <proto/exec.h>
23 #include <proto/kernel.h>
25 #include <stdarg.h>
26 #include <strings.h>
27 #include <inttypes.h>
29 #include "etask.h"
30 #include "exec_intern.h"
31 #include "exec_util.h"
32 #include "intservers.h"
33 #include "memory.h"
34 #include "taskstorage.h"
36 D(extern void debugmem(void));
38 void exec_main(struct TagItem *msg, void *entry);
39 extern CONST_APTR Exec_FuncTable[];
40 extern ULONG Exec_15_MakeFunctions(APTR, CONST_APTR, CONST_APTR, struct ExecBase *);
41 void exec_DefaultTaskExit();
42 IPTR **exec_RomTagScanner(struct TagItem *msg, struct ExecBase *);
43 extern struct Library * PrepareAROSSupportBase (struct ExecBase *);
44 intptr_t krnGetTagData(Tag tagValue, intptr_t defaultVal, const struct TagItem *tagList);
46 struct ExecBase *priv_SysBase;
48 AROS_LD2(int, KrnBug,
49 AROS_LDA(const char *, format, A0),
50 AROS_LDA(va_list, args, A1),
51 APTR, kernelBase, 12, Kernel);
52 #undef bug
54 static inline void bug(const char *format, ...)
56 va_list args;
58 va_start(args, format);
59 /* Our KrnBug() ignores base address */
60 AROS_SLIB_ENTRY(KrnBug, Kernel, 12)(format, args, NULL);
61 va_end(args);
64 const char exec_name[] = "exec.library";
65 const char exec_idstring[] = "$VER: exec 41.11 (16.12.2000)\r\n";
66 const char exec_fastname[] = "System Memory";
68 const short exec_Version = 41;
69 const short exec_Revision = 11;
71 const struct __attribute__((section(".text"))) Resident Exec_resident =
73 RTC_MATCHWORD, /* Magic value used to find resident */
74 &Exec_resident, /* Points to Resident itself */
75 (APTR)&Exec_resident+1, /* Where could we find next Resident? */
76 0, /* There are no flags!! */
77 41, /* Version */
78 NT_LIBRARY, /* Type */
79 126, /* Very high startup priority. */
80 (STRPTR)exec_name, /* Pointer to name string */
81 (STRPTR)exec_idstring, /* Ditto */
82 exec_main /* Library initializer (for exec this value is irrelevant since we've jumped there at the begining to bring the system up */
85 THIS_PROGRAM_HANDLES_SYMBOLSET(INITLIB)
86 DEFINESET(INITLIB)
88 void exec_main(struct TagItem *msg, void *entry)
90 struct ExecBase *SysBase = NULL;
91 struct TaskStorageFreeSlot *tsfs;
92 struct Task *t;
93 uintptr_t lowmem = 0;
94 int i;
96 priv_SysBase = NULL;
98 D(bug("[exec] AROS for Efika5200B - The AROS Research OS\n"));
100 /* Prepare the exec base */
102 ULONG negsize = LIB_VECTSIZE; /* size of vector table */
103 CONST_APTR *fp = Exec_FuncTable; /* pointer to a function in the table */
105 D(bug("[exec] Preparing the ExecBase...\n"));
107 /* Calculate the size of the vector table */
108 while (*fp++ != (APTR) -1) negsize += LIB_VECTSIZE;
110 /* Align the offset for SysBase to the cache line */
111 negsize = (negsize + 31) & ~31;
113 /* Get the lowest usable memory location */
114 lowmem = 0x3000;
116 /* And now let's have the SysBase */
117 SysBase = (struct ExecBase *)(lowmem + negsize);
118 wrspr(SPRG5, SysBase);
119 *(struct ExecBase **)4UL = SysBase;
120 /* Store the SysBase for local use. It's ugly, it's dirty, it's a hack. */
121 priv_SysBase = SysBase;
122 lowmem = (lowmem + negsize + sizeof(struct IntExecBase) + 4095) & ~4095;
124 D(bug("[exec] ExecBase at %08x\n", SysBase));
126 D(bug("[exec] Clearing ExecBase\n"));
128 /* How about clearing most of ExecBase structure? */
129 memset(&SysBase->IntVects[0], 0, sizeof(struct IntExecBase) - offsetof(struct ExecBase, IntVects[0]));
131 SysBase->KickMemPtr = NULL;
132 SysBase->KickTagPtr = NULL;
133 SysBase->KickCheckSum = NULL;
135 SysBase->DispCount = 0;
136 SysBase->IdleCount = 0;
139 * Now everything is prepared to store ExecBase at the location 4UL and set
140 * it complement in ExecBase structure
143 D(bug("[exec] Initializing library...\n"));
145 SysBase->ChkBase = ~(ULONG)SysBase;
147 /* Store memory configuration */
148 SysBase->MaxLocMem = (IPTR)0; //locmem;
149 SysBase->MaxExtMem = (APTR)0; //extmem;
152 * Initialize exec lists. This is done through information table which consist
153 * of offset from begining of ExecBase and type of the list.
155 NEWLIST(&SysBase->MemList);
156 SysBase->MemList.lh_Type = NT_MEMORY;
157 NEWLIST(&SysBase->ResourceList);
158 SysBase->ResourceList.lh_Type = NT_RESOURCE;
159 NEWLIST(&SysBase->DeviceList);
160 SysBase->DeviceList.lh_Type = NT_DEVICE;
161 NEWLIST(&SysBase->LibList);
162 SysBase->LibList.lh_Type = NT_LIBRARY;
163 NEWLIST(&SysBase->PortList);
164 SysBase->PortList.lh_Type = NT_MSGPORT;
165 NEWLIST(&SysBase->TaskReady);
166 SysBase->TaskReady.lh_Type = NT_TASK;
167 NEWLIST(&SysBase->TaskWait);
168 SysBase->TaskWait.lh_Type = NT_TASK;
169 NEWLIST(&SysBase->IntrList);
170 SysBase->IntrList.lh_Type = NT_INTERRUPT;
171 NEWLIST(&SysBase->SemaphoreList);
172 SysBase->SemaphoreList.lh_Type = NT_SIGNALSEM;
173 NEWLIST(&SysBase->ex_MemHandlers);
175 for (i=0; i<5; i++)
177 NEWLIST(&SysBase->SoftInts[i].sh_List);
178 SysBase->SoftInts[i].sh_List.lh_Type = NT_SOFTINT;
182 * Exec.library initializer. Prepares exec.library for future use. All
183 * lists have to be initialized, some values from ROM are copied.
186 SysBase->TaskTrapCode = NULL; //exec_DefaultTrap;
187 SysBase->TaskExceptCode = NULL; //exec_DefaultTrap;
188 SysBase->TaskExitCode = exec_DefaultTaskExit;
189 SysBase->TaskSigAlloc = 0x0000ffff;
190 SysBase->TaskTrapAlloc = 0x8000;
192 /* Prepare values for execBase (like name, type, pri and other) */
194 SysBase->LibNode.lib_Node.ln_Type = NT_LIBRARY;
195 SysBase->LibNode.lib_Node.ln_Pri = 0;
196 SysBase->LibNode.lib_Node.ln_Name = (char *)exec_name;
197 SysBase->LibNode.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
198 SysBase->LibNode.lib_PosSize = sizeof(struct IntExecBase);
199 SysBase->LibNode.lib_OpenCnt = 1;
200 SysBase->LibNode.lib_IdString = (char *)exec_idstring;
201 SysBase->LibNode.lib_Version = exec_Version;
202 SysBase->LibNode.lib_Revision = exec_Revision;
204 SysBase->Quantum = 4;
205 SysBase->Elapsed = 4;
206 SysBase->VBlankFrequency = 50;
207 SysBase->PowerSupplyFrequency = 1;
209 NEWLIST(&PrivExecBase(SysBase)->ResetHandlers);
210 NEWLIST(&PrivExecBase(SysBase)->AllocMemList);
212 #if AROS_MUNGWALL_DEBUG
214 * TODO: implement command line parsing instead of this awkward hack
215 * Or, even better, merge this init code with arch-independent one
217 PrivExecBase(SysBase)->IntFlags = EXECF_MungWall;
218 #endif
220 /* Build the jumptable */
221 SysBase->LibNode.lib_NegSize =
222 Exec_15_MakeFunctions(SysBase, Exec_FuncTable, NULL, SysBase);
224 SumLibrary((struct Library *)SysBase);
226 InitSemaphore(&PrivExecBase(SysBase)->MemListSem);
227 InitSemaphore(&PrivExecBase(SysBase)->LowMemSem);
229 PrivExecBase(SysBase)->TaskStorageSize = TASKSTORAGEPUDDLE;
230 NEWLIST(&PrivExecBase(SysBase)->TaskStorageSlots);
232 D(bug("[exec] Adding memory\n"));
234 AddMemList(0x07000000 - lowmem,
235 MEMF_FAST | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL,
237 (APTR)lowmem,
238 (STRPTR)exec_fastname);
240 SumLibrary((struct Library *)SysBase);
242 Enqueue(&SysBase->LibList,&SysBase->LibNode.lib_Node);
244 SysBase->DebugAROSBase = PrepareAROSSupportBase(SysBase);
246 /* Scan for valid RomTags */
247 SysBase->ResModules = exec_RomTagScanner(msg, SysBase);
249 D(bug("[exec] InitCode(RTF_SINGLETASK)\n"));
250 InitCode(RTF_SINGLETASK, 0);
252 /* Install the interrupt servers */
253 for (i=0; i<16; i++)
255 if( (1<<i) & (INTF_PORTS|INTF_COPER|INTF_VERTB|INTF_EXTER|INTF_SETCLR))
257 struct Interrupt *is;
258 struct SoftIntList *sil;
259 is = AllocMem
261 sizeof(struct Interrupt) + sizeof(struct SoftIntList),
262 MEMF_CLEAR | MEMF_PUBLIC
264 if( is == NULL )
266 D(bug("[exec] ERROR: Cannot install Interrupt Servers!\n"));
268 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
270 is->is_Code = &IntServer;
271 is->is_Data = sil;
272 NEWLIST((struct List *)sil);
273 SetIntVector(i,is);
275 else
277 struct Interrupt *is;
278 switch (i)
280 case INTB_SOFTINT :
281 is = AllocMem
283 sizeof(struct Interrupt),
284 MEMF_CLEAR | MEMF_PUBLIC
286 if (is == NULL)
288 D(bug("[exec] Error: Cannot install Interrupt Servers!\n"));
289 // Alert(AT_DeadEnd | AN_IntrMem);
291 is->is_Node.ln_Type = NT_SOFTINT; //INTERRUPT;
292 is->is_Node.ln_Pri = 0;
293 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
294 is->is_Data = NULL;
295 is->is_Code = (void *)SoftIntDispatch;
296 SetIntVector(i,is);
297 break;
302 /* Now it's time to calculate exec checksum. It will be used
303 * in future to distinguish whether we'd had proper execBase
304 * before restart */
306 UWORD sum=0, *ptr = &SysBase->SoftVer;
307 int i=((IPTR)&SysBase->IntVects[0] - (IPTR)&SysBase->SoftVer) / 2,
310 /* Calculate sum for every static part from SoftVer to ChkSum */
311 for (j=0;j < i;j++)
313 sum+=*(ptr++);
316 SysBase->ChkSum = ~sum;
319 tsfs = AllocMem(sizeof(struct TaskStorageFreeSlot), MEMF_PUBLIC|MEMF_CLEAR);
320 if (!tsfs)
322 D(bug("[exec] ERROR: Cannot create Task Storage!\n"));
324 tsfs->FreeSlot = 1;
325 AddHead((struct List *)&PrivExecBase(SysBase)->TaskStorageSlots, (struct Node *)tsfs);
327 /* Create boot task. Sigh, we actually create a Process sized Task,
328 since DOS needs to call things which think it has a Process and
329 we don't want to overwrite memory with something strange do we?
331 We do this until at least we can boot dos more cleanly.
334 struct MemList *ml;
336 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
337 t = (struct Task *) AllocMem(sizeof(struct Process), MEMF_PUBLIC|MEMF_CLEAR);
339 if( !ml || !t )
341 D(bug("[exec] ERROR: Cannot create Boot Task!\n"));
343 ml->ml_NumEntries = 1;
344 ml->ml_ME[0].me_Addr = t;
345 ml->ml_ME[0].me_Length = sizeof(struct Process);
347 NEWLIST(&t->tc_MemEntry);
348 NEWLIST(&((struct Process *)t)->pr_MsgPort.mp_MsgList);
350 /* It's the boot process that RunCommand()s the boot shell, so we
351 must have this list initialized */
352 NEWLIST((struct List *)&((struct Process *)t)->pr_LocalVars);
354 AddHead(&t->tc_MemEntry,&ml->ml_Node);
356 t->tc_Node.ln_Name = (char *)exec_name;
357 t->tc_Node.ln_Pri = 0;
358 t->tc_Node.ln_Type = NT_TASK;
359 t->tc_State = TS_RUN;
360 t->tc_SigAlloc = 0xFFFF;
361 t->tc_SPLower = 0; /* This is the system's stack */
362 t->tc_SPUpper = (APTR)~0UL;
363 t->tc_Flags |= TF_ETASK;
365 if (t->tc_Flags & TF_ETASK)
367 t->tc_UnionETask.tc_ETask = AllocVec
369 sizeof(struct IntETask),
370 MEMF_ANY|MEMF_CLEAR
373 if (!t->tc_UnionETask.tc_ETask)
375 D(bug("[exec] Not enough memory for first task\n"));
378 /* Initialise the ETask data. */
379 InitETask(t, t->tc_UnionETask.tc_ETask);
380 t->tc_UnionETask.tc_ETask->et_RegFrame = KrnCreateContext();
382 if (!t->tc_UnionETask.tc_ETask->et_RegFrame)
384 D(bug("[exec] Not enough memory for first task\n"));
388 SysBase->ThisTask = t;
391 D(bug("[exec] Done. SysBase->ThisTask = %08p\n", SysBase->ThisTask));
393 /* We now start up the interrupts */
394 Permit();
395 Enable();
397 D(debugmem());
399 /* Our housekeeper must have the largest possible priority */
400 t = NewCreateTask(TASKTAG_NAME , "Exec housekeeper",
401 TASKTAG_PRI , 127,
402 TASKTAG_PC , ServiceTask,
403 TASKTAG_TASKMSGPORT, &((struct IntExecBase *)SysBase)->ServicePort,
404 TASKTAG_ARG1 , SysBase,
405 TAG_DONE);
406 if (t)
408 set_call_libfuncs(SETNAME(INITLIB), 1, 1, SysBase);
410 D(bug("[exec] InitCode(RTF_COLDSTART)\n"));
411 InitCode(RTF_COLDSTART, 0);
414 D(bug("[exec] I should never get here...\n"));
419 * RomTag scanner.
421 * This function scans kernel for existing Resident modules. If two modules
422 * with the same name are found, the one with higher version or priority wins.
424 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
425 * checksummed. If checksum is proper and all memory pointed in KickMemPtr may
426 * be allocated, then all modules from KickTagPtr are added to RT list
428 * Afterwards the proper RomTagList is created (see InitCode() for details) and
429 * memory after list and nodes is freed.
432 struct rt_node
434 struct Node node;
435 struct Resident *module;
439 void exec_DefaultTaskExit()
441 struct ExecBase *SysBase = priv_SysBase;
442 RemTask(SysBase->ThisTask);
445 IPTR **exec_RomTagScanner(struct TagItem *msg, struct ExecBase *SysBase)
447 struct List rtList; /* List of modules */
448 UWORD *ptr = (UWORD*)(krnGetTagData(KRN_KernelLowest, 0, msg) ^ 0xf8000000); /* Start looking here */
449 UWORD *maxptr = (UWORD*)(krnGetTagData(KRN_KernelHighest, 0, msg) ^ 0xf8000000);
450 struct Resident *res; /* module found */
452 int i;
453 IPTR **RomTag;
455 /* Initialize list */
456 NEWLIST(&rtList);
458 D(bug("[exec] Resident modules (addr: pri version name):\n"));
460 /* Look in whole kernel for resident modules */
463 /* Do we have RTC_MATCHWORD? */
464 if (*ptr == RTC_MATCHWORD)
466 /* Yes, assume we have Resident */
467 res = (struct Resident *)ptr;
469 /* Does rt_MatchTag point to Resident? */
470 if (res == res->rt_MatchTag)
472 /* Yes, it is Resident module */
473 struct rt_node *node;
475 /* Check if there is module with such name already */
476 node = (struct rt_node*)FindName(&rtList, res->rt_Name);
477 if (node)
479 /* Yes, there was such module. It it had lower pri then replace it */
480 if (node->node.ln_Pri <= res->rt_Pri)
482 /* If they have the same Pri but new one has higher Version, replace */
483 if ((node->node.ln_Pri == res->rt_Pri) &&
484 (node->module->rt_Version < res->rt_Version))
486 node->node.ln_Pri = res->rt_Pri;
487 node->module = res;
491 else
493 /* New module. Allocate some memory for it */
494 node = (struct rt_node *)
495 AllocMem(sizeof(struct rt_node),MEMF_PUBLIC|MEMF_CLEAR);
497 if (node)
499 node->node.ln_Name = (char *)res->rt_Name;
500 node->node.ln_Pri = res->rt_Pri;
501 node->module = res;
503 Enqueue(&rtList,(struct Node*)node);
506 ptr+=sizeof(struct Resident)/sizeof(UWORD);
507 continue;
511 /* Get next address... */
512 ptr++;
513 } while (ptr < maxptr);
516 * By now we have valid (and sorted) list of kernel resident modules.
518 * Now, we will have to analyze used-defined RomTags (via KickTagPtr and
519 * KickMemPtr)
521 #warning "TODO: Implement external modules!"
523 * Everything is done now. Allocate buffer for normal RomTag and convert
524 * list to RomTag
527 ListLength(&rtList,i); /* Get length of the list */
529 RomTag = AllocMem((i+1)*sizeof(IPTR),MEMF_PUBLIC | MEMF_CLEAR);
531 if (RomTag)
533 int j;
534 struct rt_node *n;
536 for (j=0; j<i; j++)
538 n = (struct rt_node *)RemHead(&rtList);
539 D(bug("[exec] + 0x%08lx: %4d %3d \"%s\"\n",
540 n->module,
541 n->node.ln_Pri,
542 n->module->rt_Version,
543 n->node.ln_Name));
544 RomTag[j] = (IPTR*)n->module;
545 FreeMem(n, sizeof(struct rt_node));
547 RomTag[i] = 0;
550 return RomTag;
553 AROS_LH1(struct ExecBase *, open,
554 AROS_LHA(ULONG, version, D0),
555 struct ExecBase *, SysBase, 1, Exec)
557 AROS_LIBFUNC_INIT
559 /* I have one more opener. */
560 SysBase->LibNode.lib_OpenCnt++;
561 return SysBase;
563 AROS_LIBFUNC_EXIT
566 AROS_LH0(BPTR, close,
567 struct ExecBase *, SysBase, 2, Exec)
569 AROS_LIBFUNC_INIT
571 /* I have one fewer opener. */
572 SysBase->LibNode.lib_OpenCnt--;
573 return 0;
574 AROS_LIBFUNC_EXIT
577 AROS_LH0I(int, null,
578 struct ExecBase *, SysBase, 4, Exec)
580 AROS_LIBFUNC_INIT
581 return 0;
582 AROS_LIBFUNC_EXIT
586 We temporarily redefine kprintf() so we use the real version in case
587 we have one of these two fn's called before AROSSupportBase is ready.
590 #undef kprintf
591 #undef rkprintf
592 #undef vkprintf
594 static int __kprintf(const UBYTE *fmt, ...)
596 va_list ap;
597 int result = 0;
599 va_start(ap,fmt);
600 result = AROS_SLIB_ENTRY(KrnBug, Kernel, 12)(fmt, ap, NULL);
601 va_end(ap);
603 return result;
606 static int __vkprintf(const UBYTE *fmt, va_list args)
608 return AROS_SLIB_ENTRY(KrnBug, Kernel, 12)(fmt, args, NULL);
611 static int __rkprintf(const STRPTR mainSystem, const STRPTR subSystem, int level, const UBYTE *fmt, ...)
613 va_list ap;
614 int result = 0;
616 va_start(ap,fmt);
617 result = AROS_SLIB_ENTRY(KrnBug, Kernel, 12)(fmt, ap, NULL);
618 va_end(ap);
620 return result;
623 struct Library * PrepareAROSSupportBase(struct ExecBase *SysBase)
625 struct AROSSupportBase *AROSSupportBase =
626 AllocMem(sizeof(struct AROSSupportBase), MEMF_CLEAR);
628 AROSSupportBase->kprintf = (void *)__kprintf;
629 AROSSupportBase->rkprintf = (void *)__rkprintf;
630 AROSSupportBase->vkprintf = (void *)__vkprintf;
632 return (struct Library *)AROSSupportBase;
635 void _aros_not_implemented(char *string) {}