adapted to new ResetSpin parameter
[aros:aros.git] / AROS / rom / exec / prepareexecbase.c
1 /*
2     Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3     $Id$
4
5     Desc: Sets up the ExecBase a bit. (Mostly clearing).
6     Lang:
7 */
8
9 #include <aros/asmcall.h>
10 #include <aros/debug.h>
11 #include <aros/kernel.h>
12 #include <clib/macros.h>
13 #include <exec/types.h>
14 #include <exec/lists.h>
15 #include <exec/memory.h>
16 #include <exec/memheaderext.h>
17 #include <exec/resident.h>
18 #include <exec/execbase.h>
19 #include <exec/libraries.h>
20 #include <aros/arossupportbase.h>
21
22 #include <string.h>
23
24 #include <proto/alib.h>
25 #include <proto/exec.h>
26 #include <proto/kernel.h>
27
28 #include LC_LIBDEFS_FILE
29 #include "etask.h"
30 #include "memory.h"
31 #include "exec_util.h"
32 #include "exec_debug.h"
33 #include "exec_intern.h"
34
35 #undef kprintf /* This can't be used in the code here */
36
37 extern void *LIBFUNCTABLE[];
38
39 extern struct Resident Exec_resident; /* Need this for lib_IdString */
40
41 extern void Exec_TrapHandler(ULONG trapNum);
42 AROS_LD3(ULONG, MakeFunctions,
43          AROS_LDA(APTR, target, A0),
44          AROS_LDA(CONST_APTR, functionArray, A1),
45          AROS_LDA(CONST_APTR, funcDispBase, A2),
46          struct ExecBase *, SysBase, 15, Exec);
47
48 /* Default finaliser. */
49 static void Exec_TaskFinaliser(void)
50 {
51     /* Get rid of current task. */
52     RemTask(NULL);
53 }
54
55 #undef kprintf
56 #undef rkprintf
57 #undef vkprintf
58
59 void _aros_not_implemented(char *X)
60 {
61     kprintf("Unsupported function at offset -0x%h in %s\n",
62             ABS(*(WORD *)((&X)[-1]-2)),
63             ((struct Library *)(&X)[-2])->lib_Node.ln_Name);
64 }
65
66 struct Library *PrepareAROSSupportBase (struct MemHeader *mh)
67 {
68     struct AROSSupportBase *AROSSupportBase;
69
70     AROSSupportBase = Allocate(mh, sizeof(struct AROSSupportBase));
71
72     AROSSupportBase->kprintf = (void *)kprintf;
73     AROSSupportBase->rkprintf = (void *)rkprintf;
74     AROSSupportBase->vkprintf = (void *)vkprintf;
75
76     AROSSupportBase->StdOut = NULL;
77     AROSSupportBase->DebugConfig = NULL;
78
79     return (struct Library *)AROSSupportBase;
80 }
81
82 BOOL IsSysBaseValid(struct ExecBase *sysbase)
83 {
84     if (sysbase == NULL)
85         return FALSE;
86 #ifdef __mc68000
87     if (((IPTR)sysbase) & 0x80000001)
88         return FALSE;
89 #endif
90     if (sysbase->ChkBase != ~(IPTR)sysbase)
91         return FALSE;
92     if (sysbase->SoftVer != VERSION_NUMBER)
93         return FALSE;
94     /* more tests? */
95     return GetSysBaseChkSum(sysbase) == 0xffff;
96 }
97
98 UWORD GetSysBaseChkSum(struct ExecBase *sysbase)
99 {
100      UWORD sum = 0;
101      UWORD *p = (UWORD*)&sysbase->SoftVer;
102      while (p <= &sysbase->ChkSum)
103         sum += *p++;
104      return sum;
105 }
106
107 void SetSysBaseChkSum(void)
108 {
109      SysBase->ChkBase=~(IPTR)SysBase;
110      SysBase->ChkSum = 0;
111      SysBase->ChkSum = GetSysBaseChkSum(SysBase) ^ 0xffff;
112 }
113
114 static APTR allocmem(struct MemHeader *mh, ULONG size, ULONG attributes)
115 {
116     APTR ret;
117
118     if (mh->mh_Attributes & MEMF_MANAGED)
119     {
120         struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
121
122         if (mhe->mhe_Alloc)
123             ret = mhe->mhe_Alloc(mhe, size, &attributes);
124         else
125             ret = 0;
126     }
127     else
128     {
129         ret = stdAlloc(mh, NULL, size, attributes, NULL, NULL);
130     }
131
132     return ret;
133 }
134
135 /*
136  *  PrepareExecBase() will initialize the ExecBase to default values.
137  *  MemHeader and ExecBase itself will already be added to appropriate
138  *  lists. You don't need to do this yourself.
139  *
140  *  WARNING: this routine intentionally sets up global SysBase.
141  *  This is done because:
142  *  1. PrepareAROSSupportBase() calls Allocate() which relies on functional SysBase
143  *  2. After PrepareAROSSupportBase() it is possible to call debug output functions
144  *     (kprintf() etc). Yes, KernelBase is not set up yet, but remember that kernel.resource
145  *     may have patched functions in AROSSupportBase so that KernelBase is not needed there.
146  *  3. Existing ports (at least UNIX-hosted and Windows-hosted) rely on the fact that SysBase is
147  *     set up here.
148  *
149  *  Resume: please be extremely careful, study existing code, and think five times if you decide to
150  *  change this. You WILL break existing ports if you do not modify their code accordingly. There's
151  *  nothing really bad in the fact that global SysBase is touched here and changing this does not
152  *  really win something.
153  *                                              Pavel Fedin <pavel_fedin@mail.ru>
154  */
155 struct ExecBase *PrepareExecBase(struct MemHeader *mh, struct TagItem *msg)
156 {
157     ULONG negsize = 0;
158     VOID  **fp = LIBFUNCTABLE;
159     APTR ColdCapture = NULL, CoolCapture = NULL, WarmCapture = NULL;
160     APTR KickMemPtr = NULL, KickTagPtr = NULL, KickCheckSum = NULL;
161     APTR mem;
162     ULONG i;
163     char *args;
164
165
166     /*
167      * Copy reset proof pointers if old SysBase is valid.
168      * Additional platform-specific code is needed in order to test
169      * address validity. This routine should zero out SysBase if it is invalid.
170      */
171     if (IsSysBaseValid(SysBase))
172     {
173         ColdCapture  = SysBase->ColdCapture;
174         CoolCapture  = SysBase->CoolCapture;
175         WarmCapture  = SysBase->WarmCapture;
176         KickMemPtr   = SysBase->KickMemPtr; 
177         KickTagPtr   = SysBase->KickTagPtr;
178         KickCheckSum = SysBase->KickCheckSum;
179     }
180
181     /* Calculate the size of the vector table */
182     while (*fp++ != (VOID *) -1) negsize += LIB_VECTSIZE;
183     
184     /* Align library base */
185     negsize = AROS_ALIGN(negsize);
186
187     /* Allocate memory for library base */
188     mem = allocmem(mh, negsize + sizeof(struct IntExecBase), MEMF_CLEAR);
189     if (!mem)
190         return NULL;
191
192     SysBase = mem + negsize;
193
194 #ifdef HAVE_PREPAREPLATFORM
195     /* Setup platform-specific data */
196     if (!Exec_PreparePlatform(&PD(SysBase), msg))
197         return NULL;
198 #endif
199
200     /* Setup function vectors */
201     AROS_CALL3(ULONG, AROS_SLIB_ENTRY(MakeFunctions, Exec, 15),
202               AROS_UFCA(APTR, SysBase, A0),
203               AROS_UFCA(CONST_APTR, LIBFUNCTABLE, A1),
204               AROS_UFCA(CONST_APTR, NULL, A2),
205               struct ExecBase *, SysBase);
206
207     /* Set default values */
208     SysBase->LibNode.lib_Node.ln_Type = NT_LIBRARY;
209     SysBase->LibNode.lib_Node.ln_Pri  = -100;
210     SysBase->LibNode.lib_Node.ln_Name = (char *)Exec_resident.rt_Name;
211     SysBase->LibNode.lib_IdString     = (char *)Exec_resident.rt_IdString;
212     SysBase->LibNode.lib_Version      = VERSION_NUMBER;
213     SysBase->LibNode.lib_Revision     = REVISION_NUMBER;
214     SysBase->LibNode.lib_OpenCnt      = 1;
215     SysBase->LibNode.lib_NegSize      = negsize;
216     SysBase->LibNode.lib_PosSize      = sizeof(struct IntExecBase);
217     SysBase->LibNode.lib_Flags        = LIBF_CHANGED | LIBF_SUMUSED;
218
219     NEWLIST(&SysBase->MemList);
220     SysBase->MemList.lh_Type = NT_MEMORY;
221     
222     NEWLIST(&SysBase->ResourceList);
223     SysBase->ResourceList.lh_Type = NT_RESOURCE;
224     
225     NEWLIST(&SysBase->DeviceList);
226     SysBase->DeviceList.lh_Type = NT_DEVICE;
227
228     NEWLIST(&SysBase->IntrList);
229     SysBase->IntrList.lh_Type = NT_INTERRUPT;
230
231     NEWLIST(&SysBase->LibList);
232     SysBase->LibList.lh_Type = NT_LIBRARY;
233
234     /* Add exec.library to system library list */
235     ADDHEAD(&SysBase->LibList, &SysBase->LibNode.lib_Node);
236
237     NEWLIST(&SysBase->PortList);
238     SysBase->PortList.lh_Type = NT_MSGPORT;
239
240     NEWLIST(&SysBase->TaskReady);
241     SysBase->TaskReady.lh_Type = NT_TASK;
242
243     NEWLIST(&SysBase->TaskWait);
244     SysBase->TaskWait.lh_Type = NT_TASK;
245
246     NEWLIST(&SysBase->SemaphoreList);
247     SysBase->SemaphoreList.lh_Type = NT_SEMAPHORE;
248
249     NEWLIST(&SysBase->ex_MemHandlers);
250
251     for (i = 0; i < 5; i++)
252     {
253         NEWLIST(&SysBase->SoftInts[i].sh_List);
254         SysBase->SoftInts[i].sh_List.lh_Type = NT_INTERRUPT;
255     }
256
257     NEWLIST(&PrivExecBase(SysBase)->ResetHandlers);
258     NEWLIST(&PrivExecBase(SysBase)->AllocMemList);
259     NEWLIST(&PrivExecBase(SysBase)->AllocatorCtxList);
260
261     InitSemaphore(&PrivExecBase(SysBase)->MemListSem);
262     InitSemaphore(&PrivExecBase(SysBase)->LowMemSem);
263
264     /* No need to initialize those locks. Just a reminder, if it becomes necessary in the future */
265     //ResetSpin(&PrivExecBase(SysBase)->semaphore_spinlock, 1);
266     //ResetSpin(&PrivExecBase(SysBase)->LibList_spinlock, 1);
267
268     SysBase->SoftVer        = VERSION_NUMBER;
269     SysBase->Quantum        = 4;
270     SysBase->TaskTrapCode   = Exec_TrapHandler;
271     SysBase->TaskExceptCode = NULL;
272     SysBase->TaskExitCode   = Exec_TaskFinaliser;
273     SysBase->TaskSigAlloc   = 0xFFFF;
274     SysBase->TaskTrapAlloc  = 0;
275
276     /* Parse some arguments from command line */
277     args = (char *)LibGetTagData(KRN_CmdLine, 0, msg);
278     if (args)
279     {
280         char *opts;
281
282         /*
283          * Enable mungwall before the first AllocMem().
284          * Yes, we have actually already called stdAlloc() once
285          * in order to allocate memory for SysBase itself, however
286          * this is not a real problem because it is never going
287          * to be freed.
288          *
289          * We store mungwall setting in private flags because it must not be
290          * switched at runtime (or hard crash will happen).
291          */
292         opts = strcasestr(args, "mungwall");
293         if (opts)
294             PrivExecBase(SysBase)->IntFlags = EXECF_MungWall;
295
296         opts = strcasestr(args, "stacksnoop");
297         if (opts)
298             PrivExecBase(SysBase)->IntFlags = EXECF_StackSnoop;
299
300         /*
301          * Parse system runtime debug flags.
302          * These are public. In future they will be editable by prefs program.
303          * However in order to be able to turn them on during early startup,
304          * we apply them also here.
305          */
306         opts = strcasestr(args, "sysdebug=");
307         if (opts)
308             SysBase->ex_DebugFlags = ParseFlags(&opts[9], ExecFlagNames);
309     }
310
311     NEWLIST(&PrivExecBase(SysBase)->TaskStorageSlots);
312 #if AROS_SMP
313     NEWLIST(&PrivExecBase(SysBase)->CPUList);
314 #endif
315
316     SetSysBaseChkSum();
317
318     /* Add our initial MemHeader */
319     ADDHEAD(&SysBase->MemList, &mh->mh_Node);
320
321     /* Bring back saved values (or NULLs) */
322     SysBase->ColdCapture  = ColdCapture;
323     SysBase->CoolCapture  = CoolCapture;
324     SysBase->WarmCapture  = WarmCapture;
325     SysBase->KickMemPtr   = KickMemPtr;
326     SysBase->KickTagPtr   = KickTagPtr;
327     SysBase->KickCheckSum = KickCheckSum;
328
329     SysBase->DebugAROSBase = PrepareAROSSupportBase(mh);
330
331     return SysBase;
332 }