2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
8 #include <aros/debug.h>
9 #include <aros/asmcall.h>
10 #include <exec/execbase.h>
11 #include <exec/lists.h>
12 #include <exec/nodes.h>
13 #include <exec/memory.h>
14 #include <exec/resident.h>
15 #include <proto/alib.h>
16 #include <proto/exec.h>
20 #include <kernel_base.h>
21 #include <kernel_debug.h>
22 #include <kernel_romtags.h>
24 static LONG
findname(struct Resident
**list
, ULONG len
, CONST_STRPTR name
)
28 for (i
= 0; i
< len
; i
++)
30 if (!strcmp(name
, list
[i
]->rt_Name
))
38 * Our own, very simplified down memory allocator.
39 * We use it because we should avoid to statically link in functions from other modules.
40 * Currently the only linked in function is PrepareExecBase() and at some point it will
41 * change. It will be possible to completely separate exec.library and kernel.resource,
42 * and load them separately from the bootstrap.
44 * It is okay to use this routine because this is one of the first allocations (actually
45 * should be the first one) and it is never going to be freed.
46 * Additionally, in order to be able to discover exec.library (and its early init function)
47 * dynamically, we want krnRomTagScanner() to work before ExecBase is created.
49 static inline void krnAllocBootMem(struct MemHeader
*mh
, struct MemChunk
*next
, IPTR chunkSize
, IPTR allocSize
)
51 allocSize
= AROS_ROUNDUP2(allocSize
, MEMCHUNK_TOTAL
);
53 mh
->mh_First
= (struct MemChunk
*)((APTR
)mh
->mh_First
+ allocSize
);
54 mh
->mh_First
->mc_Next
= next
;
55 mh
->mh_Free
-= allocSize
;
56 mh
->mh_First
->mc_Bytes
= chunkSize
- allocSize
;
62 * This function scans kernel for existing Resident modules. If two modules
63 * with the same name are found, the one with higher version or priority
66 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
67 * checksummed. If checksum is proper and all memory pointed in KickMemPtr
68 * may be allocated, then all modules from KickTagPtr are added to RT list
70 * Afterwards the proper RomTagList is created (see InitCode() for details)
71 * and memory after list and nodes is freed.
73 * The array ranges gives a [ start, end ] pair to scan, with an entry of
74 * -1 used to break the loop.
77 APTR
krnRomTagScanner(struct MemHeader
*mh
, UWORD
*ranges
[])
80 UWORD
*ptr
; /* Start looking here */
81 struct Resident
*res
; /* module found */
85 * We take the beginning of free memory from our boot MemHeader
86 * and construct resident list there.
87 * When we are done we know list length, so we can seal the used
88 * memory by allocating it from the MemHeader.
89 * This is 100% safe because we are here long before multitasking
90 * is started up. However in some situations we can already have several
91 * MemChunks in our MemHeader (this happens on softkicked m68k Amiga).
92 * So, we preserve origiinal chunk size and next chunk pointer.
93 * Note that we expect the first chunk in the MemHeader to have enough space for resident list.
95 struct MemChunk
*nextChunk
= mh
->mh_First
->mc_Next
;
96 IPTR chunkSize
= mh
->mh_First
->mc_Bytes
;
97 IPTR limit
= chunkSize
/ sizeof(APTR
);
98 struct Resident
**RomTag
= (struct Resident
**)mh
->mh_First
;
101 /* Look in whole kickstart for resident modules */
102 while (*ranges
!= (UWORD
*)~0)
107 D(bug("RomTagScanner: Start = %p, End = %p\n", ptr
, end
));
110 res
= (struct Resident
*)ptr
;
112 /* Do we have RTC_MATCHWORD and rt_MatchTag*/
113 if (res
->rt_MatchWord
== RTC_MATCHWORD
&& res
->rt_MatchTag
== res
)
115 /* Yes, it is Resident module. Check if there is module with such name already */
116 i
= findname((struct Resident
**)mh
->mh_First
, num
, res
->rt_Name
);
119 struct Resident
*old
= RomTag
[i
];
121 Rules for replacing modules:
122 1. Higher version always wins.
123 2. If the versions are equal, then lower priority
126 if ((old
->rt_Version
< res
->rt_Version
) ||
127 (old
->rt_Version
== res
->rt_Version
&& old
->rt_Pri
<= res
->rt_Pri
))
137 * 'limit' holds a length of our MemChunk in pointers.
138 * Actually it's a number or pointers we can safely store in it (including NULL terminator).
139 * If it's exceeded, return NULL.
140 * TODO: If ever needed, this routine can be made smarter. There can be
141 * the following approaches:
142 * a) Move the data to a next MemChunk which is bigger than the current one
144 * b) In the beginning of this routine, find the largest available MemChunk and use it.
145 * Note that we exit with destroyed MemChunk here. Anyway, failure here means the system
146 * is completely unable to boot up.
152 /* Get address of EndOfResident from RomTag but only when
153 * it's higher then present one - this avoids strange locks
154 * when not all modules have Resident structure in .text
156 ptr
= ((IPTR
)res
->rt_EndSkip
> (IPTR
)ptr
)
157 ? (UWORD
*)res
->rt_EndSkip
- 2
160 if ((IPTR
)ptr
& 0x01)
161 ptr
= (UWORD
*)((IPTR
)ptr
+1);
164 /* Get next address... */
166 } while (ptr
< (UWORD
*)end
);
169 /* Terminate the list */
172 /* Seal our used memory as allocated */
173 krnAllocBootMem(mh
, nextChunk
, chunkSize
, (num
+ 1) * sizeof(struct Resident
*));
176 * By now we have valid list of kickstart resident modules.
178 * Now, we will have to analyze used-defined RomTags (via KickTagPtr and
181 /* TODO: Implement external modules! */
184 * Building list is complete, sort RomTags according to their priority.
185 * I use BubbleSort algorithm.
191 for (i
= 0; i
< num
- 1; i
++)
193 if (RomTag
[i
]->rt_Pri
< RomTag
[i
+1]->rt_Pri
)
195 struct Resident
*tmp
;
198 RomTag
[i
+1] = RomTag
[i
];
209 struct Resident
*krnFindResident(struct Resident
**resList
, const char *name
)
213 for (i
= 0; resList
[i
]; i
++)
215 if (!strcmp(resList
[i
]->rt_Name
, name
))
221 struct ExecBase
*krnPrepareExecBase(UWORD
*ranges
[], struct MemHeader
*mh
, struct TagItem
*bootMsg
)
223 struct Resident
*exec
;
224 struct ExecBase
*sysBase
;
225 struct Resident
**resList
= krnRomTagScanner(mh
, ranges
);
230 exec
= krnFindResident(resList
, "exec.library");
234 /* Magic. Described in rom/exec/exec_init.c. */
235 sysBase
= AROS_UFC3(struct ExecBase
*, exec
->rt_Init
,
236 AROS_UFCA(struct MemHeader
*, mh
, D0
),
237 AROS_UFCA(struct TagItem
*, bootMsg
, A0
),
238 AROS_UFCA(struct ExecBase
*, NULL
, A6
));
242 sysBase
->ResModules
= resList
;
244 #ifndef NO_RUNTIME_DEBUG
245 /* Print out modules list if requested by the user */
246 if (SysBase
->ex_DebugFlags
& EXECDEBUGF_INITCODE
)
250 bug("Resident modules (addr: pri flags version name):\n");
252 for (i
= 0; resList
[i
]; i
++)
254 bug("+ %p: %4d %02x %3d \"%s\"\n", resList
[i
], resList
[i
]->rt_Pri
,
255 resList
[i
]->rt_Flags
, resList
[i
]->rt_Version
, resList
[i
]->rt_Name
);