xref: /freebsd/sys/kern/subr_module.c (revision 60ae52f785331b48d1f4e82a9cf3f2d0da9540d5)
16ba9413bSMike Smith /*-
26ba9413bSMike Smith  * Copyright (c) 1998 Michael Smith
36ba9413bSMike Smith  * All rights reserved.
46ba9413bSMike Smith  *
56ba9413bSMike Smith  * Redistribution and use in source and binary forms, with or without
66ba9413bSMike Smith  * modification, are permitted provided that the following conditions
76ba9413bSMike Smith  * are met:
86ba9413bSMike Smith  * 1. Redistributions of source code must retain the above copyright
96ba9413bSMike Smith  *    notice, this list of conditions and the following disclaimer.
106ba9413bSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
116ba9413bSMike Smith  *    notice, this list of conditions and the following disclaimer in the
126ba9413bSMike Smith  *    documentation and/or other materials provided with the distribution.
136ba9413bSMike Smith  *
146ba9413bSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
156ba9413bSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
166ba9413bSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
176ba9413bSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
186ba9413bSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
196ba9413bSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
206ba9413bSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
216ba9413bSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
226ba9413bSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
236ba9413bSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
246ba9413bSMike Smith  * SUCH DAMAGE.
256ba9413bSMike Smith  */
266ba9413bSMike Smith 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
306ba9413bSMike Smith #include <sys/param.h>
316ba9413bSMike Smith #include <sys/systm.h>
326ba9413bSMike Smith #include <sys/linker.h>
336ba9413bSMike Smith 
346ba9413bSMike Smith /*
356ba9413bSMike Smith  * Preloaded module support
366ba9413bSMike Smith  */
376ba9413bSMike Smith 
38e4f1a52fSPeter Wemm caddr_t	preload_metadata;
396ba9413bSMike Smith 
406ba9413bSMike Smith /*
416ba9413bSMike Smith  * Search for the preloaded module (name)
426ba9413bSMike Smith  */
436ba9413bSMike Smith caddr_t
44e4f1a52fSPeter Wemm preload_search_by_name(const char *name)
456ba9413bSMike Smith {
466ba9413bSMike Smith     caddr_t	curp;
47*60ae52f7SEd Schouten     uint32_t	*hdr;
48e4f1a52fSPeter Wemm     int		next;
496ba9413bSMike Smith 
50e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
516ba9413bSMike Smith 
52e4f1a52fSPeter Wemm 	curp = preload_metadata;
536ba9413bSMike Smith 	for (;;) {
54*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
55e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
566ba9413bSMike Smith 		break;
576ba9413bSMike Smith 
586ba9413bSMike Smith 	    /* Search for a MODINFO_NAME field */
596ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_NAME) &&
60*60ae52f7SEd Schouten 		!strcmp(name, curp + sizeof(uint32_t) * 2))
616ba9413bSMike Smith 		return(curp);
626ba9413bSMike Smith 
636ba9413bSMike Smith 	    /* skip to next field */
64*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
652a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
66e4f1a52fSPeter Wemm 	    curp += next;
676ba9413bSMike Smith 	}
686ba9413bSMike Smith     }
696ba9413bSMike Smith     return(NULL);
706ba9413bSMike Smith }
716ba9413bSMike Smith 
726ba9413bSMike Smith /*
736ba9413bSMike Smith  * Search for the first preloaded module of (type)
746ba9413bSMike Smith  */
756ba9413bSMike Smith caddr_t
76e4f1a52fSPeter Wemm preload_search_by_type(const char *type)
776ba9413bSMike Smith {
786ba9413bSMike Smith     caddr_t	curp, lname;
79*60ae52f7SEd Schouten     uint32_t	*hdr;
80e4f1a52fSPeter Wemm     int		next;
816ba9413bSMike Smith 
82e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
836ba9413bSMike Smith 
84e4f1a52fSPeter Wemm 	curp = preload_metadata;
856ba9413bSMike Smith 	lname = NULL;
866ba9413bSMike Smith 	for (;;) {
87*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
88e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
896ba9413bSMike Smith 		break;
906ba9413bSMike Smith 
916ba9413bSMike Smith 	    /* remember the start of each record */
926ba9413bSMike Smith 	    if (hdr[0] == MODINFO_NAME)
936ba9413bSMike Smith 		lname = curp;
946ba9413bSMike Smith 
956ba9413bSMike Smith 	    /* Search for a MODINFO_TYPE field */
966ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_TYPE) &&
97*60ae52f7SEd Schouten 		!strcmp(type, curp + sizeof(uint32_t) * 2))
986ba9413bSMike Smith 		return(lname);
996ba9413bSMike Smith 
1006ba9413bSMike Smith 	    /* skip to next field */
101*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1022a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
103e4f1a52fSPeter Wemm 	    curp += next;
104e4f1a52fSPeter Wemm 	}
105e4f1a52fSPeter Wemm     }
106e4f1a52fSPeter Wemm     return(NULL);
107e4f1a52fSPeter Wemm }
108e4f1a52fSPeter Wemm 
109e4f1a52fSPeter Wemm /*
110e4f1a52fSPeter Wemm  * Walk through the preloaded module list
111e4f1a52fSPeter Wemm  */
112e4f1a52fSPeter Wemm caddr_t
113e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base)
114e4f1a52fSPeter Wemm {
115e4f1a52fSPeter Wemm     caddr_t	curp;
116*60ae52f7SEd Schouten     uint32_t	*hdr;
117e4f1a52fSPeter Wemm     int		next;
118e4f1a52fSPeter Wemm 
119e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
120e4f1a52fSPeter Wemm 
121e4f1a52fSPeter Wemm 	/* Pick up where we left off last time */
122e4f1a52fSPeter Wemm 	if (base) {
123e4f1a52fSPeter Wemm 	    /* skip to next field */
124e4f1a52fSPeter Wemm 	    curp = base;
125*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
126*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1272a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
128e4f1a52fSPeter Wemm 	    curp += next;
129e4f1a52fSPeter Wemm 	} else
130e4f1a52fSPeter Wemm 	    curp = preload_metadata;
131e4f1a52fSPeter Wemm 
132e4f1a52fSPeter Wemm 	for (;;) {
133*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
134e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
135e4f1a52fSPeter Wemm 		break;
136e4f1a52fSPeter Wemm 
137e4f1a52fSPeter Wemm 	    /* Found a new record? */
138e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME)
139e4f1a52fSPeter Wemm 		return curp;
140e4f1a52fSPeter Wemm 
141e4f1a52fSPeter Wemm 	    /* skip to next field */
142*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1432a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
144e4f1a52fSPeter Wemm 	    curp += next;
1456ba9413bSMike Smith 	}
1466ba9413bSMike Smith     }
1476ba9413bSMike Smith     return(NULL);
1486ba9413bSMike Smith }
1496ba9413bSMike Smith 
1506ba9413bSMike Smith /*
1516ba9413bSMike Smith  * Given a preloaded module handle (mod), return a pointer
1526ba9413bSMike Smith  * to the data for the attribute (inf).
1536ba9413bSMike Smith  */
1546ba9413bSMike Smith caddr_t
155e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf)
1566ba9413bSMike Smith {
1576ba9413bSMike Smith     caddr_t	curp;
158*60ae52f7SEd Schouten     uint32_t	*hdr;
159*60ae52f7SEd Schouten     uint32_t	type = 0;
160e4f1a52fSPeter Wemm     int		next;
1616ba9413bSMike Smith 
1626ba9413bSMike Smith     curp = mod;
1636ba9413bSMike Smith     for (;;) {
164*60ae52f7SEd Schouten 	hdr = (uint32_t *)curp;
1656ba9413bSMike Smith 	/* end of module data? */
166e4f1a52fSPeter Wemm 	if (hdr[0] == 0 && hdr[1] == 0)
1676ba9413bSMike Smith 	    break;
1686ba9413bSMike Smith 	/*
1696ba9413bSMike Smith 	 * We give up once we've looped back to what we were looking at
1706ba9413bSMike Smith 	 * first - this should normally be a MODINFO_NAME field.
1716ba9413bSMike Smith 	 */
1726ba9413bSMike Smith 	if (type == 0) {
1736ba9413bSMike Smith 	    type = hdr[0];
1746ba9413bSMike Smith 	} else {
1756ba9413bSMike Smith 	    if (hdr[0] == type)
1766ba9413bSMike Smith 		break;
1776ba9413bSMike Smith 	}
1786ba9413bSMike Smith 
1796ba9413bSMike Smith 	/*
1806ba9413bSMike Smith 	 * Attribute match? Return pointer to data.
181d7d97eb0SJeroen Ruigrok van der Werven 	 * Consumer may safely assume that size value precedes
1826ba9413bSMike Smith 	 * data.
1836ba9413bSMike Smith 	 */
1846ba9413bSMike Smith 	if (hdr[0] == inf)
185*60ae52f7SEd Schouten 	    return(curp + (sizeof(uint32_t) * 2));
1866ba9413bSMike Smith 
1876ba9413bSMike Smith 	/* skip to next field */
188*60ae52f7SEd Schouten 	next = sizeof(uint32_t) * 2 + hdr[1];
1892a26e9eaSPeter Wemm 	next = roundup(next, sizeof(u_long));
190e4f1a52fSPeter Wemm 	curp += next;
1916ba9413bSMike Smith     }
1926ba9413bSMike Smith     return(NULL);
1936ba9413bSMike Smith }
1946ba9413bSMike Smith 
195e4f1a52fSPeter Wemm /*
196e4f1a52fSPeter Wemm  * Delete a preload record by name.
197e4f1a52fSPeter Wemm  */
198e4f1a52fSPeter Wemm void
199e4f1a52fSPeter Wemm preload_delete_name(const char *name)
200e4f1a52fSPeter Wemm {
201e4f1a52fSPeter Wemm     caddr_t	curp;
202*60ae52f7SEd Schouten     uint32_t	*hdr;
203e4f1a52fSPeter Wemm     int		next;
204e4f1a52fSPeter Wemm     int		clearing;
205e4f1a52fSPeter Wemm 
206e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
207e4f1a52fSPeter Wemm 
208e4f1a52fSPeter Wemm 	clearing = 0;
209e4f1a52fSPeter Wemm 	curp = preload_metadata;
210e4f1a52fSPeter Wemm 	for (;;) {
211*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
212e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
213e4f1a52fSPeter Wemm 		break;
214e4f1a52fSPeter Wemm 
215e4f1a52fSPeter Wemm 	    /* Search for a MODINFO_NAME field */
216e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME) {
217*60ae52f7SEd Schouten 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
218e4f1a52fSPeter Wemm 		    clearing = 1;	/* got it, start clearing */
219e4f1a52fSPeter Wemm 		else if (clearing)
220e4f1a52fSPeter Wemm 		    clearing = 0;	/* at next one now.. better stop */
221e4f1a52fSPeter Wemm 	    }
222e4f1a52fSPeter Wemm 	    if (clearing)
223e4f1a52fSPeter Wemm 		hdr[0] = MODINFO_EMPTY;
224e4f1a52fSPeter Wemm 
225e4f1a52fSPeter Wemm 	    /* skip to next field */
226*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2272a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
228e4f1a52fSPeter Wemm 	    curp += next;
229e4f1a52fSPeter Wemm 	}
230e4f1a52fSPeter Wemm     }
231e4f1a52fSPeter Wemm }
232e4f1a52fSPeter Wemm 
233e4f1a52fSPeter Wemm /* Called from locore on i386.  Convert physical pointers to kvm. Sigh. */
234e4f1a52fSPeter Wemm void
235e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset)
236e4f1a52fSPeter Wemm {
237e4f1a52fSPeter Wemm     caddr_t	curp;
238*60ae52f7SEd Schouten     uint32_t	*hdr;
239e4f1a52fSPeter Wemm     vm_offset_t	*ptr;
240e4f1a52fSPeter Wemm     int		next;
241e4f1a52fSPeter Wemm 
242e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
243e4f1a52fSPeter Wemm 
244e4f1a52fSPeter Wemm 	curp = preload_metadata;
245e4f1a52fSPeter Wemm 	for (;;) {
246*60ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
247e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
248e4f1a52fSPeter Wemm 		break;
249e4f1a52fSPeter Wemm 
2502da2eeacSPeter Wemm 	    /* Deal with the ones that we know we have to fix */
2512da2eeacSPeter Wemm 	    switch (hdr[0]) {
2522da2eeacSPeter Wemm 	    case MODINFO_ADDR:
2532da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_SSYM:
2542da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_ESYM:
255*60ae52f7SEd Schouten 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
256e4f1a52fSPeter Wemm 		*ptr += offset;
2572da2eeacSPeter Wemm 		break;
258e4f1a52fSPeter Wemm 	    }
259e4f1a52fSPeter Wemm 	    /* The rest is beyond us for now */
260e4f1a52fSPeter Wemm 
261e4f1a52fSPeter Wemm 	    /* skip to next field */
262*60ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2632a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
264e4f1a52fSPeter Wemm 	    curp += next;
265e4f1a52fSPeter Wemm 	}
266e4f1a52fSPeter Wemm     }
267e4f1a52fSPeter Wemm }
268