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 <exec/memheaderext.h>
15 #include <proto/alib.h>
16 #include <proto/exec.h>
20 #include <kernel_base.h>
21 #include <kernel_debug.h>
22 #include <kernel_romtags.h>
26 static LONG
findname(struct Resident
**list
, ULONG len
, CONST_STRPTR name
)
30 for (i
= 0; i
< len
; i
++)
32 if (!strcmp(name
, list
[i
]->rt_Name
))
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
;
52 return mhe
->mhe_Alloc(mhe
, *size
, NULL
);
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
));
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
;
81 mhe
->mhe_ReAlloc(mhe
, addr
, allocSize
);
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
)
95 mc
= addr
+ allocSize
;
97 mc
->mc_Next
= mh
->mh_First
;
98 mc
->mc_Bytes
= chunkSize
;
101 mh
->mh_Free
+= mc
->mc_Bytes
;
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
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
[])
126 UWORD
*ptr
; /* Start looking here */
127 struct Resident
*res
; /* module found */
131 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
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.
137 struct Resident
**RomTag
= krnGetSysMem(mh
, &chunkSize
);
138 IPTR limit
= chunkSize
/ sizeof(APTR
);
144 /* Look in whole kickstart for resident modules */
145 while (*ranges
!= (UWORD
*)~0)
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
);
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
173 if ((old
->rt_Version
< res
->rt_Version
) ||
174 (old
->rt_Version
== res
->rt_Version
&& old
->rt_Pri
<= res
->rt_Pri
))
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
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.
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
203 ptr
= ((IPTR
)res
->rt_EndSkip
> (IPTR
)ptr
)
204 ? (UWORD
*)res
->rt_EndSkip
- 2
207 if ((IPTR
)ptr
& 0x01)
208 ptr
= (UWORD
*)((IPTR
)ptr
+1);
211 /* Get next address... */
213 } while (ptr
< (UWORD
*)end
);
216 /* Terminate the list */
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.
230 for (i
= 0; i
< num
- 1; i
++)
232 if (RomTag
[i
]->rt_Pri
< RomTag
[i
+1]->rt_Pri
)
234 struct Resident
*tmp
;
237 RomTag
[i
+1] = RomTag
[i
];
248 struct Resident
*krnFindResident(struct Resident
**resList
, const char *name
)
252 for (i
= 0; resList
[i
]; i
++)
254 if (!strcmp(resList
[i
]->rt_Name
, name
))