refactored some code. compiles now without suppresing any warning with gcc-6.3.0.
[AROS.git] / rom / kernel / kernel_romtags.c
blob6bd4c855547a492d49202f33fc82118aa76fedc7
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 <exec/memheaderext.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 #define D(x)
26 static LONG findname(struct Resident **list, ULONG len, CONST_STRPTR name)
28 ULONG i;
30 for (i = 0; i < len; i++)
32 if (!strcmp(name, list[i]->rt_Name))
33 return i;
36 return -1;
39 /*
40 * Allocate memory space for boot-time usage. Returns address and size of the usable area.
41 * It's strongly adviced to return enough space to store resident list of sane length.
43 static APTR krnGetSysMem(struct MemHeader *mh, IPTR *size)
45 if (mh->mh_Attributes & MEMF_MANAGED)
47 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
49 if (mhe->mhe_Alloc)
51 *size = 1024*1024;
52 return mhe->mhe_Alloc(mhe, *size, NULL);
55 *size = 0;
56 return NULL;
58 else
60 /* Just dequeue the first MemChunk. It's assumed that it has the required space for sure. */
61 struct MemChunk *mc = mh->mh_First;
63 mh->mh_First = mc->mc_Next;
64 mh->mh_Free -= mc->mc_Bytes;
66 D(bug("[RomTagScanner] Using chunk 0x%p of %lu bytes\n", mc, mc->mc_Bytes));
68 *size = mc->mc_Bytes;
69 return mc;
73 /* Release unused boot-time memory */
74 static void krnReleaseSysMem(struct MemHeader *mh, APTR addr, IPTR chunkSize, IPTR allocSize)
76 if (mh->mh_Attributes & MEMF_MANAGED)
78 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
80 if (mhe->mhe_ReAlloc)
81 mhe->mhe_ReAlloc(mhe, addr, allocSize);
83 else
85 struct MemChunk *mc;
87 allocSize = AROS_ROUNDUP2(allocSize, MEMCHUNK_TOTAL);
88 chunkSize -= allocSize;
90 D(bug("[RomTagScanner] Chunk 0x%p, %lu of %lu bytes used\n", addr, allocSize, chunkSize));
92 if (chunkSize < MEMCHUNK_TOTAL)
93 return;
95 mc = addr + allocSize;
97 mc->mc_Next = mh->mh_First;
98 mc->mc_Bytes = chunkSize;
100 mh->mh_First = mc;
101 mh->mh_Free += mc->mc_Bytes;
106 * RomTag scanner.
108 * This function scans kernel for existing Resident modules. If two modules
109 * with the same name are found, the one with higher version or priority
110 * wins.
112 * After building list of kernel modules, the KickTagPtr and KickMemPtr are
113 * checksummed. If checksum is proper and all memory pointed in KickMemPtr
114 * may be allocated, then all modules from KickTagPtr are added to RT list
116 * Afterwards the proper RomTagList is created (see InitCode() for details)
117 * and memory after list and nodes is freed.
119 * The array ranges gives a [ start, end ] pair to scan, with an entry of
120 * -1 used to break the loop.
123 APTR krnRomTagScanner(struct MemHeader *mh, UWORD *ranges[])
125 UWORD *end;
126 UWORD *ptr; /* Start looking here */
127 struct Resident *res; /* module found */
128 ULONG i;
129 BOOL sorted;
131 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
132 * for this purpose.
133 * First we dequeue some space from the MemHeader, and remember its starting address and size. Then we
134 * construct resident list in this area. After it's done, we return part of the used space to the system.
136 IPTR chunkSize;
137 struct Resident **RomTag = krnGetSysMem(mh, &chunkSize);
138 IPTR limit = chunkSize / sizeof(APTR);
139 ULONG num = 0;
141 if (!RomTag)
142 return NULL;
144 /* Look in whole kickstart for resident modules */
145 while (*ranges != (UWORD *)~0)
147 ptr = *ranges++;
148 end = *ranges++;
150 /* Make sure that addresses are UWORD-aligned. In some circumstances they can be not. */
151 ptr = (UWORD *)(((IPTR)ptr + 1) & ~1);
152 end = (UWORD *)((IPTR)end & ~1);
154 D(bug("RomTagScanner: Start = %p, End = %p\n", ptr, end));
157 res = (struct Resident *)ptr;
159 /* Do we have RTC_MATCHWORD and rt_MatchTag*/
160 if (res->rt_MatchWord == RTC_MATCHWORD && res->rt_MatchTag == res)
162 /* Yes, it is Resident module. Check if there is module with such name already */
163 i = findname(RomTag, num, res->rt_Name);
164 if (i != -1)
166 struct Resident *old = RomTag[i];
168 Rules for replacing modules:
169 1. Higher version always wins.
170 2. If the versions are equal, then lower priority
171 looses.
173 if ((old->rt_Version < res->rt_Version) ||
174 (old->rt_Version == res->rt_Version && old->rt_Pri <= res->rt_Pri))
176 RomTag[i] = res;
179 else
181 /* New module */
182 RomTag[num++] = res;
184 * 'limit' holds a length of our MemChunk in pointers.
185 * Actually it's a number or pointers we can safely store in it (including NULL terminator).
186 * If it's exceeded, return NULL.
187 * TODO: If ever needed, this routine can be made smarter. There can be
188 * the following approaches:
189 * a) Move the data to a next MemChunk which is bigger than the current one
190 * and continue.
191 * b) In the beginning of this routine, find the largest available MemChunk and use it.
192 * Note that we exit with destroyed MemChunk here. Anyway, failure here means the system
193 * is completely unable to boot up.
195 if (num == limit)
196 return NULL;
199 /* Get address of EndOfResident from RomTag but only when
200 * it's higher then present one - this avoids strange locks
201 * when not all modules have Resident structure in .text
202 * section */
203 ptr = ((IPTR)res->rt_EndSkip > (IPTR)ptr)
204 ? (UWORD *)res->rt_EndSkip - 2
205 : ptr;
207 if ((IPTR)ptr & 0x01)
208 ptr = (UWORD *)((IPTR)ptr+1);
211 /* Get next address... */
212 ptr++;
213 } while (ptr < (UWORD*)end);
216 /* Terminate the list */
217 RomTag[num] = NULL;
219 /* Seal our used memory as allocated */
220 krnReleaseSysMem(mh, RomTag, chunkSize, (num + 1) * sizeof(struct Resident *));
223 * Building list is complete, sort RomTags according to their priority.
224 * I use BubbleSort algorithm.
228 sorted = TRUE;
230 for (i = 0; i < num - 1; i++)
232 if (RomTag[i]->rt_Pri < RomTag[i+1]->rt_Pri)
234 struct Resident *tmp;
236 tmp = RomTag[i+1];
237 RomTag[i+1] = RomTag[i];
238 RomTag[i] = tmp;
240 sorted = FALSE;
243 } while (!sorted);
245 return RomTag;
248 struct Resident *krnFindResident(struct Resident **resList, const char *name)
250 ULONG i;
252 for (i = 0; resList[i]; i++)
254 if (!strcmp(resList[i]->rt_Name, name))
255 return resList[i];
257 return NULL;