2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: exec.library resident and initialization.
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"
35 #include "intservers.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
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
=
71 (struct Resident
*)&Exec_resident
,
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
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
)
101 struct ExceptionContext
*ctx
;
105 * exec.library init routine is a little bit magic. The magic is that it
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.
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
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");
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
);
191 DINIT("ERROR: Cannot install Interrupt Servers!");
192 Alert( AT_DeadEnd
| AN_IntrMem
);
195 sil
= (struct SoftIntList
*)((struct Interrupt
*)is
+ 1);
198 is
->is_Code
= &VBlankServer
;
200 is
->is_Code
= &IntServer
;
202 NEWLIST((struct List
*)sil
);
207 struct Interrupt
* is
;
209 is
= AllocMem(sizeof(struct Interrupt
), MEMF_CLEAR
|MEMF_PUBLIC
);
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";
220 is
->is_Code
= (void *)SoftIntDispatch
;
225 /* We now start up the interrupts */
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. */
249 AROS_PLH1(struct ExecBase
*, open
,
250 AROS_LHA(ULONG
, version
, D0
),
251 struct ExecBase
*, SysBase
, 1, Exec
)
255 /* I have one more opener. */
256 SysBase
->LibNode
.lib_OpenCnt
++;
261 AROS_PLH0(BPTR
, close
,
262 struct ExecBase
*, SysBase
, 2, Exec
)
266 /* I have one fewer opener. */
267 SysBase
->LibNode
.lib_OpenCnt
--;