rom/exec: All ETask memory handling is done in exec_util.c
[AROS.git] / rom / exec / exec_init.c
blob301b4a4dc7dc8d33fa41708274aab92805e0c0f5
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: exec.library resident and initialization.
6 Lang: english
7 */
9 #include <exec/lists.h>
10 #include <exec/execbase.h>
11 #include <exec/interrupts.h>
12 #include <exec/resident.h>
13 #include <exec/memory.h>
14 #include <exec/alerts.h>
15 #include <exec/tasks.h>
16 #include <hardware/intbits.h>
18 #include <aros/symbolsets.h>
19 #include <aros/system.h>
20 #include <aros/arossupportbase.h>
21 #include <aros/asmcall.h>
22 #include <aros/config.h>
24 #include <aros/debug.h>
26 #include <proto/arossupport.h>
27 #include <proto/exec.h>
28 #include <proto/kernel.h>
30 #include "exec_debug.h"
31 #include "exec_intern.h"
32 #include "exec_util.h"
33 #include "etask.h"
34 #include "intservers.h"
35 #include "memory.h"
36 #include "taskstorage.h"
38 #include LC_LIBDEFS_FILE
40 static const UBYTE name[];
41 static const UBYTE version[];
43 /* This comes from genmodule */
44 extern const char LIBEND;
46 AROS_UFP3S(struct ExecBase *, GM_UNIQUENAME(init),
47 AROS_UFPA(struct MemHeader *, mh, D0),
48 AROS_UFPA(struct TagItem *, tagList, A0),
49 AROS_UFPA(struct ExecBase *, sysBase, A6));
52 * exec.library ROMTag.
54 * It has RTF_COLDSTART level specified, however it actually runs at SINGLETASK
55 * (no multitasking, incomplete boot task).
56 * This is supposed to be the first COLDSTART resident to be executed. Its job is
57 * to complete the boot task and enable multitasking (which actually means entering
58 * COLDSTART level).
59 * Such mechanism allows kernel.resource boot code to do some additional setup after
60 * all SINGLETASK residents are run. Usually these are various lowlevel hardware resources
61 * (like acpi.resource, efi.resource, etc) which can be needed for kernel.resource to
62 * complete own setup. This helps to get rid of additional ROMTag hooks.
63 * There's one more magic with this ROMTag: it's called twice. First time it's called manually
64 * from within krnPrepareExecBase(), for initial ExecBase creation. This magic is described below.
66 * WARNING: the CPU privilege level must be set to user before calling InitCode(RTF_COLDSTART)!
68 const struct Resident Exec_resident =
70 RTC_MATCHWORD,
71 (struct Resident *)&Exec_resident,
72 (APTR)&LIBEND,
73 RTF_COLDSTART,
74 VERSION_NUMBER,
75 NT_LIBRARY,
76 120,
77 (STRPTR)name,
78 (STRPTR)&version[6],
79 &GM_UNIQUENAME(init),
82 static const UBYTE name[] = MOD_NAME_STRING;
83 static const UBYTE version[] = VERSION_STRING;
85 extern void debugmem(void);
87 THIS_PROGRAM_HANDLES_SYMBOLSETS
88 DEFINESET(INITLIB)
89 DEFINESET(PREINITLIB)
91 AROS_UFH3S(struct ExecBase *, GM_UNIQUENAME(init),
92 AROS_UFHA(struct MemHeader *, mh, D0),
93 AROS_UFHA(struct TagItem *, tagList, A0),
94 AROS_UFHA(struct ExecBase *, origSysBase, A6)
97 AROS_USERFUNC_INIT
99 struct TaskStorageFreeSlot *tsfs;
100 struct Task *t;
101 struct MemList *ml;
102 struct ExceptionContext *ctx;
103 int i;
106 * exec.library init routine is a little bit magic. The magic is that it
107 * can be run twice.
108 * First time it's run manually from kernel.resource's ROMTag scanner in order
109 * to create initial ExecBase. This condition is determined by origSysBase == NULL
110 * passed to this function. In this case the routine expects two more arguments:
111 * mh - an initial MemHeader in which ExecBase will be constructed.
112 * tagList - boot information passed from the bootstrap. It is used to parse
113 * certain command-line arguments.
115 * Second time it's run as part of normal modules initialization sequence, at the
116 * end of all RTS_SINGLETASK modules. At this moment we already have a complete
117 * memory list and working kernel.resource. Now the job is to complete the boot task
118 * structure, and start up multitasking.
120 if (!origSysBase)
121 return PrepareExecBase(mh, tagList);
123 DINIT("exec.library init");
126 * Call platform-specific pre-init code (if any). Return values are not checked.
127 * Note that Boot Task is still incomplete here, and there's no multitasking yet.
129 * TODO: Amiga(tm) port may call PrepareExecBaseMove() here instead of hardlinking
130 * it from within the boot code.
132 * NOTE: All functions will be passed origSysBase value. This is the original
133 * ExecBase pointer in case if it was moved. The new pointer will be in global
134 * SysBase then.
136 set_call_libfuncs(SETNAME(PREINITLIB), 1, 0, origSysBase);
139 * kernel.resource is up and running and memory list is complete.
140 * Global SysBase is set to its final value. We've got KernelBase and AllocMem() works.
141 * Initialize free task storage slots management
143 tsfs = AllocMem(sizeof(struct TaskStorageFreeSlot), MEMF_PUBLIC|MEMF_CLEAR);
144 if (!tsfs)
146 DINIT("ERROR: Could not allocate free slot node!");
147 return NULL;
149 tsfs->FreeSlot = 1;
150 AddHead((struct List *)&PrivExecBase(SysBase)->TaskStorageSlots, (struct Node *)tsfs);
152 /* Now we are ready to become a Boot Task and turn on the multitasking */
153 t = AllocMem(sizeof(struct Task), MEMF_PUBLIC|MEMF_CLEAR);
154 ml = AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
155 ctx = KrnCreateContext();
157 D(bug("[exec] Boot Task 0x%p, ETask 0x%p, CPU context 0x%p\n", t, t->tc_UnionETask.tc_ETask, ctx));
159 if (!t || !ml || !ctx)
161 DINIT("Not enough memory for first task");
162 return NULL;
165 NEWLIST(&t->tc_MemEntry);
167 t->tc_Node.ln_Name = "Boot Task";
168 t->tc_Node.ln_Type = NT_TASK;
169 t->tc_Node.ln_Pri = 0;
170 t->tc_State = TS_RUN;
171 t->tc_SigAlloc = 0xFFFF;
174 * Boot-time stack can be placed anywhere in memory.
175 * In order to avoid complex platform-dependent mechanism for querying its limits
176 * we simply shut up stack checking in kernel.resource by specifying the whole address
177 * space as limits.
179 t->tc_SPLower = NULL;
180 t->tc_SPUpper = (APTR)~0;
183 * Build a memory list for the task.
184 * It doesn't include stack because it wasn't allocated by us.
186 ml->ml_NumEntries = 1;
187 ml->ml_ME[0].me_Addr = t;
188 ml->ml_ME[0].me_Length = sizeof(struct Task);
189 AddHead(&t->tc_MemEntry, &ml->ml_Node);
191 /* Create a ETask structure and attach CPU context */
192 InitETask(t);
193 if (!t->tc_UnionETask.tc_ETask)
195 DINIT("Not enough memory for first task");
196 return NULL;
198 GetIntETask(t)->iet_Context = ctx;
201 * Set the current task and elapsed time for it.
202 * Set ThisTask only AFTER InitETask() has been called. InitETask() sets et_Parent
203 * to FindTask(NULL). We must get NULL there, otherwise we'll get task looped on itself.
205 SysBase->ThisTask = t;
206 SysBase->Elapsed = SysBase->Quantum;
208 /* Install the interrupt servers. Again, do it here because allocations are needed. */
209 for (i=0; i < 16; i++)
211 struct Interrupt *is;
213 if (i != INTB_SOFTINT)
215 struct SoftIntList *sil;
217 is = AllocMem(sizeof(struct Interrupt) + sizeof(struct SoftIntList), MEMF_CLEAR|MEMF_PUBLIC);
218 if (is == NULL)
220 DINIT("ERROR: Cannot install Interrupt Servers!");
221 Alert( AT_DeadEnd | AN_IntrMem );
224 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
226 if (i == INTB_VERTB)
227 is->is_Code = &VBlankServer;
228 else
229 is->is_Code = &IntServer;
230 is->is_Data = sil;
231 NEWLIST((struct List *)sil);
232 SetIntVector(i,is);
234 else
236 struct Interrupt * is;
238 is = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR|MEMF_PUBLIC);
239 if (NULL == is)
241 DINIT("Error: Cannot install SoftInt Handler!\n");
242 Alert( AT_DeadEnd | AN_IntrMem );
245 is->is_Node.ln_Type = NT_INTERRUPT;
246 is->is_Node.ln_Pri = 0;
247 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
248 is->is_Data = NULL;
249 is->is_Code = (void *)SoftIntDispatch;
250 SetIntVector(i,is);
254 /* We now start up the interrupts */
255 Permit();
256 Enable();
258 D(debugmem());
260 /* Call platform-specific init code (if any) */
261 set_call_libfuncs(SETNAME(INITLIB), 1, 1, SysBase);
263 /* Multitasking is on. Call CoolCapture. */
264 if (SysBase->CoolCapture)
266 DINIT("Calling CoolCapture at 0x%p", SysBase->CoolCapture);
268 AROS_UFC1(void, SysBase->CoolCapture,
269 AROS_UFCA(struct Library *, (struct Library *)SysBase, A6));
272 /* Done. Following the convention, we return our base pointer. */
273 return SysBase;
275 AROS_USERFUNC_EXIT
278 AROS_PLH1(struct ExecBase *, open,
279 AROS_LHA(ULONG, version, D0),
280 struct ExecBase *, SysBase, 1, Exec)
282 AROS_LIBFUNC_INIT
284 /* I have one more opener. */
285 SysBase->LibNode.lib_OpenCnt++;
286 return SysBase;
287 AROS_LIBFUNC_EXIT
290 AROS_PLH0(BPTR, close,
291 struct ExecBase *, SysBase, 2, Exec)
293 AROS_LIBFUNC_INIT
295 /* I have one fewer opener. */
296 SysBase->LibNode.lib_OpenCnt--;
297 return 0;
298 AROS_LIBFUNC_EXIT