2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Sets up the ExecBase a bit. (Mostly clearing).
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>
24 #include <proto/alib.h>
25 #include <proto/exec.h>
26 #include <proto/kernel.h>
28 #include LC_LIBDEFS_FILE
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
);
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
)
87 if (((IPTR
)sysbase
) & 0x80000001)
90 if (sysbase
->ChkBase
!= ~(IPTR
)sysbase
)
92 if (sysbase
->SoftVer
!= VERSION_NUMBER
)
95 return GetSysBaseChkSum(sysbase
) == 0xffff;
98 UWORD
GetSysBaseChkSum(struct ExecBase
*sysbase
)
101 UWORD
*p
= (UWORD
*)&sysbase
->SoftVer
;
102 while (p
<= &sysbase
->ChkSum
)
107 void SetSysBaseChkSum(void)
109 SysBase
->ChkBase
=~(IPTR
)SysBase
;
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
)
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
);
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
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");
217 PrivExecBase(SysBase
)->IntFlags
= EXECF_MungWall
;
219 opts
= strcasestr(args
, "stacksnoop");
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=");
232 SysBase
->ex_DebugFlags
= ParseFlags(&opts
[9], ExecFlagNames
);
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
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
)
262 VOID
**fp
= LIBFUNCTABLE
;
263 APTR ColdCapture
= NULL
, CoolCapture
= NULL
, WarmCapture
= NULL
;
264 APTR KickMemPtr
= NULL
, KickTagPtr
= NULL
, KickCheckSum
= NULL
;
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
))
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
329 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
|MEMF_CLEAR
);
330 D(bug("[exec] Boot task 0x%p\n", t
));
333 DINIT("ERROR: Cannot create Boot Task!");
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
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
;