gcc-4.6.2: Update with patch for gengtype.c
[AROS.git] / rom / kernel / kernel_romtags.c
blob8c89928652631b0dda6b3663adea71ec1f653e45
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 /* Just dequeue the first MemChunk. It's assumed that it has the required space for sure. */
45 struct MemChunk *mc = mh->mh_First;
47 mh->mh_First = mc->mc_Next;
48 mh->mh_Free -= mc->mc_Bytes;
50 D(bug("[RomTagScanner] Using chunk 0x%p of %lu bytes\n", mc, mc->mc_Bytes));
52 *size = mc->mc_Bytes;
53 return mc;
56 /* Release unused boot-time memory */
57 static void krnReleaseSysMem(struct MemHeader *mh, APTR addr, IPTR chunkSize, IPTR allocSize)
59 struct MemChunk *mc;
61 allocSize = AROS_ROUNDUP2(allocSize, MEMCHUNK_TOTAL);
62 chunkSize -= allocSize;
64 D(bug("[RomTagScanner] Chunk 0x%p, %lu of %lu bytes used\n", addr, allocSize, chunkSize));
66 if (chunkSize < MEMCHUNK_TOTAL)
67 return;
69 mc = addr + allocSize;
71 mc->mc_Next = mh->mh_First;
72 mc->mc_Bytes = chunkSize - allocSize;
74 mh->mh_First = mc;
75 mh->mh_Free += mc->mc_Bytes;
80 * RomTag scanner.
82 * This function scans kernel for existing Resident modules. If two modules
83 * with the same name are found, the one with higher version or priority
84 * wins.
86 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
87 * checksummed. If checksum is proper and all memory pointed in KickMemPtr
88 * may be allocated, then all modules from KickTagPtr are added to RT list
90 * Afterwards the proper RomTagList is created (see InitCode() for details)
91 * and memory after list and nodes is freed.
93 * The array ranges gives a [ start, end ] pair to scan, with an entry of
94 * -1 used to break the loop.
97 APTR krnRomTagScanner(struct MemHeader *mh, UWORD *ranges[])
99 UWORD *end;
100 UWORD *ptr; /* Start looking here */
101 struct Resident *res; /* module found */
102 ULONG i;
103 BOOL sorted;
105 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
106 * for this purpose.
107 * First we dequeue some space from the MemHeader, and remember its starting address and size. Then we
108 * construct resident list in this area. After it's done, we return part of the used space to the system.
110 IPTR chunkSize;
111 struct Resident **RomTag = krnGetSysMem(mh, &chunkSize);
112 IPTR limit = chunkSize / sizeof(APTR);
113 ULONG num = 0;
115 if (!RomTag)
116 return NULL;
118 /* Look in whole kickstart for resident modules */
119 while (*ranges != (UWORD *)~0)
121 ptr = *ranges++;
122 end = *ranges++;
124 /* Make sure that addresses are UWORD-aligned. In some circumstances they can be not. */
125 ptr = (UWORD *)(((IPTR)ptr + 1) & ~1);
126 end = (UWORD *)((IPTR)end & ~1);
128 D(bug("RomTagScanner: Start = %p, End = %p\n", ptr, end));
131 res = (struct Resident *)ptr;
133 /* Do we have RTC_MATCHWORD and rt_MatchTag*/
134 if (res->rt_MatchWord == RTC_MATCHWORD && res->rt_MatchTag == res)
136 /* Yes, it is Resident module. Check if there is module with such name already */
137 i = findname(RomTag, num, res->rt_Name);
138 if (i != -1)
140 struct Resident *old = RomTag[i];
142 Rules for replacing modules:
143 1. Higher version always wins.
144 2. If the versions are equal, then lower priority
145 looses.
147 if ((old->rt_Version < res->rt_Version) ||
148 (old->rt_Version == res->rt_Version && old->rt_Pri <= res->rt_Pri))
150 RomTag[i] = res;
153 else
155 /* New module */
156 RomTag[num++] = res;
158 * 'limit' holds a length of our MemChunk in pointers.
159 * Actually it's a number or pointers we can safely store in it (including NULL terminator).
160 * If it's exceeded, return NULL.
161 * TODO: If ever needed, this routine can be made smarter. There can be
162 * the following approaches:
163 * a) Move the data to a next MemChunk which is bigger than the current one
164 * and continue.
165 * b) In the beginning of this routine, find the largest available MemChunk and use it.
166 * Note that we exit with destroyed MemChunk here. Anyway, failure here means the system
167 * is completely unable to boot up.
169 if (num == limit)
170 return NULL;
173 /* Get address of EndOfResident from RomTag but only when
174 * it's higher then present one - this avoids strange locks
175 * when not all modules have Resident structure in .text
176 * section */
177 ptr = ((IPTR)res->rt_EndSkip > (IPTR)ptr)
178 ? (UWORD *)res->rt_EndSkip - 2
179 : ptr;
181 if ((IPTR)ptr & 0x01)
182 ptr = (UWORD *)((IPTR)ptr+1);
185 /* Get next address... */
186 ptr++;
187 } while (ptr < (UWORD*)end);
190 /* Terminate the list */
191 RomTag[num] = NULL;
193 /* Seal our used memory as allocated */
194 krnReleaseSysMem(mh, RomTag, chunkSize, (num + 1) * sizeof(struct Resident *));
197 * Building list is complete, sort RomTags according to their priority.
198 * I use BubbleSort algorithm.
202 sorted = TRUE;
204 for (i = 0; i < num - 1; i++)
206 if (RomTag[i]->rt_Pri < RomTag[i+1]->rt_Pri)
208 struct Resident *tmp;
210 tmp = RomTag[i+1];
211 RomTag[i+1] = RomTag[i];
212 RomTag[i] = tmp;
214 sorted = FALSE;
217 } while (!sorted);
219 return RomTag;
222 struct Resident *krnFindResident(struct Resident **resList, const char *name)
224 ULONG i;
226 for (i = 0; resList[i]; i++)
228 if (!strcmp(resList[i]->rt_Name, name))
229 return resList[i];
231 return NULL;