Port the SB128 code to AROS.
[AROS.git] / rom / exec / exec_init.c
blob902177d0c314f11a9dd5f5fc2b82aec9aeda91b7
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/types.h>
10 #include <exec/lists.h>
11 #include <exec/execbase.h>
12 #include <exec/interrupts.h>
13 #include <exec/resident.h>
14 #include <exec/memory.h>
15 #include <exec/alerts.h>
16 #include <exec/tasks.h>
17 #include <hardware/intbits.h>
19 #include <aros/symbolsets.h>
20 #include <aros/system.h>
21 #include <aros/arossupportbase.h>
22 #include <aros/asmcall.h>
23 #include <aros/config.h>
25 #include <aros/debug.h>
27 #include <proto/arossupport.h>
28 #include <proto/exec.h>
29 #include <proto/kernel.h>
31 #include "exec_debug.h"
32 #include "exec_intern.h"
33 #include "exec_util.h"
34 #include "etask.h"
35 #include "intservers.h"
36 #include "memory.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 Task *t;
100 struct MemList *ml;
101 struct ExceptionContext *ctx;
102 int i;
105 * exec.library init routine is a little bit magic. The magic is that it
106 * can be run twice.
107 * First time it's run manually from kernel.resource's ROMTag scanner in order
108 * to create initial ExecBase. This condition is determined by origSysBase == NULL
109 * passed to this function. In this case the routine expects two more arguments:
110 * mh - an initial MemHeader in which ExecBase will be constructed.
111 * tagList - boot information passed from the bootstrap. It is used to parse
112 * certain command-line arguments.
114 * Second time it's run as part of normal modules initialization sequence, at the
115 * end of all RTS_SINGLETASK modules. At this moment we already have a complete
116 * memory list and working kernel.resource. Now the job is to complete the boot task
117 * structure, and start up multitasking.
119 if (!origSysBase)
120 return PrepareExecBase(mh, tagList);
122 DINIT("exec.library init");
125 * Call platform-specific pre-init code (if any). Return values are not checked.
126 * Note that Boot Task is still incomplete here, and there's no multitasking yet.
128 * TODO: Amiga(tm) port may call PrepareExecBaseMove() here instead of hardlinking
129 * it from within the boot code.
131 * NOTE: All functions will be passed origSysBase value. This is the original
132 * ExecBase pointer in case if it was moved. The new pointer will be in global
133 * SysBase then.
135 set_call_libfuncs(SETNAME(PREINITLIB), 1, 0, origSysBase);
138 * kernel.resource is up and running and memory list is complete.
139 * Global SysBase is set to its final value.
140 * Complete boot task with ETask and CPU context.
142 t = SysBase->ThisTask;
144 ml = AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
145 t->tc_UnionETask.tc_ETask = AllocVec(sizeof(struct IntETask), MEMF_ANY|MEMF_CLEAR);
146 ctx = KrnCreateContext();
148 D(bug("[exec] MemList 0x%p, ETask 0x%p, CPU context 0x%p\n", ml, t->tc_UnionETask.tc_ETask, ctx));
150 if (!ml || !t->tc_UnionETask.tc_ETask || !ctx)
152 DINIT("Not enough memory for first task");
153 return NULL;
157 * Build a memory list for the task.
158 * It doesn't include stack because it wasn't allocated by us.
160 ml->ml_NumEntries = 1;
161 ml->ml_ME[0].me_Addr = t;
162 ml->ml_ME[0].me_Length = sizeof(struct Task);
163 AddHead(&t->tc_MemEntry, &ml->ml_Node);
165 InitETask(t, t->tc_UnionETask.tc_ETask);
168 * These adjustments need to be done after InitETask():
169 * 1. Set et_Parent to NULL, InitETask() will set it to FindTask(NULL). At this moment
170 * we have SysBase->ThisTask already set to incomplete "boot task".
171 * 2. Set TF_ETASK in tc_Flags. If it will be already set, InitETask() will try to add
172 * a new ETask into children list of parent ETask (i. e. ourselves).
174 t->tc_UnionETask.tc_ETask->et_Parent = NULL;
175 t->tc_Flags = TF_ETASK;
177 GetIntETask(t)->iet_Context = ctx;
179 /* Install the interrupt servers. Again, do it here because allocations are needed. */
180 for (i=0; i < 16; i++)
182 struct Interrupt *is;
184 if (i != INTB_SOFTINT)
186 struct SoftIntList *sil;
188 is = AllocMem(sizeof(struct Interrupt) + sizeof(struct SoftIntList), MEMF_CLEAR|MEMF_PUBLIC);
189 if (is == NULL)
191 DINIT("ERROR: Cannot install Interrupt Servers!");
192 Alert( AT_DeadEnd | AN_IntrMem );
195 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
197 if (i == INTB_VERTB)
198 is->is_Code = &VBlankServer;
199 else
200 is->is_Code = &IntServer;
201 is->is_Data = sil;
202 NEWLIST((struct List *)sil);
203 SetIntVector(i,is);
205 else
207 struct Interrupt * is;
209 is = AllocMem(sizeof(struct Interrupt), MEMF_CLEAR|MEMF_PUBLIC);
210 if (NULL == is)
212 DINIT("Error: Cannot install SoftInt Handler!\n");
213 Alert( AT_DeadEnd | AN_IntrMem );
216 is->is_Node.ln_Type = NT_INTERRUPT;
217 is->is_Node.ln_Pri = 0;
218 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
219 is->is_Data = NULL;
220 is->is_Code = (void *)SoftIntDispatch;
221 SetIntVector(i,is);
225 /* We now start up the interrupts */
226 Permit();
227 Enable();
229 D(debugmem());
231 /* Call platform-specific init code (if any) */
232 set_call_libfuncs(SETNAME(INITLIB), 1, 1, SysBase);
234 /* Multitasking is on. Call CoolCapture. */
235 if (SysBase->CoolCapture)
237 DINIT("Calling CoolCapture at 0x%p", SysBase->CoolCapture);
239 AROS_UFC1(void, SysBase->CoolCapture,
240 AROS_UFCA(struct Library *, (struct Library *)SysBase, A6));
243 /* Done. Following the convention, we return our base pointer. */
244 return SysBase;
246 AROS_USERFUNC_EXIT
249 AROS_PLH1(struct ExecBase *, open,
250 AROS_LHA(ULONG, version, D0),
251 struct ExecBase *, SysBase, 1, Exec)
253 AROS_LIBFUNC_INIT
255 /* I have one more opener. */
256 SysBase->LibNode.lib_OpenCnt++;
257 return SysBase;
258 AROS_LIBFUNC_EXIT
261 AROS_PLH0(BPTR, close,
262 struct ExecBase *, SysBase, 2, Exec)
264 AROS_LIBFUNC_INIT
266 /* I have one fewer opener. */
267 SysBase->LibNode.lib_OpenCnt--;
268 return 0;
269 AROS_LIBFUNC_EXIT