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