Added a reset handler.
[AROS.git] / rom / exec / prepareexecbase.c
blobdd7a8f640edd18ac371a423bd58799bf0bd02e95
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Sets up the ExecBase a bit. (Mostly clearing).
6 Lang:
7 */
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>
22 #include <string.h>
24 #include <proto/alib.h>
25 #include <proto/exec.h>
26 #include <proto/kernel.h>
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"
35 #undef kprintf /* This can't be used in the code here */
37 extern void *LIBFUNCTABLE[];
39 extern struct Resident Exec_resident; /* Need this for lib_IdString */
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);
48 /* Default finaliser. */
49 static void Exec_TaskFinaliser(void)
51 /* Get rid of current task. */
52 RemTask(SysBase->ThisTask);
55 #undef kprintf
56 #undef rkprintf
57 #undef vkprintf
59 void _aros_not_implemented(char *X)
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);
66 struct Library *PrepareAROSSupportBase (struct MemHeader *mh)
68 struct AROSSupportBase *AROSSupportBase;
70 AROSSupportBase = Allocate(mh, sizeof(struct AROSSupportBase));
72 AROSSupportBase->kprintf = (void *)kprintf;
73 AROSSupportBase->rkprintf = (void *)rkprintf;
74 AROSSupportBase->vkprintf = (void *)vkprintf;
76 AROSSupportBase->StdOut = NULL;
77 AROSSupportBase->DebugConfig = NULL;
79 return (struct Library *)AROSSupportBase;
82 BOOL IsSysBaseValid(struct ExecBase *sysbase)
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;
98 UWORD GetSysBaseChkSum(struct ExecBase *sysbase)
100 UWORD sum = 0;
101 UWORD *p = (UWORD*)&sysbase->SoftVer;
102 while (p <= &sysbase->ChkSum)
103 sum += *p++;
104 return sum;
107 void SetSysBaseChkSum(void)
109 SysBase->ChkBase=~(IPTR)SysBase;
110 SysBase->ChkSum = 0;
111 SysBase->ChkSum = GetSysBaseChkSum(SysBase) ^ 0xffff;
115 * Exec.library initializer. Prepares exec.library for future use.
116 * All lists have to be initialized.
117 * This function is currently used directly by i386-pc port. When the port
118 * is fully updated, this function can be made static for optimization.
120 void InitExecBase(struct ExecBase *SysBase, ULONG negsize, struct TagItem *msg)
122 ULONG i;
123 char *args;
125 /* Setup function vectors */
126 AROS_CALL3(ULONG, AROS_SLIB_ENTRY(MakeFunctions, Exec, 15),
127 AROS_UFCA(APTR, SysBase, A0),
128 AROS_UFCA(CONST_APTR, LIBFUNCTABLE, A1),
129 AROS_UFCA(CONST_APTR, NULL, A2),
130 struct ExecBase *, SysBase);
132 SysBase->LibNode.lib_Node.ln_Type = NT_LIBRARY;
133 SysBase->LibNode.lib_Node.ln_Pri = -100;
134 SysBase->LibNode.lib_Node.ln_Name = (char *)Exec_resident.rt_Name;
135 SysBase->LibNode.lib_IdString = (char *)Exec_resident.rt_IdString;
136 SysBase->LibNode.lib_Version = VERSION_NUMBER;
137 SysBase->LibNode.lib_Revision = REVISION_NUMBER;
138 SysBase->LibNode.lib_OpenCnt = 1;
139 SysBase->LibNode.lib_NegSize = negsize;
140 SysBase->LibNode.lib_PosSize = sizeof(struct IntExecBase);
141 SysBase->LibNode.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
143 NEWLIST(&SysBase->MemList);
144 SysBase->MemList.lh_Type = NT_MEMORY;
146 NEWLIST(&SysBase->ResourceList);
147 SysBase->ResourceList.lh_Type = NT_RESOURCE;
149 NEWLIST(&SysBase->DeviceList);
150 SysBase->DeviceList.lh_Type = NT_DEVICE;
152 NEWLIST(&SysBase->IntrList);
153 SysBase->IntrList.lh_Type = NT_INTERRUPT;
155 NEWLIST(&SysBase->LibList);
156 SysBase->LibList.lh_Type = NT_LIBRARY;
158 /* Add exec.library to system library list */
159 ADDHEAD(&SysBase->LibList, &SysBase->LibNode.lib_Node);
161 NEWLIST(&SysBase->PortList);
162 SysBase->PortList.lh_Type = NT_MSGPORT;
164 NEWLIST(&SysBase->TaskReady);
165 SysBase->TaskReady.lh_Type = NT_TASK;
167 NEWLIST(&SysBase->TaskWait);
168 SysBase->TaskWait.lh_Type = NT_TASK;
170 NEWLIST(&SysBase->SemaphoreList);
171 SysBase->TaskWait.lh_Type = NT_SEMAPHORE;
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_INTERRUPT;
181 NEWLIST(&PrivExecBase(SysBase)->ResetHandlers);
182 NEWLIST(&PrivExecBase(SysBase)->AllocMemList);
184 InitSemaphore(&PrivExecBase(SysBase)->MemListSem);
185 InitSemaphore(&PrivExecBase(SysBase)->LowMemSem);
187 SysBase->SoftVer = VERSION_NUMBER;
188 SysBase->Quantum = 4;
189 SysBase->TaskTrapCode = Exec_TrapHandler;
190 SysBase->TaskExceptCode = NULL;
191 SysBase->TaskExitCode = Exec_TaskFinaliser;
192 SysBase->TaskSigAlloc = 0xFFFF;
193 SysBase->TaskTrapAlloc = 0;
195 /* Default frequencies. FIXME: PowerSupplyFrequency is still used as a multiplier in i386-pc port. */
196 SysBase->VBlankFrequency = 50;
197 SysBase->PowerSupplyFrequency = 1;
199 /* Parse some arguments from command line */
200 args = (char *)LibGetTagData(KRN_CmdLine, 0, msg);
201 if (args)
203 char *opts;
206 * Enable mungwall before the first AllocMem().
207 * Yes, we have actually already called stdAlloc() once
208 * in order to allocate memory for SysBase itself, however
209 * this is not a real problem because it is never going
210 * to be freed.
212 * We store mungwall setting in private flags because it must not be
213 * switched at runtime (or hard crash will happen).
215 opts = strcasestr(args, "mungwall");
216 if (opts)
217 PrivExecBase(SysBase)->IntFlags = EXECF_MungWall;
219 opts = strcasestr(args, "stacksnoop");
220 if (opts)
221 PrivExecBase(SysBase)->IntFlags = EXECF_StackSnoop;
225 * Parse system runtime debug flags.
226 * These are public. In future they will be editable by prefs program.
227 * However in order to be able to turn them on during early startup,
228 * we apply them also here.
230 opts = strcasestr(args, "sysdebug=");
231 if (opts)
232 SysBase->ex_DebugFlags = ParseFlags(&opts[9], ExecFlagNames);
235 SetSysBaseChkSum();
239 * PrepareExecBase() will initialize the ExecBase to default values.
240 * MemHeader and ExecBase itself will already be added to appropriate
241 * lists. You don't need to do this yourself.
243 * WARNING: this routine intentionally sets up global SysBase.
244 * This is done because:
245 * 1. PrepareAROSSupportBase() calls Allocate() which relies on functional SysBase
246 * 2. After PrepareAROSSupportBase() it is possible to call debug output functions
247 * (kprintf() etc). Yes, KernelBase is not set up yet, but remember that kernel.resource
248 * may have patched functions in AROSSupportBase so that KernelBase is not needed there.
249 * 3. Existing ports (at least UNIX-hosted and Windows-hosted) rely on the fact that SysBase is
250 * set up here.
252 * Resume: please be extremely careful, study existing code, and think five times if you decide to
253 * change this. You WILL break existing ports if you do not modify their code accordingly. There's
254 * nothing really bad in the fact that global SysBase is touched here and changing this does not
255 * really win something.
256 * Pavel Fedin <pavel_fedin@mail.ru>
258 struct ExecBase *PrepareExecBase(struct MemHeader *mh, struct TagItem *msg)
260 ULONG negsize = 0;
261 ULONG totalsize;
262 VOID **fp = LIBFUNCTABLE;
263 APTR ColdCapture = NULL, CoolCapture = NULL, WarmCapture = NULL;
264 APTR KickMemPtr = NULL, KickTagPtr = NULL, KickCheckSum = NULL;
265 struct Task *t;
268 * Copy reset proof pointers if old SysBase is valid.
269 * Additional platform-specific code is needed in order to test
270 * address validity. This routine should zero out SysBase if it is invalid.
272 if (IsSysBaseValid(SysBase))
274 ColdCapture = SysBase->ColdCapture;
275 CoolCapture = SysBase->CoolCapture;
276 WarmCapture = SysBase->WarmCapture;
277 KickMemPtr = SysBase->KickMemPtr;
278 KickTagPtr = SysBase->KickTagPtr;
279 KickCheckSum = SysBase->KickCheckSum;
282 /* Calculate the size of the vector table */
283 while (*fp++ != (VOID *) -1) negsize += LIB_VECTSIZE;
285 /* Align library base */
286 negsize = AROS_ALIGN(negsize);
288 /* Allocate memory for library base */
289 totalsize = negsize + sizeof(struct IntExecBase);
290 SysBase = (struct ExecBase *)((UBYTE *)stdAlloc(mh, totalsize, MEMF_CLEAR, NULL) + negsize);
292 #ifdef HAVE_PREPAREPLATFORM
293 /* Setup platform-specific data */
294 if (!Exec_PreparePlatform(&PD(SysBase), msg))
295 return NULL;
296 #endif
298 /* Set default values */
299 InitExecBase(SysBase, negsize, msg);
301 /* Add our initial MemHeader */
302 ADDHEAD(&SysBase->MemList, &mh->mh_Node);
304 /* Bring back saved values (or NULLs) */
305 SysBase->ColdCapture = ColdCapture;
306 SysBase->CoolCapture = CoolCapture;
307 SysBase->WarmCapture = WarmCapture;
308 SysBase->KickMemPtr = KickMemPtr;
309 SysBase->KickTagPtr = KickTagPtr;
310 SysBase->KickCheckSum = KickCheckSum;
312 SysBase->DebugAROSBase = PrepareAROSSupportBase(mh);
315 * Create boot task skeleton.
316 * In order to call libraries with base-relative global variables we may need correctly set up
317 * tc_SPLower and tc_SPUpper. We do it in kernel.resource startup code, when this function returns.
318 * Let's remember that it's boot-time MemHeader. It can be small and/or slow, so keep amount of
319 * allocations at minimum. We'll complete our task later, in exec.library normal init.
320 * Yes, AllocMem() and not direct stdAlloc(), because boot task will be freed when it's done,
321 * and its allocation needs to be mungwall-aware.
323 * FIXME: In future when memory protection is implemented, AllocMem() may represent a problem here
324 * because it's going to rely on functional kernel.resource. Is it okay to move boot task allocation
325 * to delayed init code in AddResource() ? This only may represent a problem with old native i386 and
326 * PPC ports, which use own init code, which can be badly compatible with the base code. Merge is really
327 * needed.
329 t = AllocMem(sizeof(struct Task), MEMF_PUBLIC|MEMF_CLEAR);
330 D(bug("[exec] Boot task 0x%p\n", t));
331 if (!t)
333 DINIT("ERROR: Cannot create Boot Task!");
334 return NULL;
337 NEWLIST(&t->tc_MemEntry);
339 t->tc_Node.ln_Name = "Boot Task";
340 t->tc_Node.ln_Type = NT_TASK;
341 t->tc_Node.ln_Pri = 0;
342 t->tc_State = TS_RUN;
343 t->tc_SigAlloc = 0xFFFF;
345 * Boot-time stack can be placed anywhere in memory.
346 * In order to avoid complex platform-dependent mechanism for querying its limits
347 * we simply shut up stack checking in kernel.resource by specifying the whole address
348 * space as limits.
349 * If needed, real stack size can be set up later, in kernel.resource startup code
350 * after it has called us. It knows where the stack is.
352 t->tc_SPLower = NULL;
353 t->tc_SPUpper = (APTR)~0;
356 * Set the current task and elapsed time for it. However, multitasking is
357 * not started up yet (and can't, because this is just a barebone task.
359 SysBase->ThisTask = t;
360 SysBase->Elapsed = SysBase->Quantum;
362 return SysBase;