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