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