revert between 56095 -> 55830 in arch
[AROS.git] / rom / exec / exec_init.c
blob1420c5cbfb7e6432316dfcd3b97bde2388960ec3
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: exec.library resident and initialization.
6 Lang: english
7 */
9 #define DEBUG 0
11 #include <aros/config.h>
13 #include <exec/lists.h>
14 #include <exec/execbase.h>
15 #include <exec/interrupts.h>
16 #include <exec/resident.h>
17 #include <exec/memory.h>
18 #include <exec/alerts.h>
19 #include <exec/tasks.h>
20 #include <hardware/intbits.h>
22 #include <aros/symbolsets.h>
23 #include <aros/system.h>
24 #include <aros/arossupportbase.h>
25 #include <aros/asmcall.h>
27 #include <aros/debug.h>
29 #include <proto/arossupport.h>
30 #include <proto/exec.h>
32 #include "exec_debug.h"
33 #include "exec_intern.h"
34 #include "exec_util.h"
35 #include "etask.h"
36 #include "intservers.h"
37 #include "memory.h"
38 #include "taskstorage.h"
40 #include LC_LIBDEFS_FILE
42 static const UBYTE name[];
43 static const UBYTE version[];
45 /* This comes from genmodule */
46 extern int LIBEND(void);
48 AROS_UFP3S(struct ExecBase *, GM_UNIQUENAME(init),
49 AROS_UFPA(struct MemHeader *, mh, D0),
50 AROS_UFPA(struct TagItem *, tagList, A0),
51 AROS_UFPA(struct ExecBase *, sysBase, A6));
54 * exec.library ROMTag.
56 * It has RTF_COLDSTART level specified, however it actually runs at SINGLETASK
57 * (no multitasking, incomplete boot task).
58 * This is supposed to be the first COLDSTART resident to be executed. Its job is
59 * to complete the boot task and enable multitasking (which actually means entering
60 * COLDSTART level).
61 * Such mechanism allows kernel.resource boot code to do some additional setup after
62 * all SINGLETASK residents are run. Usually these are various lowlevel hardware resources
63 * (like acpica.library, efi.resource, etc) which can be needed for kernel.resource to
64 * complete own setup. This helps to get rid of additional ROMTag hooks.
65 * There's one more magic with this ROMTag: it's called twice. First time it's called manually
66 * from within krnPrepareExecBase(), for initial ExecBase creation. This magic is described below.
68 * WARNING: the CPU privilege level must be set to user before calling InitCode(RTF_COLDSTART)!
70 const struct Resident Exec_resident =
72 RTC_MATCHWORD,
73 (struct Resident *)&Exec_resident,
74 (APTR)&LIBEND,
75 RTF_COLDSTART,
76 VERSION_NUMBER,
77 NT_LIBRARY,
78 120,
79 (STRPTR)name,
80 (STRPTR)&version[6],
81 &GM_UNIQUENAME(init),
84 static const UBYTE name[] = MOD_NAME_STRING;
85 static const UBYTE version[] = VERSION_STRING;
87 extern void debugmem(void);
89 void SupervisorAlertTask(struct ExecBase *SysBase);
91 THIS_PROGRAM_HANDLES_SYMBOLSET(INITLIB)
92 THIS_PROGRAM_HANDLES_SYMBOLSET(PREINITLIB)
93 DEFINESET(INITLIB)
94 DEFINESET(PREINITLIB)
96 AROS_UFH3S(struct ExecBase *, GM_UNIQUENAME(init),
97 AROS_UFHA(struct MemHeader *, mh, D0),
98 AROS_UFHA(struct TagItem *, tagList, A0),
99 AROS_UFHA(struct ExecBase *, origSysBase, A6)
102 AROS_USERFUNC_INIT
104 struct TaskStorageFreeSlot *tsfs;
105 struct Task *t;
106 struct MemList *ml;
107 struct ExceptionContext *ctx;
108 int i;
111 * exec.library init routine is a little bit magic. The magic is that it
112 * can be run twice.
113 * First time it's run manually from kernel.resource's ROMTag scanner in order
114 * to create initial ExecBase. This condition is determined by origSysBase == NULL
115 * passed to this function. In this case the routine expects two more arguments:
116 * mh - an initial MemHeader in which ExecBase will be constructed.
117 * tagList - boot information passed from the bootstrap. It is used to parse
118 * certain command-line arguments.
120 * Second time it's run as part of normal modules initialization sequence, at the
121 * end of all RTS_SINGLETASK modules. At this moment we already have a complete
122 * memory list and working kernel.resource. Now the job is to complete the boot task
123 * structure, and start up multitasking.
125 if (!origSysBase)
126 return PrepareExecBase(mh, tagList);
128 #if defined(__AROSEXEC_SMP__)
129 DINIT("AROS SMP 'exec.library' Initialization");
130 #else
131 DINIT("AROS 'exec.library' Initialization");
132 #endif
135 * Call platform-specific pre-init code (if any). Return values are not checked.
136 * Note that Boot Task is still incomplete here, and there's no multitasking yet.
138 * TODO: Amiga(tm) port may call PrepareExecBaseMove() here instead of hardlinking
139 * it from within the boot code.
141 * NOTE: All functions will be passed origSysBase value. This is the original
142 * ExecBase pointer in case if it was moved. The new pointer will be in global
143 * SysBase then.
145 set_call_libfuncs(SETNAME(PREINITLIB), 1, 0, origSysBase);
147 DINIT("Preparing Bootstrap Task...");
150 * kernel.resource is up and running and memory list is complete.
151 * Global SysBase is set to its final value. We've got KernelBase and AllocMem() works.
152 * Initialize free task storage slots management
154 tsfs = AllocMem(sizeof(struct TaskStorageFreeSlot), MEMF_PUBLIC|MEMF_CLEAR);
155 if (!tsfs)
157 DINIT("FATAL: Failed to allocate a task storage slot!");
158 goto execfatal;
160 tsfs->FreeSlot = __TS_FIRSTSLOT+1;
161 AddHead((struct List *)&PrivExecBase(SysBase)->TaskStorageSlots, (struct Node *)tsfs);
163 /* Now we are ready to become a Boot Task and turn on the multitasking */
164 t = AllocMem(sizeof(struct Task), MEMF_PUBLIC|MEMF_CLEAR);
165 ml = AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
167 if (!t || !ml)
169 DINIT("FATAL: Failed to allocate any memory for first task!");
170 goto execfatal;
173 DINIT("Allocated Task structure and MemList");
175 ctx = KrnCreateContext();
176 if (!ctx)
178 DINIT("FATAL: Failed to create the first task context!");
179 goto execfatal;
182 DINIT("Bootstrap CPU context @ 0x%p\n", ctx);
184 NEWLIST(&t->tc_MemEntry);
186 #if defined(__AROSEXEC_SMP__)
187 t->tc_Node.ln_Name = "Exec BSP Bootstrap Task";
188 #else
189 t->tc_Node.ln_Name = "Exec Bootstrap Task";
190 #endif
191 t->tc_Node.ln_Type = NT_TASK;
192 t->tc_Node.ln_Pri = 0;
193 t->tc_State = TS_RUN;
194 t->tc_SigAlloc = 0xFFFF;
197 * Boot-time stack can be placed anywhere in memory.
198 * In order to avoid complex platform-dependent mechanism for querying its limits
199 * we simply shut up stack checking in kernel.resource by specifying the whole address
200 * space as limits.
202 t->tc_SPLower = NULL;
203 t->tc_SPUpper = (APTR)~0;
206 * Build a memory list for the task.
207 * It doesn't include stack because it wasn't allocated by us.
209 ml->ml_NumEntries = 1;
210 ml->ml_ME[0].me_Addr = t;
211 ml->ml_ME[0].me_Length = sizeof(struct Task);
212 AddHead(&t->tc_MemEntry, &ml->ml_Node);
214 /* Set the bootstrapping task incase errors occur... */
215 DINIT("Preparing the Bootstrap task @ 0x%p", t);
216 SET_THIS_TASK(t);
217 DINIT("ThisTask is now 0x%p", GET_THIS_TASK);
219 /* Create the first ETask structure and attach CPU context */
220 if (!InitETask(t, NULL))
222 DINIT("FATAL: Failed to allocate any memory for first tasks extended data!");
223 goto execfatal;
225 t->tc_UnionETask.tc_ETask->et_RegFrame = ctx;
227 DINIT("Bootstrap task ETask @ 0x%p\n", t->tc_UnionETask.tc_ETask);
229 SCHEDELAPSED_SET(SCHEDQUANTUM_GET);
231 DINIT("Inital Quantum = %d, Elapsed = %d\n", SCHEDQUANTUM_GET, SCHEDELAPSED_GET);
233 /* Install the interrupt servers. Again, do it here because allocations are needed. */
234 for (i=0; i < 16; i++)
236 struct Interrupt *is;
238 if (i != INTB_SOFTINT)
240 struct SoftIntList *sil;
242 is = AllocMem(sizeof(struct Interrupt) + sizeof(struct SoftIntList), MEMF_CLEAR|MEMF_PUBLIC);
243 if (is == NULL)
245 DINIT("FATAL: Cannot install Interrupt Servers!");
246 Alert( AT_DeadEnd | AN_IntrMem | AN_ExecLib );
249 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
251 if (i == INTB_VERTB)
252 is->is_Code = (VOID_FUNC)VBlankServer;
253 else
254 is->is_Code = (VOID_FUNC)IntServer;
255 is->is_Data = sil;
256 NEWLIST((struct List *)sil);
257 SetIntVector(i,is);
259 else
261 struct Interrupt * is;
263 is = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR|MEMF_PUBLIC);
264 if (NULL == is)
266 DINIT("Error: Cannot install SoftInt Handler!\n");
267 Alert( AT_DeadEnd | AN_IntrMem | AN_ExecLib );
270 is->is_Node.ln_Type = NT_INTERRUPT;
271 is->is_Node.ln_Pri = 0;
272 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
273 is->is_Data = NULL;
274 is->is_Code = (void *)SoftIntDispatch;
275 SetIntVector(i,is);
279 DINIT("Enabling Exec Interrupts...\n");
281 /* We now start up the interrupts */
282 Permit();
283 Enable();
285 D(debugmem());
287 /* Call platform-specific init code (if any) */
288 set_call_libfuncs(SETNAME(INITLIB), 1, 1, SysBase);
290 /* Multitasking is on. Call CoolCapture. */
291 if (SysBase->CoolCapture)
293 DINIT("Calling CoolCapture at 0x%p", SysBase->CoolCapture);
295 AROS_UFC1NR(void, SysBase->CoolCapture,
296 AROS_UFCA(struct Library *, (struct Library *)SysBase, A6));
299 /* Done. Following the convention, we return our base pointer. */
300 return SysBase;
302 execfatal:
304 Alert( AT_DeadEnd | AG_NoMemory | AN_ExecLib );
306 return NULL;
308 AROS_USERFUNC_EXIT
311 int Exec_InitServices(struct ExecBase *SysBase)
313 struct Task *t;
315 DINIT("starting exec service tasks");
317 /* Our housekeeper must have the largest possible priority */
318 t = NewCreateTask(TASKTAG_NAME , "Exec housekeeper",
319 TASKTAG_PRI , 127,
320 #if defined(__AROSEXEC_SMP__)
321 TASKTAG_AFFINITY, TASKAFFINITY_ANY,
322 #endif
323 TASKTAG_PC , ServiceTask,
324 TASKTAG_TASKMSGPORT, &((struct IntExecBase *)SysBase)->ServicePort,
325 TASKTAG_ARG1 , SysBase,
326 TAG_DONE);
328 if (!t)
330 Alert( AT_DeadEnd | AN_ExecLib );
331 return FALSE;
334 /* Create task for handling supervisor level errors */
335 NewCreateTask(TASKTAG_NAME , "Exec Guru Task",
336 TASKTAG_PRI , 126,
337 TASKTAG_PC , SupervisorAlertTask,
338 TASKTAG_ARG1 , SysBase,
339 TAG_DONE);
341 return TRUE;
344 AROS_PLH1(struct ExecBase *, open,
345 AROS_LHA(ULONG, version, D0),
346 struct ExecBase *, SysBase, 1, Exec)
348 AROS_LIBFUNC_INIT
350 /* I have one more opener. */
351 SysBase->LibNode.lib_OpenCnt++;
352 return SysBase;
354 AROS_LIBFUNC_EXIT
357 AROS_PLH0(BPTR, close,
358 struct ExecBase *, SysBase, 2, Exec)
360 AROS_LIBFUNC_INIT
362 /* I have one fewer opener. */
363 SysBase->LibNode.lib_OpenCnt--;
364 return 0;
366 AROS_LIBFUNC_EXIT
369 ADD2INITLIB(Exec_InitServices, -126)