2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
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>
19 #include <kernel_base.h>
20 #include <kernel_debug.h>
21 #include <kernel_romtags.h>
25 static LONG
findname(struct Resident
**list
, ULONG len
, CONST_STRPTR name
)
29 for (i
= 0; i
< len
; i
++)
31 if (!strcmp(name
, list
[i
]->rt_Name
))
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
;
51 return mhe
->mhe_Alloc(mhe
, *size
, NULL
);
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
));
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
;
77 mhe
->mhe_Realloc(mhe
, addr
, allocSize
);
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
)
91 mc
= addr
+ allocSize
;
93 mc
->mc_Next
= mh
->mh_First
;
94 mc
->mc_Bytes
= chunkSize
- allocSize
;
97 mh
->mh_Free
+= mc
->mc_Bytes
;
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
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
[])
122 UWORD
*ptr
; /* Start looking here */
123 struct Resident
*res
; /* module found */
127 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
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.
133 struct Resident
**RomTag
= krnGetSysMem(mh
, &chunkSize
);
134 IPTR limit
= chunkSize
/ sizeof(APTR
);
140 /* Look in whole kickstart for resident modules */
141 while (*ranges
!= (UWORD
*)~0)
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
);
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
169 if ((old
->rt_Version
< res
->rt_Version
) ||
170 (old
->rt_Version
== res
->rt_Version
&& old
->rt_Pri
<= res
->rt_Pri
))
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
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.
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
199 ptr
= ((IPTR
)res
->rt_EndSkip
> (IPTR
)ptr
)
200 ? (UWORD
*)res
->rt_EndSkip
- 2
203 if ((IPTR
)ptr
& 0x01)
204 ptr
= (UWORD
*)((IPTR
)ptr
+1);
207 /* Get next address... */
209 } while (ptr
< (UWORD
*)end
);
212 /* Terminate the list */
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.
226 for (i
= 0; i
< num
- 1; i
++)
228 if (RomTag
[i
]->rt_Pri
< RomTag
[i
+1]->rt_Pri
)
230 struct Resident
*tmp
;
233 RomTag
[i
+1] = RomTag
[i
];
244 struct Resident
*krnFindResident(struct Resident
**resList
, const char *name
)
248 for (i
= 0; resList
[i
]; i
++)
250 if (!strcmp(resList
[i
]->rt_Name
, name
))