xref: /dragonfly/sys/kern/subr_module.c (revision aa8d5dcb)
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.3 2003/11/20 22:07:33 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 void
210 preload_delete_name(const char *name)
211 {
212     caddr_t	curp;
213     u_int32_t	*hdr;
214     int		next;
215     int		clearing;
216 
217     if (preload_metadata != NULL) {
218 
219 	clearing = 0;
220 	curp = preload_metadata;
221 	for (;;) {
222 	    hdr = (u_int32_t *)curp;
223 	    if (hdr[0] == 0 && hdr[1] == 0)
224 		break;
225 
226 	    /* Search for a MODINFO_NAME field */
227 	    if (hdr[0] == MODINFO_NAME) {
228 		if (!strcmp(name, curp + sizeof(u_int32_t) * 2))
229 		    clearing = 1;	/* got it, start clearing */
230 		else if (clearing)
231 		    clearing = 0;	/* at next one now.. better stop */
232 	    }
233 	    if (clearing)
234 		hdr[0] = MODINFO_EMPTY;
235 
236 	    /* skip to next field */
237 	    next = sizeof(u_int32_t) * 2 + hdr[1];
238 	    next = roundup(next, sizeof(u_long));
239 	    curp += next;
240 	}
241     }
242 }
243 
244 /* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
245 void
246 preload_bootstrap_relocate(vm_offset_t offset)
247 {
248     caddr_t	curp;
249     u_int32_t	*hdr;
250     vm_offset_t	*ptr;
251     int		next;
252 
253     if (preload_metadata != NULL) {
254 
255 	curp = preload_metadata;
256 	for (;;) {
257 	    hdr = (u_int32_t *)curp;
258 	    if (hdr[0] == 0 && hdr[1] == 0)
259 		break;
260 
261 	    /* Deal with the ones that we know we have to fix */
262 	    switch (hdr[0]) {
263 	    case MODINFO_ADDR:
264 	    case MODINFO_METADATA|MODINFOMD_SSYM:
265 	    case MODINFO_METADATA|MODINFOMD_ESYM:
266 		ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
267 		*ptr += offset;
268 		break;
269 	    }
270 	    /* The rest is beyond us for now */
271 
272 	    /* skip to next field */
273 	    next = sizeof(u_int32_t) * 2 + hdr[1];
274 	    next = roundup(next, sizeof(u_long));
275 	    curp += next;
276 	}
277     }
278 }
279