2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
8 #include <asm/mpc5200b.h>
9 #include <aros/config.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/arossupportbase.h>
13 #include <aros/symbolsets.h>
14 #include <exec/execbase.h>
15 #include <exec/types.h>
16 #include <exec/resident.h>
18 #include <dos/dosextens.h>
19 #include <hardware/custom.h>
20 #include <hardware/intbits.h>
22 #include <proto/exec.h>
23 #include <proto/kernel.h>
30 #include "exec_intern.h"
31 #include "exec_util.h"
32 #include "intservers.h"
34 #include "taskstorage.h"
36 D(extern void debugmem(void));
38 void exec_main(struct TagItem
*msg
, void *entry
);
39 extern CONST_APTR Exec_FuncTable
[];
40 extern ULONG
Exec_15_MakeFunctions(APTR
, CONST_APTR
, CONST_APTR
, struct ExecBase
*);
41 void exec_DefaultTaskExit();
42 IPTR
**exec_RomTagScanner(struct TagItem
*msg
, struct ExecBase
*);
43 extern struct Library
* PrepareAROSSupportBase (struct ExecBase
*);
44 intptr_t krnGetTagData(Tag tagValue
, intptr_t defaultVal
, const struct TagItem
*tagList
);
46 struct ExecBase
*priv_SysBase
;
49 AROS_LDA(const char *, format
, A0
),
50 AROS_LDA(va_list, args
, A1
),
51 APTR
, kernelBase
, 12, Kernel
);
54 static inline void bug(const char *format
, ...)
58 va_start(args
, format
);
59 /* Our KrnBug() ignores base address */
60 AROS_SLIB_ENTRY(KrnBug
, Kernel
, 12)(format
, args
, NULL
);
64 const char exec_name
[] = "exec.library";
65 const char exec_idstring
[] = "$VER: exec 41.11 (16.12.2000)\r\n";
66 const char exec_fastname
[] = "System Memory";
68 const short exec_Version
= 41;
69 const short exec_Revision
= 11;
71 const struct __attribute__((section(".text"))) Resident Exec_resident
=
73 RTC_MATCHWORD
, /* Magic value used to find resident */
74 &Exec_resident
, /* Points to Resident itself */
75 (APTR
)&Exec_resident
+1, /* Where could we find next Resident? */
76 0, /* There are no flags!! */
78 NT_LIBRARY
, /* Type */
79 126, /* Very high startup priority. */
80 (STRPTR
)exec_name
, /* Pointer to name string */
81 (STRPTR
)exec_idstring
, /* Ditto */
82 exec_main
/* Library initializer (for exec this value is irrelevant since we've jumped there at the begining to bring the system up */
85 THIS_PROGRAM_HANDLES_SYMBOLSET(INITLIB
)
88 void exec_main(struct TagItem
*msg
, void *entry
)
90 struct ExecBase
*SysBase
= NULL
;
91 struct TaskStorageFreeSlot
*tsfs
;
98 D(bug("[exec] AROS for Efika5200B - The AROS Research OS\n"));
100 /* Prepare the exec base */
102 ULONG negsize
= LIB_VECTSIZE
; /* size of vector table */
103 CONST_APTR
*fp
= Exec_FuncTable
; /* pointer to a function in the table */
105 D(bug("[exec] Preparing the ExecBase...\n"));
107 /* Calculate the size of the vector table */
108 while (*fp
++ != (APTR
) -1) negsize
+= LIB_VECTSIZE
;
110 /* Align the offset for SysBase to the cache line */
111 negsize
= (negsize
+ 31) & ~31;
113 /* Get the lowest usable memory location */
116 /* And now let's have the SysBase */
117 SysBase
= (struct ExecBase
*)(lowmem
+ negsize
);
118 wrspr(SPRG5
, SysBase
);
119 *(struct ExecBase
**)4UL = SysBase
;
120 /* Store the SysBase for local use. It's ugly, it's dirty, it's a hack. */
121 priv_SysBase
= SysBase
;
122 lowmem
= (lowmem
+ negsize
+ sizeof(struct IntExecBase
) + 4095) & ~4095;
124 D(bug("[exec] ExecBase at %08x\n", SysBase
));
126 D(bug("[exec] Clearing ExecBase\n"));
128 /* How about clearing most of ExecBase structure? */
129 memset(&SysBase
->IntVects
[0], 0, sizeof(struct IntExecBase
) - offsetof(struct ExecBase
, IntVects
[0]));
131 SysBase
->KickMemPtr
= NULL
;
132 SysBase
->KickTagPtr
= NULL
;
133 SysBase
->KickCheckSum
= NULL
;
135 SysBase
->DispCount
= 0;
136 SysBase
->IdleCount
= 0;
139 * Now everything is prepared to store ExecBase at the location 4UL and set
140 * it complement in ExecBase structure
143 D(bug("[exec] Initializing library...\n"));
145 SysBase
->ChkBase
= ~(ULONG
)SysBase
;
147 /* Store memory configuration */
148 SysBase
->MaxLocMem
= (IPTR
)0; //locmem;
149 SysBase
->MaxExtMem
= (APTR
)0; //extmem;
152 * Initialize exec lists. This is done through information table which consist
153 * of offset from begining of ExecBase and type of the list.
155 NEWLIST(&SysBase
->MemList
);
156 SysBase
->MemList
.lh_Type
= NT_MEMORY
;
157 NEWLIST(&SysBase
->ResourceList
);
158 SysBase
->ResourceList
.lh_Type
= NT_RESOURCE
;
159 NEWLIST(&SysBase
->DeviceList
);
160 SysBase
->DeviceList
.lh_Type
= NT_DEVICE
;
161 NEWLIST(&SysBase
->LibList
);
162 SysBase
->LibList
.lh_Type
= NT_LIBRARY
;
163 NEWLIST(&SysBase
->PortList
);
164 SysBase
->PortList
.lh_Type
= NT_MSGPORT
;
165 NEWLIST(&SysBase
->TaskReady
);
166 SysBase
->TaskReady
.lh_Type
= NT_TASK
;
167 NEWLIST(&SysBase
->TaskWait
);
168 SysBase
->TaskWait
.lh_Type
= NT_TASK
;
169 NEWLIST(&SysBase
->IntrList
);
170 SysBase
->IntrList
.lh_Type
= NT_INTERRUPT
;
171 NEWLIST(&SysBase
->SemaphoreList
);
172 SysBase
->SemaphoreList
.lh_Type
= NT_SIGNALSEM
;
173 NEWLIST(&SysBase
->ex_MemHandlers
);
177 NEWLIST(&SysBase
->SoftInts
[i
].sh_List
);
178 SysBase
->SoftInts
[i
].sh_List
.lh_Type
= NT_SOFTINT
;
182 * Exec.library initializer. Prepares exec.library for future use. All
183 * lists have to be initialized, some values from ROM are copied.
186 SysBase
->TaskTrapCode
= NULL
; //exec_DefaultTrap;
187 SysBase
->TaskExceptCode
= NULL
; //exec_DefaultTrap;
188 SysBase
->TaskExitCode
= exec_DefaultTaskExit
;
189 SysBase
->TaskSigAlloc
= 0x0000ffff;
190 SysBase
->TaskTrapAlloc
= 0x8000;
192 /* Prepare values for execBase (like name, type, pri and other) */
194 SysBase
->LibNode
.lib_Node
.ln_Type
= NT_LIBRARY
;
195 SysBase
->LibNode
.lib_Node
.ln_Pri
= 0;
196 SysBase
->LibNode
.lib_Node
.ln_Name
= (char *)exec_name
;
197 SysBase
->LibNode
.lib_Flags
= LIBF_CHANGED
| LIBF_SUMUSED
;
198 SysBase
->LibNode
.lib_PosSize
= sizeof(struct IntExecBase
);
199 SysBase
->LibNode
.lib_OpenCnt
= 1;
200 SysBase
->LibNode
.lib_IdString
= (char *)exec_idstring
;
201 SysBase
->LibNode
.lib_Version
= exec_Version
;
202 SysBase
->LibNode
.lib_Revision
= exec_Revision
;
204 SysBase
->Quantum
= 4;
205 SysBase
->Elapsed
= 4;
206 SysBase
->VBlankFrequency
= 50;
207 SysBase
->PowerSupplyFrequency
= 1;
209 NEWLIST(&PrivExecBase(SysBase
)->ResetHandlers
);
210 NEWLIST(&PrivExecBase(SysBase
)->AllocMemList
);
212 #if AROS_MUNGWALL_DEBUG
214 * TODO: implement command line parsing instead of this awkward hack
215 * Or, even better, merge this init code with arch-independent one
217 PrivExecBase(SysBase
)->IntFlags
= EXECF_MungWall
;
220 /* Build the jumptable */
221 SysBase
->LibNode
.lib_NegSize
=
222 Exec_15_MakeFunctions(SysBase
, Exec_FuncTable
, NULL
, SysBase
);
224 SumLibrary((struct Library
*)SysBase
);
226 InitSemaphore(&PrivExecBase(SysBase
)->MemListSem
);
227 InitSemaphore(&PrivExecBase(SysBase
)->LowMemSem
);
229 PrivExecBase(SysBase
)->TaskStorageSize
= TASKSTORAGEPUDDLE
;
230 NEWLIST(&PrivExecBase(SysBase
)->TaskStorageSlots
);
232 D(bug("[exec] Adding memory\n"));
234 AddMemList(0x07000000 - lowmem
,
235 MEMF_FAST
| MEMF_PUBLIC
| MEMF_KICK
| MEMF_LOCAL
,
238 (STRPTR
)exec_fastname
);
240 SumLibrary((struct Library
*)SysBase
);
242 Enqueue(&SysBase
->LibList
,&SysBase
->LibNode
.lib_Node
);
244 SysBase
->DebugAROSBase
= PrepareAROSSupportBase(SysBase
);
246 /* Scan for valid RomTags */
247 SysBase
->ResModules
= exec_RomTagScanner(msg
, SysBase
);
249 D(bug("[exec] InitCode(RTF_SINGLETASK)\n"));
250 InitCode(RTF_SINGLETASK
, 0);
252 /* Install the interrupt servers */
255 if( (1<<i
) & (INTF_PORTS
|INTF_COPER
|INTF_VERTB
|INTF_EXTER
|INTF_SETCLR
))
257 struct Interrupt
*is
;
258 struct SoftIntList
*sil
;
261 sizeof(struct Interrupt
) + sizeof(struct SoftIntList
),
262 MEMF_CLEAR
| MEMF_PUBLIC
266 D(bug("[exec] ERROR: Cannot install Interrupt Servers!\n"));
268 sil
= (struct SoftIntList
*)((struct Interrupt
*)is
+ 1);
270 is
->is_Code
= &IntServer
;
272 NEWLIST((struct List
*)sil
);
277 struct Interrupt
*is
;
283 sizeof(struct Interrupt
),
284 MEMF_CLEAR
| MEMF_PUBLIC
288 D(bug("[exec] Error: Cannot install Interrupt Servers!\n"));
289 // Alert(AT_DeadEnd | AN_IntrMem);
291 is
->is_Node
.ln_Type
= NT_SOFTINT
; //INTERRUPT;
292 is
->is_Node
.ln_Pri
= 0;
293 is
->is_Node
.ln_Name
= "SW Interrupt Dispatcher";
295 is
->is_Code
= (void *)SoftIntDispatch
;
302 /* Now it's time to calculate exec checksum. It will be used
303 * in future to distinguish whether we'd had proper execBase
306 UWORD sum
=0, *ptr
= &SysBase
->SoftVer
;
307 int i
=((IPTR
)&SysBase
->IntVects
[0] - (IPTR
)&SysBase
->SoftVer
) / 2,
310 /* Calculate sum for every static part from SoftVer to ChkSum */
316 SysBase
->ChkSum
= ~sum
;
319 tsfs
= AllocMem(sizeof(struct TaskStorageFreeSlot
), MEMF_PUBLIC
|MEMF_CLEAR
);
322 D(bug("[exec] ERROR: Cannot create Task Storage!\n"));
325 AddHead((struct List
*)&PrivExecBase(SysBase
)->TaskStorageSlots
, (struct Node
*)tsfs
);
327 /* Create boot task. Sigh, we actually create a Process sized Task,
328 since DOS needs to call things which think it has a Process and
329 we don't want to overwrite memory with something strange do we?
331 We do this until at least we can boot dos more cleanly.
336 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
);
337 t
= (struct Task
*) AllocMem(sizeof(struct Process
), MEMF_PUBLIC
|MEMF_CLEAR
);
341 D(bug("[exec] ERROR: Cannot create Boot Task!\n"));
343 ml
->ml_NumEntries
= 1;
344 ml
->ml_ME
[0].me_Addr
= t
;
345 ml
->ml_ME
[0].me_Length
= sizeof(struct Process
);
347 NEWLIST(&t
->tc_MemEntry
);
348 NEWLIST(&((struct Process
*)t
)->pr_MsgPort
.mp_MsgList
);
350 /* It's the boot process that RunCommand()s the boot shell, so we
351 must have this list initialized */
352 NEWLIST((struct List
*)&((struct Process
*)t
)->pr_LocalVars
);
354 AddHead(&t
->tc_MemEntry
,&ml
->ml_Node
);
356 t
->tc_Node
.ln_Name
= (char *)exec_name
;
357 t
->tc_Node
.ln_Pri
= 0;
358 t
->tc_Node
.ln_Type
= NT_TASK
;
359 t
->tc_State
= TS_RUN
;
360 t
->tc_SigAlloc
= 0xFFFF;
361 t
->tc_SPLower
= 0; /* This is the system's stack */
362 t
->tc_SPUpper
= (APTR
)~0UL;
363 t
->tc_Flags
|= TF_ETASK
;
365 if (t
->tc_Flags
& TF_ETASK
)
367 t
->tc_UnionETask
.tc_ETask
= AllocVec
369 sizeof(struct IntETask
),
373 if (!t
->tc_UnionETask
.tc_ETask
)
375 D(bug("[exec] Not enough memory for first task\n"));
378 /* Initialise the ETask data. */
379 InitETask(t
, t
->tc_UnionETask
.tc_ETask
);
380 t
->tc_UnionETask
.tc_ETask
->et_RegFrame
= KrnCreateContext();
382 if (!t
->tc_UnionETask
.tc_ETask
->et_RegFrame
)
384 D(bug("[exec] Not enough memory for first task\n"));
388 SysBase
->ThisTask
= t
;
391 D(bug("[exec] Done. SysBase->ThisTask = %08p\n", SysBase
->ThisTask
));
393 /* We now start up the interrupts */
399 /* Our housekeeper must have the largest possible priority */
400 t
= NewCreateTask(TASKTAG_NAME
, "Exec housekeeper",
402 TASKTAG_PC
, ServiceTask
,
403 TASKTAG_TASKMSGPORT
, &((struct IntExecBase
*)SysBase
)->ServicePort
,
404 TASKTAG_ARG1
, SysBase
,
408 set_call_libfuncs(SETNAME(INITLIB
), 1, 1, SysBase
);
410 D(bug("[exec] InitCode(RTF_COLDSTART)\n"));
411 InitCode(RTF_COLDSTART
, 0);
414 D(bug("[exec] I should never get here...\n"));
421 * This function scans kernel for existing Resident modules. If two modules
422 * with the same name are found, the one with higher version or priority wins.
424 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
425 * checksummed. If checksum is proper and all memory pointed in KickMemPtr may
426 * be allocated, then all modules from KickTagPtr are added to RT list
428 * Afterwards the proper RomTagList is created (see InitCode() for details) and
429 * memory after list and nodes is freed.
435 struct Resident
*module
;
439 void exec_DefaultTaskExit()
441 struct ExecBase
*SysBase
= priv_SysBase
;
442 RemTask(SysBase
->ThisTask
);
445 IPTR
**exec_RomTagScanner(struct TagItem
*msg
, struct ExecBase
*SysBase
)
447 struct List rtList
; /* List of modules */
448 UWORD
*ptr
= (UWORD
*)(krnGetTagData(KRN_KernelLowest
, 0, msg
) ^ 0xf8000000); /* Start looking here */
449 UWORD
*maxptr
= (UWORD
*)(krnGetTagData(KRN_KernelHighest
, 0, msg
) ^ 0xf8000000);
450 struct Resident
*res
; /* module found */
455 /* Initialize list */
458 D(bug("[exec] Resident modules (addr: pri version name):\n"));
460 /* Look in whole kernel for resident modules */
463 /* Do we have RTC_MATCHWORD? */
464 if (*ptr
== RTC_MATCHWORD
)
466 /* Yes, assume we have Resident */
467 res
= (struct Resident
*)ptr
;
469 /* Does rt_MatchTag point to Resident? */
470 if (res
== res
->rt_MatchTag
)
472 /* Yes, it is Resident module */
473 struct rt_node
*node
;
475 /* Check if there is module with such name already */
476 node
= (struct rt_node
*)FindName(&rtList
, res
->rt_Name
);
479 /* Yes, there was such module. It it had lower pri then replace it */
480 if (node
->node
.ln_Pri
<= res
->rt_Pri
)
482 /* If they have the same Pri but new one has higher Version, replace */
483 if ((node
->node
.ln_Pri
== res
->rt_Pri
) &&
484 (node
->module
->rt_Version
< res
->rt_Version
))
486 node
->node
.ln_Pri
= res
->rt_Pri
;
493 /* New module. Allocate some memory for it */
494 node
= (struct rt_node
*)
495 AllocMem(sizeof(struct rt_node
),MEMF_PUBLIC
|MEMF_CLEAR
);
499 node
->node
.ln_Name
= (char *)res
->rt_Name
;
500 node
->node
.ln_Pri
= res
->rt_Pri
;
503 Enqueue(&rtList
,(struct Node
*)node
);
506 ptr
+=sizeof(struct Resident
)/sizeof(UWORD
);
511 /* Get next address... */
513 } while (ptr
< maxptr
);
516 * By now we have valid (and sorted) list of kernel resident modules.
518 * Now, we will have to analyze used-defined RomTags (via KickTagPtr and
521 #warning "TODO: Implement external modules!"
523 * Everything is done now. Allocate buffer for normal RomTag and convert
527 ListLength(&rtList
,i
); /* Get length of the list */
529 RomTag
= AllocMem((i
+1)*sizeof(IPTR
),MEMF_PUBLIC
| MEMF_CLEAR
);
538 n
= (struct rt_node
*)RemHead(&rtList
);
539 D(bug("[exec] + 0x%08lx: %4d %3d \"%s\"\n",
542 n
->module
->rt_Version
,
544 RomTag
[j
] = (IPTR
*)n
->module
;
545 FreeMem(n
, sizeof(struct rt_node
));
553 AROS_LH1(struct ExecBase
*, open
,
554 AROS_LHA(ULONG
, version
, D0
),
555 struct ExecBase
*, SysBase
, 1, Exec
)
559 /* I have one more opener. */
560 SysBase
->LibNode
.lib_OpenCnt
++;
566 AROS_LH0(BPTR
, close
,
567 struct ExecBase
*, SysBase
, 2, Exec
)
571 /* I have one fewer opener. */
572 SysBase
->LibNode
.lib_OpenCnt
--;
578 struct ExecBase
*, SysBase
, 4, Exec
)
586 We temporarily redefine kprintf() so we use the real version in case
587 we have one of these two fn's called before AROSSupportBase is ready.
594 static int __kprintf(const UBYTE
*fmt
, ...)
600 result
= AROS_SLIB_ENTRY(KrnBug
, Kernel
, 12)(fmt
, ap
, NULL
);
606 static int __vkprintf(const UBYTE
*fmt
, va_list args
)
608 return AROS_SLIB_ENTRY(KrnBug
, Kernel
, 12)(fmt
, args
, NULL
);
611 static int __rkprintf(const STRPTR mainSystem
, const STRPTR subSystem
, int level
, const UBYTE
*fmt
, ...)
617 result
= AROS_SLIB_ENTRY(KrnBug
, Kernel
, 12)(fmt
, ap
, NULL
);
623 struct Library
* PrepareAROSSupportBase(struct ExecBase
*SysBase
)
625 struct AROSSupportBase
*AROSSupportBase
=
626 AllocMem(sizeof(struct AROSSupportBase
), MEMF_CLEAR
);
628 AROSSupportBase
->kprintf
= (void *)__kprintf
;
629 AROSSupportBase
->rkprintf
= (void *)__rkprintf
;
630 AROSSupportBase
->vkprintf
= (void *)__vkprintf
;
632 return (struct Library
*)AROSSupportBase
;
635 void _aros_not_implemented(char *string
) {}