xref: /dragonfly/sys/kern/subr_module.c (revision 279dd846)
1 /*-
2  * Copyright (c) 1998 Michael Smith
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
27  * $DragonFly: src/sys/kern/subr_module.c,v 1.4 2004/05/26 08:32:41 dillon Exp $
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/linker.h>
33 
34 /*
35  * Preloaded module support
36  */
37 
38 caddr_t	preload_metadata;
39 
40 /*
41  * Search for the preloaded module (name)
42  */
43 caddr_t
44 preload_search_by_name(const char *name)
45 {
46     caddr_t	curp;
47     u_int32_t	*hdr;
48     int		next;
49     int		i;
50     char	*scanname;
51 
52     if (preload_metadata == NULL)
53 	return(NULL);
54 
55     curp = preload_metadata;
56     for (;;) {
57 	hdr = (u_int32_t *)curp;
58 	if (hdr[0] == 0 && hdr[1] == 0)
59 	    break;
60 
61 	/*
62 	 * Search for a MODINFO_NAME field.  the boot loader really
63 	 * ought to strip the path names
64 	 */
65 	if (hdr[0] == MODINFO_NAME) {
66 	    scanname = curp + sizeof(u_int32_t) * 2;
67 	    i = strlen(scanname);
68 	    while (i > 0 && scanname[i-1] != '/')
69 		--i;
70 	    if (strcmp(name, scanname) == 0)
71 		return(curp);
72 	    if (strcmp(name, scanname + i) == 0)
73 		return(curp);
74 	}
75 	/* skip to next field */
76 	next = sizeof(u_int32_t) * 2 + hdr[1];
77 	next = roundup(next, sizeof(u_long));
78 	curp += next;
79     }
80     return(NULL);
81 }
82 
83 /*
84  * Search for the first preloaded module of (type)
85  */
86 caddr_t
87 preload_search_by_type(const char *type)
88 {
89     caddr_t	curp, lname;
90     u_int32_t	*hdr;
91     int		next;
92 
93     if (preload_metadata != NULL) {
94 
95 	curp = preload_metadata;
96 	lname = NULL;
97 	for (;;) {
98 	    hdr = (u_int32_t *)curp;
99 	    if (hdr[0] == 0 && hdr[1] == 0)
100 		break;
101 
102 	    /* remember the start of each record */
103 	    if (hdr[0] == MODINFO_NAME)
104 		lname = curp;
105 
106 	    /* Search for a MODINFO_TYPE field */
107 	    if ((hdr[0] == MODINFO_TYPE) &&
108 		!strcmp(type, curp + sizeof(u_int32_t) * 2))
109 		return(lname);
110 
111 	    /* skip to next field */
112 	    next = sizeof(u_int32_t) * 2 + hdr[1];
113 	    next = roundup(next, sizeof(u_long));
114 	    curp += next;
115 	}
116     }
117     return(NULL);
118 }
119 
120 /*
121  * Walk through the preloaded module list
122  */
123 caddr_t
124 preload_search_next_name(caddr_t base)
125 {
126     caddr_t	curp;
127     u_int32_t	*hdr;
128     int		next;
129 
130     if (preload_metadata != NULL) {
131 
132 	/* Pick up where we left off last time */
133 	if (base) {
134 	    /* skip to next field */
135 	    curp = base;
136 	    hdr = (u_int32_t *)curp;
137 	    next = sizeof(u_int32_t) * 2 + hdr[1];
138 	    next = roundup(next, sizeof(u_long));
139 	    curp += next;
140 	} else
141 	    curp = preload_metadata;
142 
143 	for (;;) {
144 	    hdr = (u_int32_t *)curp;
145 	    if (hdr[0] == 0 && hdr[1] == 0)
146 		break;
147 
148 	    /* Found a new record? */
149 	    if (hdr[0] == MODINFO_NAME)
150 		return curp;
151 
152 	    /* skip to next field */
153 	    next = sizeof(u_int32_t) * 2 + hdr[1];
154 	    next = roundup(next, sizeof(u_long));
155 	    curp += next;
156 	}
157     }
158     return(NULL);
159 }
160 
161 /*
162  * Given a preloaded module handle (mod), return a pointer
163  * to the data for the attribute (inf).
164  */
165 caddr_t
166 preload_search_info(caddr_t mod, int inf)
167 {
168     caddr_t	curp;
169     u_int32_t	*hdr;
170     u_int32_t	type = 0;
171     int		next;
172 
173     curp = mod;
174     for (;;) {
175 	hdr = (u_int32_t *)curp;
176 	/* end of module data? */
177 	if (hdr[0] == 0 && hdr[1] == 0)
178 	    break;
179 	/*
180 	 * We give up once we've looped back to what we were looking at
181 	 * first - this should normally be a MODINFO_NAME field.
182 	 */
183 	if (type == 0) {
184 	    type = hdr[0];
185 	} else {
186 	    if (hdr[0] == type)
187 		break;
188 	}
189 
190 	/*
191 	 * Attribute match? Return pointer to data.
192 	 * Consumer may safely assume that size value preceeds
193 	 * data.
194 	 */
195 	if (hdr[0] == inf)
196 	    return(curp + (sizeof(u_int32_t) * 2));
197 
198 	/* skip to next field */
199 	next = sizeof(u_int32_t) * 2 + hdr[1];
200 	next = roundup(next, sizeof(u_long));
201 	curp += next;
202     }
203     return(NULL);
204 }
205 
206 /*
207  * Delete a preload record by name.
208  *
209  * XXX we should really pass the base of the preloaded module here and not
210  * require rematching of the name.  If the wrong module (or no module) is
211  * deleted, the original preloaded module might be loaded again, causing it's
212  * data to be relocated twice.
213  */
214 void
215 preload_delete_name(const char *name)
216 {
217     caddr_t	curp;
218     u_int32_t	*hdr;
219     int		next;
220     int		clearing;
221     int		i;
222     char	*scanname;
223 
224     if (preload_metadata != NULL) {
225 	clearing = 0;
226 	curp = preload_metadata;
227 	for (;;) {
228 	    hdr = (u_int32_t *)curp;
229 	    if (hdr[0] == 0 && hdr[1] == 0)
230 		break;
231 
232 	    /* Search for a MODINFO_NAME field */
233 	    if (hdr[0] == MODINFO_NAME) {
234 		scanname = curp + sizeof(u_int32_t) * 2;
235 		i = strlen(scanname);
236 		while (i > 0 && scanname[i-1] != '/')
237 		    --i;
238 		if (strcmp(name, scanname) == 0)
239 		    clearing = 1;
240 		else if (strcmp(name, scanname + i) == 0)
241 		    clearing = 1;
242 		else
243 		    clearing = 0;	/* at next module now, stop clearing */
244 	    }
245 	    if (clearing)
246 		hdr[0] = MODINFO_EMPTY;
247 
248 	    /* skip to next field */
249 	    next = sizeof(u_int32_t) * 2 + hdr[1];
250 	    next = roundup(next, sizeof(u_long));
251 	    curp += next;
252 	}
253     }
254 }
255 
256 /* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
257 void
258 preload_bootstrap_relocate(vm_offset_t offset)
259 {
260     caddr_t	curp;
261     u_int32_t	*hdr;
262     vm_offset_t	*ptr;
263     int		next;
264 
265     if (preload_metadata != NULL) {
266 
267 	curp = preload_metadata;
268 	for (;;) {
269 	    hdr = (u_int32_t *)curp;
270 	    if (hdr[0] == 0 && hdr[1] == 0)
271 		break;
272 
273 	    /* Deal with the ones that we know we have to fix */
274 	    switch (hdr[0]) {
275 	    case MODINFO_ADDR:
276 	    case MODINFO_METADATA|MODINFOMD_SSYM:
277 	    case MODINFO_METADATA|MODINFOMD_ESYM:
278 		ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
279 		*ptr += offset;
280 		break;
281 	    }
282 	    /* The rest is beyond us for now */
283 
284 	    /* skip to next field */
285 	    next = sizeof(u_int32_t) * 2 + hdr[1];
286 	    next = roundup(next, sizeof(u_long));
287 	    curp += next;
288 	}
289     }
290 }
291