xref: /freebsd/sys/kern/subr_module.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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     curp = mod;
164     for (;;) {
165 	hdr = (uint32_t *)curp;
166 	/* end of module data? */
167 	if (hdr[0] == 0 && hdr[1] == 0)
168 	    break;
169 	/*
170 	 * We give up once we've looped back to what we were looking at
171 	 * first - this should normally be a MODINFO_NAME field.
172 	 */
173 	if (type == 0) {
174 	    type = hdr[0];
175 	} else {
176 	    if (hdr[0] == type)
177 		break;
178 	}
179 
180 	/*
181 	 * Attribute match? Return pointer to data.
182 	 * Consumer may safely assume that size value precedes
183 	 * data.
184 	 */
185 	if (hdr[0] == inf)
186 	    return(curp + (sizeof(uint32_t) * 2));
187 
188 	/* skip to next field */
189 	next = sizeof(uint32_t) * 2 + hdr[1];
190 	next = roundup(next, sizeof(u_long));
191 	curp += next;
192     }
193     return(NULL);
194 }
195 
196 /*
197  * Delete a preload record by name.
198  */
199 void
200 preload_delete_name(const char *name)
201 {
202     caddr_t	curp;
203     uint32_t	*hdr;
204     int		next;
205     int		clearing;
206 
207     if (preload_metadata != NULL) {
208 
209 	clearing = 0;
210 	curp = preload_metadata;
211 	for (;;) {
212 	    hdr = (uint32_t *)curp;
213 	    if (hdr[0] == 0 && hdr[1] == 0)
214 		break;
215 
216 	    /* Search for a MODINFO_NAME field */
217 	    if (hdr[0] == MODINFO_NAME) {
218 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
219 		    clearing = 1;	/* got it, start clearing */
220 		else if (clearing)
221 		    clearing = 0;	/* at next one now.. better stop */
222 	    }
223 	    if (clearing)
224 		hdr[0] = MODINFO_EMPTY;
225 
226 	    /* skip to next field */
227 	    next = sizeof(uint32_t) * 2 + hdr[1];
228 	    next = roundup(next, sizeof(u_long));
229 	    curp += next;
230 	}
231     }
232 }
233 
234 void *
235 preload_fetch_addr(caddr_t mod)
236 {
237 	caddr_t *mdp;
238 
239 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
240 	if (mdp == NULL)
241 		return (NULL);
242 	return (*mdp + preload_addr_relocate);
243 }
244 
245 size_t
246 preload_fetch_size(caddr_t mod)
247 {
248 	size_t *mdp;
249 
250 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
251 	if (mdp == NULL)
252 		return (0);
253 	return (*mdp);
254 }
255 
256 /* Called from locore.  Convert physical pointers to kvm. Sigh. */
257 void
258 preload_bootstrap_relocate(vm_offset_t offset)
259 {
260     caddr_t	curp;
261     uint32_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 = (uint32_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(uint32_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(uint32_t) * 2 + hdr[1];
286 	    next = roundup(next, sizeof(u_long));
287 	    curp += next;
288 	}
289     }
290 }
291