xref: /dragonfly/sys/kern/subr_module.c (revision 6a3cbbc2)
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  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32 
33 /*
34  * Preloaded module support
35  */
36 
37 caddr_t	preload_metadata;
38 
39 /*
40  * Search for the preloaded module (name)
41  */
42 caddr_t
43 preload_search_by_name(const char *name)
44 {
45     caddr_t	curp;
46     u_int32_t	*hdr;
47     int		next;
48     int		i;
49     char	*scanname;
50 
51     if (preload_metadata == NULL)
52 	return(NULL);
53 
54     curp = preload_metadata;
55     for (;;) {
56 	hdr = (u_int32_t *)curp;
57 	if (hdr[0] == 0 && hdr[1] == 0)
58 	    break;
59 
60 	/*
61 	 * Search for a MODINFO_NAME field.  the boot loader really
62 	 * ought to strip the path names
63 	 */
64 	if (hdr[0] == MODINFO_NAME) {
65 	    scanname = curp + sizeof(u_int32_t) * 2;
66 	    i = strlen(scanname);
67 	    while (i > 0 && scanname[i-1] != '/')
68 		--i;
69 	    if (strcmp(name, scanname) == 0)
70 		return(curp);
71 	    if (strcmp(name, scanname + i) == 0)
72 		return(curp);
73 	}
74 	/* skip to next field */
75 	next = sizeof(u_int32_t) * 2 + hdr[1];
76 	next = roundup(next, sizeof(u_long));
77 	curp += next;
78     }
79     return(NULL);
80 }
81 
82 /*
83  * Search for the first preloaded module of (type)
84  */
85 caddr_t
86 preload_search_by_type(const char *type)
87 {
88     caddr_t	curp, lname;
89     u_int32_t	*hdr;
90     int		next;
91 
92     if (preload_metadata != NULL) {
93 
94 	curp = preload_metadata;
95 	lname = NULL;
96 	for (;;) {
97 	    hdr = (u_int32_t *)curp;
98 	    if (hdr[0] == 0 && hdr[1] == 0)
99 		break;
100 
101 	    /* remember the start of each record */
102 	    if (hdr[0] == MODINFO_NAME)
103 		lname = curp;
104 
105 	    /* Search for a MODINFO_TYPE field */
106 	    if ((hdr[0] == MODINFO_TYPE) &&
107 		!strcmp(type, curp + sizeof(u_int32_t) * 2))
108 		return(lname);
109 
110 	    /* skip to next field */
111 	    next = sizeof(u_int32_t) * 2 + hdr[1];
112 	    next = roundup(next, sizeof(u_long));
113 	    curp += next;
114 	}
115     }
116     return(NULL);
117 }
118 
119 /*
120  * Walk through the preloaded module list
121  */
122 caddr_t
123 preload_search_next_name(caddr_t base)
124 {
125     caddr_t	curp;
126     u_int32_t	*hdr;
127     int		next;
128 
129     if (preload_metadata != NULL) {
130 
131 	/* Pick up where we left off last time */
132 	if (base) {
133 	    /* skip to next field */
134 	    curp = base;
135 	    hdr = (u_int32_t *)curp;
136 	    next = sizeof(u_int32_t) * 2 + hdr[1];
137 	    next = roundup(next, sizeof(u_long));
138 	    curp += next;
139 	} else
140 	    curp = preload_metadata;
141 
142 	for (;;) {
143 	    hdr = (u_int32_t *)curp;
144 	    if (hdr[0] == 0 && hdr[1] == 0)
145 		break;
146 
147 	    /* Found a new record? */
148 	    if (hdr[0] == MODINFO_NAME)
149 		return curp;
150 
151 	    /* skip to next field */
152 	    next = sizeof(u_int32_t) * 2 + hdr[1];
153 	    next = roundup(next, sizeof(u_long));
154 	    curp += next;
155 	}
156     }
157     return(NULL);
158 }
159 
160 /*
161  * Given a preloaded module handle (mod), return a pointer
162  * to the data for the attribute (inf).
163  */
164 caddr_t
165 preload_search_info(caddr_t mod, int inf)
166 {
167     caddr_t	curp;
168     u_int32_t	*hdr;
169     u_int32_t	type = 0;
170     int		next;
171 
172     curp = mod;
173     for (;;) {
174 	hdr = (u_int32_t *)curp;
175 	/* end of module data? */
176 	if (hdr[0] == 0 && hdr[1] == 0)
177 	    break;
178 	/*
179 	 * We give up once we've looped back to what we were looking at
180 	 * first - this should normally be a MODINFO_NAME field.
181 	 */
182 	if (type == 0) {
183 	    type = hdr[0];
184 	} else {
185 	    if (hdr[0] == type)
186 		break;
187 	}
188 
189 	/*
190 	 * Attribute match? Return pointer to data.
191 	 * Consumer may safely assume that size value preceeds
192 	 * data.
193 	 */
194 	if (hdr[0] == inf)
195 	    return(curp + (sizeof(u_int32_t) * 2));
196 
197 	/* skip to next field */
198 	next = sizeof(u_int32_t) * 2 + hdr[1];
199 	next = roundup(next, sizeof(u_long));
200 	curp += next;
201     }
202     return(NULL);
203 }
204 
205 /*
206  * Delete a preload record by name.
207  *
208  * XXX we should really pass the base of the preloaded module here and not
209  * require rematching of the name.  If the wrong module (or no module) is
210  * deleted, the original preloaded module might be loaded again, causing it's
211  * data to be relocated twice.
212  */
213 void
214 preload_delete_name(const char *name)
215 {
216     caddr_t	curp;
217     u_int32_t	*hdr;
218     int		next;
219     int		clearing;
220     int		i;
221     char	*scanname;
222 
223     if (preload_metadata != NULL) {
224 	clearing = 0;
225 	curp = preload_metadata;
226 	for (;;) {
227 	    hdr = (u_int32_t *)curp;
228 	    if (hdr[0] == 0 && hdr[1] == 0)
229 		break;
230 
231 	    /* Search for a MODINFO_NAME field */
232 	    if (hdr[0] == MODINFO_NAME) {
233 		scanname = curp + sizeof(u_int32_t) * 2;
234 		i = strlen(scanname);
235 		while (i > 0 && scanname[i-1] != '/')
236 		    --i;
237 		if (strcmp(name, scanname) == 0)
238 		    clearing = 1;
239 		else if (strcmp(name, scanname + i) == 0)
240 		    clearing = 1;
241 		else
242 		    clearing = 0;	/* at next module now, stop clearing */
243 	    }
244 	    if (clearing)
245 		hdr[0] = MODINFO_EMPTY;
246 
247 	    /* skip to next field */
248 	    next = sizeof(u_int32_t) * 2 + hdr[1];
249 	    next = roundup(next, sizeof(u_long));
250 	    curp += next;
251 	}
252     }
253 }
254 
255 /* Called from hammer_time() on pc64.  Convert physical pointers to kvm. Sigh. */
256 void
257 preload_bootstrap_relocate(vm_offset_t offset)
258 {
259     caddr_t	curp;
260     u_int32_t	*hdr;
261     vm_offset_t	*ptr;
262     int		next;
263 
264     if (preload_metadata != NULL) {
265 
266 	curp = preload_metadata;
267 	for (;;) {
268 	    hdr = (u_int32_t *)curp;
269 	    if (hdr[0] == 0 && hdr[1] == 0)
270 		break;
271 
272 	    /* Deal with the ones that we know we have to fix */
273 	    switch (hdr[0]) {
274 	    case MODINFO_ADDR:
275 	    case MODINFO_METADATA|MODINFOMD_SSYM:
276 	    case MODINFO_METADATA|MODINFOMD_ESYM:
277 		ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
278 		*ptr += offset;
279 		break;
280 	    }
281 	    /* The rest is beyond us for now */
282 
283 	    /* skip to next field */
284 	    next = sizeof(u_int32_t) * 2 + hdr[1];
285 	    next = roundup(next, sizeof(u_long));
286 	    curp += next;
287 	}
288     }
289 }
290