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 /* 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
));
56 /* Release unused boot-time memory */
57 static void krnReleaseSysMem(struct MemHeader
*mh
, APTR addr
, IPTR chunkSize
, IPTR allocSize
)
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
)
69 mc
= addr
+ allocSize
;
71 mc
->mc_Next
= mh
->mh_First
;
72 mc
->mc_Bytes
= chunkSize
- allocSize
;
75 mh
->mh_Free
+= mc
->mc_Bytes
;
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
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
[])
100 UWORD
*ptr
; /* Start looking here */
101 struct Resident
*res
; /* module found */
105 * We don't know resident list size until it's created. Because of this, we use two-step memory allocation
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.
111 struct Resident
**RomTag
= krnGetSysMem(mh
, &chunkSize
);
112 IPTR limit
= chunkSize
/ sizeof(APTR
);
118 /* Look in whole kickstart for resident modules */
119 while (*ranges
!= (UWORD
*)~0)
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
);
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
147 if ((old
->rt_Version
< res
->rt_Version
) ||
148 (old
->rt_Version
== res
->rt_Version
&& old
->rt_Pri
<= res
->rt_Pri
))
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
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.
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
177 ptr
= ((IPTR
)res
->rt_EndSkip
> (IPTR
)ptr
)
178 ? (UWORD
*)res
->rt_EndSkip
- 2
181 if ((IPTR
)ptr
& 0x01)
182 ptr
= (UWORD
*)((IPTR
)ptr
+1);
185 /* Get next address... */
187 } while (ptr
< (UWORD
*)end
);
190 /* Terminate the list */
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.
204 for (i
= 0; i
< num
- 1; i
++)
206 if (RomTag
[i
]->rt_Pri
< RomTag
[i
+1]->rt_Pri
)
208 struct Resident
*tmp
;
211 RomTag
[i
+1] = RomTag
[i
];
222 struct Resident
*krnFindResident(struct Resident
**resList
, const char *name
)
226 for (i
= 0; resList
[i
]; i
++)
228 if (!strcmp(resList
[i
]->rt_Name
, name
))