xref: /freebsd/sys/kern/subr_module.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1998 Michael Smith
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/linker.h>
35 
36 /*
37  * Preloaded module support
38  */
39 
40 vm_offset_t preload_addr_relocate = 0;
41 caddr_t preload_metadata;
42 
43 /*
44  * Search for the preloaded module (name)
45  */
46 caddr_t
47 preload_search_by_name(const char *name)
48 {
49     caddr_t	curp;
50     uint32_t	*hdr;
51     int		next;
52 
53     if (preload_metadata != NULL) {
54 
55 	curp = preload_metadata;
56 	for (;;) {
57 	    hdr = (uint32_t *)curp;
58 	    if (hdr[0] == 0 && hdr[1] == 0)
59 		break;
60 
61 	    /* Search for a MODINFO_NAME field */
62 	    if ((hdr[0] == MODINFO_NAME) &&
63 		!strcmp(name, curp + sizeof(uint32_t) * 2))
64 		return(curp);
65 
66 	    /* skip to next field */
67 	    next = sizeof(uint32_t) * 2 + hdr[1];
68 	    next = roundup(next, sizeof(u_long));
69 	    curp += next;
70 	}
71     }
72     return(NULL);
73 }
74 
75 /*
76  * Search for the first preloaded module of (type)
77  */
78 caddr_t
79 preload_search_by_type(const char *type)
80 {
81     caddr_t	curp, lname;
82     uint32_t	*hdr;
83     int		next;
84 
85     if (preload_metadata != NULL) {
86 
87 	curp = preload_metadata;
88 	lname = NULL;
89 	for (;;) {
90 	    hdr = (uint32_t *)curp;
91 	    if (hdr[0] == 0 && hdr[1] == 0)
92 		break;
93 
94 	    /* remember the start of each record */
95 	    if (hdr[0] == MODINFO_NAME)
96 		lname = curp;
97 
98 	    /* Search for a MODINFO_TYPE field */
99 	    if ((hdr[0] == MODINFO_TYPE) &&
100 		!strcmp(type, curp + sizeof(uint32_t) * 2))
101 		return(lname);
102 
103 	    /* skip to next field */
104 	    next = sizeof(uint32_t) * 2 + hdr[1];
105 	    next = roundup(next, sizeof(u_long));
106 	    curp += next;
107 	}
108     }
109     return(NULL);
110 }
111 
112 /*
113  * Walk through the preloaded module list
114  */
115 caddr_t
116 preload_search_next_name(caddr_t base)
117 {
118     caddr_t	curp;
119     uint32_t	*hdr;
120     int		next;
121 
122     if (preload_metadata != NULL) {
123 
124 	/* Pick up where we left off last time */
125 	if (base) {
126 	    /* skip to next field */
127 	    curp = base;
128 	    hdr = (uint32_t *)curp;
129 	    next = sizeof(uint32_t) * 2 + hdr[1];
130 	    next = roundup(next, sizeof(u_long));
131 	    curp += next;
132 	} else
133 	    curp = preload_metadata;
134 
135 	for (;;) {
136 	    hdr = (uint32_t *)curp;
137 	    if (hdr[0] == 0 && hdr[1] == 0)
138 		break;
139 
140 	    /* Found a new record? */
141 	    if (hdr[0] == MODINFO_NAME)
142 		return curp;
143 
144 	    /* skip to next field */
145 	    next = sizeof(uint32_t) * 2 + hdr[1];
146 	    next = roundup(next, sizeof(u_long));
147 	    curp += next;
148 	}
149     }
150     return(NULL);
151 }
152 
153 /*
154  * Given a preloaded module handle (mod), return a pointer
155  * to the data for the attribute (inf).
156  */
157 caddr_t
158 preload_search_info(caddr_t mod, int inf)
159 {
160     caddr_t	curp;
161     uint32_t	*hdr;
162     uint32_t	type = 0;
163     int		next;
164 
165     if (mod == NULL)
166     	return (NULL);
167 
168     curp = mod;
169     for (;;) {
170 	hdr = (uint32_t *)curp;
171 	/* end of module data? */
172 	if (hdr[0] == 0 && hdr[1] == 0)
173 	    break;
174 	/*
175 	 * We give up once we've looped back to what we were looking at
176 	 * first - this should normally be a MODINFO_NAME field.
177 	 */
178 	if (type == 0) {
179 	    type = hdr[0];
180 	} else {
181 	    if (hdr[0] == type)
182 		break;
183 	}
184 
185 	/*
186 	 * Attribute match? Return pointer to data.
187 	 * Consumer may safely assume that size value precedes
188 	 * data.
189 	 */
190 	if (hdr[0] == inf)
191 	    return(curp + (sizeof(uint32_t) * 2));
192 
193 	/* skip to next field */
194 	next = sizeof(uint32_t) * 2 + hdr[1];
195 	next = roundup(next, sizeof(u_long));
196 	curp += next;
197     }
198     return(NULL);
199 }
200 
201 /*
202  * Delete a preload record by name.
203  */
204 void
205 preload_delete_name(const char *name)
206 {
207     caddr_t	curp;
208     uint32_t	*hdr;
209     int		next;
210     int		clearing;
211 
212     if (preload_metadata != NULL) {
213 
214 	clearing = 0;
215 	curp = preload_metadata;
216 	for (;;) {
217 	    hdr = (uint32_t *)curp;
218 	    if (hdr[0] == 0 && hdr[1] == 0)
219 		break;
220 
221 	    /* Search for a MODINFO_NAME field */
222 	    if (hdr[0] == MODINFO_NAME) {
223 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
224 		    clearing = 1;	/* got it, start clearing */
225 		else if (clearing)
226 		    clearing = 0;	/* at next one now.. better stop */
227 	    }
228 	    if (clearing)
229 		hdr[0] = MODINFO_EMPTY;
230 
231 	    /* skip to next field */
232 	    next = sizeof(uint32_t) * 2 + hdr[1];
233 	    next = roundup(next, sizeof(u_long));
234 	    curp += next;
235 	}
236     }
237 }
238 
239 void *
240 preload_fetch_addr(caddr_t mod)
241 {
242 	caddr_t *mdp;
243 
244 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
245 	if (mdp == NULL)
246 		return (NULL);
247 	return (*mdp + preload_addr_relocate);
248 }
249 
250 size_t
251 preload_fetch_size(caddr_t mod)
252 {
253 	size_t *mdp;
254 
255 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
256 	if (mdp == NULL)
257 		return (0);
258 	return (*mdp);
259 }
260 
261 /* Called from locore.  Convert physical pointers to kvm. Sigh. */
262 void
263 preload_bootstrap_relocate(vm_offset_t offset)
264 {
265     caddr_t	curp;
266     uint32_t	*hdr;
267     vm_offset_t	*ptr;
268     int		next;
269 
270     if (preload_metadata != NULL) {
271 
272 	curp = preload_metadata;
273 	for (;;) {
274 	    hdr = (uint32_t *)curp;
275 	    if (hdr[0] == 0 && hdr[1] == 0)
276 		break;
277 
278 	    /* Deal with the ones that we know we have to fix */
279 	    switch (hdr[0]) {
280 	    case MODINFO_ADDR:
281 	    case MODINFO_METADATA|MODINFOMD_SSYM:
282 	    case MODINFO_METADATA|MODINFOMD_ESYM:
283 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
284 		*ptr += offset;
285 		break;
286 	    }
287 	    /* The rest is beyond us for now */
288 
289 	    /* skip to next field */
290 	    next = sizeof(uint32_t) * 2 + hdr[1];
291 	    next = roundup(next, sizeof(u_long));
292 	    curp += next;
293 	}
294     }
295 }
296