2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 Desc: exec.library resident and initialization.
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"
34 #include "intservers.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
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 acpica.library, 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 void SupervisorAlertTask(struct ExecBase
*SysBase
);
89 THIS_PROGRAM_HANDLES_SYMBOLSET(INITLIB
)
90 THIS_PROGRAM_HANDLES_SYMBOLSET(PREINITLIB
)
94 AROS_UFH3S(struct ExecBase
*, GM_UNIQUENAME(init
),
95 AROS_UFHA(struct MemHeader
*, mh
, D0
),
96 AROS_UFHA(struct TagItem
*, tagList
, A0
),
97 AROS_UFHA(struct ExecBase
*, origSysBase
, A6
)
102 struct TaskStorageFreeSlot
*tsfs
;
105 struct ExceptionContext
*ctx
;
109 * exec.library init routine is a little bit magic. The magic is that it
111 * First time it's run manually from kernel.resource's ROMTag scanner in order
112 * to create initial ExecBase. This condition is determined by origSysBase == NULL
113 * passed to this function. In this case the routine expects two more arguments:
114 * mh - an initial MemHeader in which ExecBase will be constructed.
115 * tagList - boot information passed from the bootstrap. It is used to parse
116 * certain command-line arguments.
118 * Second time it's run as part of normal modules initialization sequence, at the
119 * end of all RTS_SINGLETASK modules. At this moment we already have a complete
120 * memory list and working kernel.resource. Now the job is to complete the boot task
121 * structure, and start up multitasking.
124 return PrepareExecBase(mh
, tagList
);
126 DINIT("exec.library init");
129 * Call platform-specific pre-init code (if any). Return values are not checked.
130 * Note that Boot Task is still incomplete here, and there's no multitasking yet.
132 * TODO: Amiga(tm) port may call PrepareExecBaseMove() here instead of hardlinking
133 * it from within the boot code.
135 * NOTE: All functions will be passed origSysBase value. This is the original
136 * ExecBase pointer in case if it was moved. The new pointer will be in global
139 set_call_libfuncs(SETNAME(PREINITLIB
), 1, 0, origSysBase
);
142 * kernel.resource is up and running and memory list is complete.
143 * Global SysBase is set to its final value. We've got KernelBase and AllocMem() works.
144 * Initialize free task storage slots management
146 tsfs
= AllocMem(sizeof(struct TaskStorageFreeSlot
), MEMF_PUBLIC
|MEMF_CLEAR
);
149 DINIT("FATAL: Failed to allocate a task storage slot!");
152 tsfs
->FreeSlot
= __TS_FIRSTSLOT
+1;
153 AddHead((struct List
*)&PrivExecBase(SysBase
)->TaskStorageSlots
, (struct Node
*)tsfs
);
155 /* Now we are ready to become a Boot Task and turn on the multitasking */
156 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
|MEMF_CLEAR
);
157 ml
= AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
);
161 DINIT("FATAL: Failed to allocate any memory for first task!");
165 ctx
= KrnCreateContext();
168 DINIT("FATAL: Failed to create the first task context!");
172 NEWLIST(&t
->tc_MemEntry
);
174 t
->tc_Node
.ln_Name
= "Boot Task";
175 t
->tc_Node
.ln_Type
= NT_TASK
;
176 t
->tc_Node
.ln_Pri
= 0;
177 t
->tc_State
= TS_RUN
;
178 t
->tc_SigAlloc
= 0xFFFF;
181 * Boot-time stack can be placed anywhere in memory.
182 * In order to avoid complex platform-dependent mechanism for querying its limits
183 * we simply shut up stack checking in kernel.resource by specifying the whole address
186 t
->tc_SPLower
= NULL
;
187 t
->tc_SPUpper
= (APTR
)~0;
190 * Build a memory list for the task.
191 * It doesn't include stack because it wasn't allocated by us.
193 ml
->ml_NumEntries
= 1;
194 ml
->ml_ME
[0].me_Addr
= t
;
195 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
196 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
198 /* Create a ETask structure and attach CPU context */
201 DINIT("FATAL: Failed to allocate any memory for first tasks extended data!");
204 t
->tc_UnionETask
.tc_ETask
->et_RegFrame
= ctx
;
206 DINIT("[exec] Boot Task 0x%p, ETask 0x%p, CPU context 0x%p\n", t
, t
->tc_UnionETask
.tc_ETask
, ctx
);
209 * Set the current task and elapsed time for it.
210 * Set ThisTask only AFTER InitETask() has been called. InitETask() sets et_Parent
211 * to FindTask(NULL). We must get NULL there, otherwise we'll get task looped on itself.
214 SysBase
->Elapsed
= SysBase
->Quantum
;
216 /* Install the interrupt servers. Again, do it here because allocations are needed. */
217 for (i
=0; i
< 16; i
++)
219 struct Interrupt
*is
;
221 if (i
!= INTB_SOFTINT
)
223 struct SoftIntList
*sil
;
225 is
= AllocMem(sizeof(struct Interrupt
) + sizeof(struct SoftIntList
), MEMF_CLEAR
|MEMF_PUBLIC
);
228 DINIT("FATAL: Cannot install Interrupt Servers!");
229 Alert( AT_DeadEnd
| AN_IntrMem
| AN_ExecLib
);
232 sil
= (struct SoftIntList
*)((struct Interrupt
*)is
+ 1);
235 is
->is_Code
= (VOID_FUNC
)VBlankServer
;
237 is
->is_Code
= (VOID_FUNC
)IntServer
;
239 NEWLIST((struct List
*)sil
);
244 struct Interrupt
* is
;
246 is
= AllocMem(sizeof(struct Interrupt
), MEMF_CLEAR
|MEMF_PUBLIC
);
249 DINIT("Error: Cannot install SoftInt Handler!\n");
250 Alert( AT_DeadEnd
| AN_IntrMem
| AN_ExecLib
);
253 is
->is_Node
.ln_Type
= NT_INTERRUPT
;
254 is
->is_Node
.ln_Pri
= 0;
255 is
->is_Node
.ln_Name
= "SW Interrupt Dispatcher";
257 is
->is_Code
= (void *)SoftIntDispatch
;
262 /* We now start up the interrupts */
268 /* Call platform-specific init code (if any) */
269 set_call_libfuncs(SETNAME(INITLIB
), 1, 1, SysBase
);
271 /* Multitasking is on. Call CoolCapture. */
272 if (SysBase
->CoolCapture
)
274 DINIT("Calling CoolCapture at 0x%p", SysBase
->CoolCapture
);
276 AROS_UFC1NR(void, SysBase
->CoolCapture
,
277 AROS_UFCA(struct Library
*, (struct Library
*)SysBase
, A6
));
280 /* Done. Following the convention, we return our base pointer. */
285 Alert( AT_DeadEnd
| AG_NoMemory
| AN_ExecLib
);
292 int Exec_InitServices(struct ExecBase
*SysBase
)
296 DINIT("starting exec service tasks");
298 /* Our housekeeper must have the largest possible priority */
299 t
= NewCreateTask(TASKTAG_NAME
, "Exec housekeeper",
301 TASKTAG_PC
, ServiceTask
,
302 TASKTAG_TASKMSGPORT
, &((struct IntExecBase
*)SysBase
)->ServicePort
,
303 TASKTAG_ARG1
, SysBase
,
308 Alert( AT_DeadEnd
| AN_ExecLib
);
312 /* Create task for handling supervisor level errors */
313 NewCreateTask(TASKTAG_NAME
, "Exec Guru Task",
315 TASKTAG_PC
, SupervisorAlertTask
,
316 TASKTAG_ARG1
, SysBase
,
322 AROS_PLH1(struct ExecBase
*, open
,
323 AROS_LHA(ULONG
, version
, D0
),
324 struct ExecBase
*, SysBase
, 1, Exec
)
328 /* I have one more opener. */
329 SysBase
->LibNode
.lib_OpenCnt
++;
335 AROS_PLH0(BPTR
, close
,
336 struct ExecBase
*, SysBase
, 2, Exec
)
340 /* I have one fewer opener. */
341 SysBase
->LibNode
.lib_OpenCnt
--;
347 ADD2INITLIB(Exec_InitServices
, -126)