support for MEMF_MANAGED memory is back in the system. Moreover, the MemHeaderExt...
[AROS.git] / rom / kernel / kernel_romtags.c
bloba40e402f6ed00170e44e5093768a5fcf483a7f1f
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 ROMTag scanner.
6 */
8 #include <aros/asmcall.h>
9 #include <exec/execbase.h>
10 #include <exec/lists.h>
11 #include <exec/nodes.h>
12 #include <exec/memory.h>
13 #include <exec/resident.h>
14 #include <proto/alib.h>
15 #include <proto/exec.h>
17 #include <string.h>
19 #include <kernel_base.h>
20 #include <kernel_debug.h>
21 #include <kernel_romtags.h>
23 #define D(x)
25 static LONG findname(struct Resident **list, ULONG len, CONST_STRPTR name)
27 ULONG i;
29 for (i = 0; i < len; i++)
31 if (!strcmp(name, list[i]->rt_Name))
32 return i;
35 return -1;
38 /*
39 * Allocate memory space for boot-time usage. Returns address and size of the usable area.
40 * It's strongly adviced to return enough space to store resident list of sane length.
42 static APTR krnGetSysMem(struct MemHeader *mh, IPTR *size)
44 if (mh->mh_Attributes & MEMF_MANAGED)
46 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
48 if (mhe->mhe_Alloc)
50 *size = 1024*1024;
51 return mhe->mhe_Alloc(mhe, *size, NULL);
54 else
56 /* Just dequeue the first MemChunk. It's assumed that it has the required space for sure. */
57 struct MemChunk *mc = mh->mh_First;
59 mh->mh_First = mc->mc_Next;
60 mh->mh_Free -= mc->mc_Bytes;
62 D(bug("[RomTagScanner] Using chunk 0x%p of %lu bytes\n", mc, mc->mc_Bytes));
64 *size = mc->mc_Bytes;
65 return mc;
69 /* Release unused boot-time memory */
70 static void krnReleaseSysMem(struct MemHeader *mh, APTR addr, IPTR chunkSize, IPTR allocSize)
72 if (mh->mh_Attributes & MEMF_MANAGED)
74 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
76 if (mhe->mhe_Realloc)
77 mhe->mhe_Realloc(mhe, addr, allocSize);
79 else
81 struct MemChunk *mc;
83 allocSize = AROS_ROUNDUP2(allocSize, MEMCHUNK_TOTAL);
84 chunkSize -= allocSize;
86 D(bug("[RomTagScanner] Chunk 0x%p, %lu of %lu bytes used\n", addr, allocSize, chunkSize));
88 if (chunkSize < MEMCHUNK_TOTAL)
89 return;
91 mc = addr + allocSize;
93 mc->mc_Next = mh->mh_First;
94 mc->mc_Bytes = chunkSize - allocSize;
96 mh->mh_First = mc;
97 mh->mh_Free += mc->mc_Bytes;
102 * RomTag scanner.
104 * This function scans kernel for existing Resident modules. If two modules
105 * with the same name are found, the one with higher version or priority
106 * wins.
108 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
109 * checksummed. If checksum is proper and all memory pointed in KickMemPtr
110 * may be allocated, then all modules from KickTagPtr are added to RT list
112 * Afterwards the proper RomTagList is created (see InitCode() for details)
113 * and memory after list and nodes is freed.
115 * The array ranges gives a [ start, end ] pair to scan, with an entry of
116 * -1 used to break the loop.
119 APTR krnRomTagScanner(struct MemHeader *mh, UWORD *ranges[])
121 UWORD *end;
122 UWORD *ptr; /* Start looking here */
123 struct Resident *res; /* module found */
124 ULONG i;
125 BOOL sorted;
127 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
128 * for this purpose.
129 * First we dequeue some space from the MemHeader, and remember its starting address and size. Then we
130 * construct resident list in this area. After it's done, we return part of the used space to the system.
132 IPTR chunkSize;
133 struct Resident **RomTag = krnGetSysMem(mh, &chunkSize);
134 IPTR limit = chunkSize / sizeof(APTR);
135 ULONG num = 0;
137 if (!RomTag)
138 return NULL;
140 /* Look in whole kickstart for resident modules */
141 while (*ranges != (UWORD *)~0)
143 ptr = *ranges++;
144 end = *ranges++;
146 /* Make sure that addresses are UWORD-aligned. In some circumstances they can be not. */
147 ptr = (UWORD *)(((IPTR)ptr + 1) & ~1);
148 end = (UWORD *)((IPTR)end & ~1);
150 D(bug("RomTagScanner: Start = %p, End = %p\n", ptr, end));
153 res = (struct Resident *)ptr;
155 /* Do we have RTC_MATCHWORD and rt_MatchTag*/
156 if (res->rt_MatchWord == RTC_MATCHWORD && res->rt_MatchTag == res)
158 /* Yes, it is Resident module. Check if there is module with such name already */
159 i = findname(RomTag, num, res->rt_Name);
160 if (i != -1)
162 struct Resident *old = RomTag[i];
164 Rules for replacing modules:
165 1. Higher version always wins.
166 2. If the versions are equal, then lower priority
167 looses.
169 if ((old->rt_Version < res->rt_Version) ||
170 (old->rt_Version == res->rt_Version && old->rt_Pri <= res->rt_Pri))
172 RomTag[i] = res;
175 else
177 /* New module */
178 RomTag[num++] = res;
180 * 'limit' holds a length of our MemChunk in pointers.
181 * Actually it's a number or pointers we can safely store in it (including NULL terminator).
182 * If it's exceeded, return NULL.
183 * TODO: If ever needed, this routine can be made smarter. There can be
184 * the following approaches:
185 * a) Move the data to a next MemChunk which is bigger than the current one
186 * and continue.
187 * b) In the beginning of this routine, find the largest available MemChunk and use it.
188 * Note that we exit with destroyed MemChunk here. Anyway, failure here means the system
189 * is completely unable to boot up.
191 if (num == limit)
192 return NULL;
195 /* Get address of EndOfResident from RomTag but only when
196 * it's higher then present one - this avoids strange locks
197 * when not all modules have Resident structure in .text
198 * section */
199 ptr = ((IPTR)res->rt_EndSkip > (IPTR)ptr)
200 ? (UWORD *)res->rt_EndSkip - 2
201 : ptr;
203 if ((IPTR)ptr & 0x01)
204 ptr = (UWORD *)((IPTR)ptr+1);
207 /* Get next address... */
208 ptr++;
209 } while (ptr < (UWORD*)end);
212 /* Terminate the list */
213 RomTag[num] = NULL;
215 /* Seal our used memory as allocated */
216 krnReleaseSysMem(mh, RomTag, chunkSize, (num + 1) * sizeof(struct Resident *));
219 * Building list is complete, sort RomTags according to their priority.
220 * I use BubbleSort algorithm.
224 sorted = TRUE;
226 for (i = 0; i < num - 1; i++)
228 if (RomTag[i]->rt_Pri < RomTag[i+1]->rt_Pri)
230 struct Resident *tmp;
232 tmp = RomTag[i+1];
233 RomTag[i+1] = RomTag[i];
234 RomTag[i] = tmp;
236 sorted = FALSE;
239 } while (!sorted);
241 return RomTag;
244 struct Resident *krnFindResident(struct Resident **resList, const char *name)
246 ULONG i;
248 for (i = 0; resList[i]; i++)
250 if (!strcmp(resList[i]->rt_Name, name))
251 return resList[i];
253 return NULL;