Port the SB128 code to AROS.
[AROS.git] / rom / kernel / kernel_romtags.c
blobcb53dddba89654063128e37bbde37620c6a35194
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 ROMTag scanner.
6 */
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>
18 #include <string.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)
26 ULONG i;
28 for (i = 0; i < len; i++)
30 if (!strcmp(name, list[i]->rt_Name))
31 return i;
34 return -1;
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;
60 * RomTag scanner.
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
64 * wins.
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[])
79 UWORD *end;
80 UWORD *ptr; /* Start looking here */
81 struct Resident *res; /* module found */
82 ULONG i;
83 BOOL sorted;
84 /*
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;
99 ULONG num = 0;
101 /* Look in whole kickstart for resident modules */
102 while (*ranges != (UWORD *)~0)
104 ptr = *ranges++;
105 end = *ranges++;
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);
117 if (i != -1)
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
124 looses.
126 if ((old->rt_Version < res->rt_Version) ||
127 (old->rt_Version == res->rt_Version && old->rt_Pri <= res->rt_Pri))
129 RomTag[i] = res;
132 else
134 /* New module */
135 RomTag[num++] = res;
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
143 * and continue.
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.
148 if (num == limit)
149 return NULL;
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
155 * section */
156 ptr = ((IPTR)res->rt_EndSkip > (IPTR)ptr)
157 ? (UWORD *)res->rt_EndSkip - 2
158 : ptr;
160 if ((IPTR)ptr & 0x01)
161 ptr = (UWORD *)((IPTR)ptr+1);
164 /* Get next address... */
165 ptr++;
166 } while (ptr < (UWORD*)end);
169 /* Terminate the list */
170 RomTag[num] = NULL;
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
179 * KickMemPtr)
181 /* TODO: Implement external modules! */
184 * Building list is complete, sort RomTags according to their priority.
185 * I use BubbleSort algorithm.
189 sorted = TRUE;
191 for (i = 0; i < num - 1; i++)
193 if (RomTag[i]->rt_Pri < RomTag[i+1]->rt_Pri)
195 struct Resident *tmp;
197 tmp = RomTag[i+1];
198 RomTag[i+1] = RomTag[i];
199 RomTag[i] = tmp;
201 sorted = FALSE;
204 } while (!sorted);
206 return RomTag;
209 struct Resident *krnFindResident(struct Resident **resList, const char *name)
211 ULONG i;
213 for (i = 0; resList[i]; i++)
215 if (!strcmp(resList[i]->rt_Name, name))
216 return resList[i];
218 return NULL;
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);
227 if (!resList)
228 return NULL;
230 exec = krnFindResident(resList, "exec.library");
231 if (!exec)
232 return NULL;
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));
240 if (sysBase)
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)
248 ULONG i;
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);
258 #endif
260 return sysBase;