xref: /freebsd/sys/kern/subr_module.c (revision e8234cfef67314987bb56bef07a4fbeb86a8e5d9)
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 
38278e7970SMarcel Moolenaar vm_offset_t preload_addr_relocate = 0;
39e4f1a52fSPeter Wemm caddr_t preload_metadata;
406ba9413bSMike Smith 
416ba9413bSMike Smith /*
426ba9413bSMike Smith  * Search for the preloaded module (name)
436ba9413bSMike Smith  */
446ba9413bSMike Smith caddr_t
45e4f1a52fSPeter Wemm preload_search_by_name(const char *name)
466ba9413bSMike Smith {
476ba9413bSMike Smith     caddr_t	curp;
4860ae52f7SEd Schouten     uint32_t	*hdr;
49e4f1a52fSPeter Wemm     int		next;
506ba9413bSMike Smith 
51e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
526ba9413bSMike Smith 
53e4f1a52fSPeter Wemm 	curp = preload_metadata;
546ba9413bSMike Smith 	for (;;) {
5560ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
56e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
576ba9413bSMike Smith 		break;
586ba9413bSMike Smith 
596ba9413bSMike Smith 	    /* Search for a MODINFO_NAME field */
606ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_NAME) &&
6160ae52f7SEd Schouten 		!strcmp(name, curp + sizeof(uint32_t) * 2))
626ba9413bSMike Smith 		return(curp);
636ba9413bSMike Smith 
646ba9413bSMike Smith 	    /* skip to next field */
6560ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
662a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
67e4f1a52fSPeter Wemm 	    curp += next;
686ba9413bSMike Smith 	}
696ba9413bSMike Smith     }
706ba9413bSMike Smith     return(NULL);
716ba9413bSMike Smith }
726ba9413bSMike Smith 
736ba9413bSMike Smith /*
746ba9413bSMike Smith  * Search for the first preloaded module of (type)
756ba9413bSMike Smith  */
766ba9413bSMike Smith caddr_t
77e4f1a52fSPeter Wemm preload_search_by_type(const char *type)
786ba9413bSMike Smith {
796ba9413bSMike Smith     caddr_t	curp, lname;
8060ae52f7SEd Schouten     uint32_t	*hdr;
81e4f1a52fSPeter Wemm     int		next;
826ba9413bSMike Smith 
83e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
846ba9413bSMike Smith 
85e4f1a52fSPeter Wemm 	curp = preload_metadata;
866ba9413bSMike Smith 	lname = NULL;
876ba9413bSMike Smith 	for (;;) {
8860ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
89e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
906ba9413bSMike Smith 		break;
916ba9413bSMike Smith 
926ba9413bSMike Smith 	    /* remember the start of each record */
936ba9413bSMike Smith 	    if (hdr[0] == MODINFO_NAME)
946ba9413bSMike Smith 		lname = curp;
956ba9413bSMike Smith 
966ba9413bSMike Smith 	    /* Search for a MODINFO_TYPE field */
976ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_TYPE) &&
9860ae52f7SEd Schouten 		!strcmp(type, curp + sizeof(uint32_t) * 2))
996ba9413bSMike Smith 		return(lname);
1006ba9413bSMike Smith 
1016ba9413bSMike Smith 	    /* skip to next field */
10260ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1032a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
104e4f1a52fSPeter Wemm 	    curp += next;
105e4f1a52fSPeter Wemm 	}
106e4f1a52fSPeter Wemm     }
107e4f1a52fSPeter Wemm     return(NULL);
108e4f1a52fSPeter Wemm }
109e4f1a52fSPeter Wemm 
110e4f1a52fSPeter Wemm /*
111e4f1a52fSPeter Wemm  * Walk through the preloaded module list
112e4f1a52fSPeter Wemm  */
113e4f1a52fSPeter Wemm caddr_t
114e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base)
115e4f1a52fSPeter Wemm {
116e4f1a52fSPeter Wemm     caddr_t	curp;
11760ae52f7SEd Schouten     uint32_t	*hdr;
118e4f1a52fSPeter Wemm     int		next;
119e4f1a52fSPeter Wemm 
120e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
121e4f1a52fSPeter Wemm 
122e4f1a52fSPeter Wemm 	/* Pick up where we left off last time */
123e4f1a52fSPeter Wemm 	if (base) {
124e4f1a52fSPeter Wemm 	    /* skip to next field */
125e4f1a52fSPeter Wemm 	    curp = base;
12660ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
12760ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1282a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
129e4f1a52fSPeter Wemm 	    curp += next;
130e4f1a52fSPeter Wemm 	} else
131e4f1a52fSPeter Wemm 	    curp = preload_metadata;
132e4f1a52fSPeter Wemm 
133e4f1a52fSPeter Wemm 	for (;;) {
13460ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
135e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
136e4f1a52fSPeter Wemm 		break;
137e4f1a52fSPeter Wemm 
138e4f1a52fSPeter Wemm 	    /* Found a new record? */
139e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME)
140e4f1a52fSPeter Wemm 		return curp;
141e4f1a52fSPeter Wemm 
142e4f1a52fSPeter Wemm 	    /* skip to next field */
14360ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1442a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
145e4f1a52fSPeter Wemm 	    curp += next;
1466ba9413bSMike Smith 	}
1476ba9413bSMike Smith     }
1486ba9413bSMike Smith     return(NULL);
1496ba9413bSMike Smith }
1506ba9413bSMike Smith 
1516ba9413bSMike Smith /*
1526ba9413bSMike Smith  * Given a preloaded module handle (mod), return a pointer
1536ba9413bSMike Smith  * to the data for the attribute (inf).
1546ba9413bSMike Smith  */
1556ba9413bSMike Smith caddr_t
156e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf)
1576ba9413bSMike Smith {
1586ba9413bSMike Smith     caddr_t	curp;
15960ae52f7SEd Schouten     uint32_t	*hdr;
16060ae52f7SEd Schouten     uint32_t	type = 0;
161e4f1a52fSPeter Wemm     int		next;
1626ba9413bSMike Smith 
163*e8234cfeSRoger Pau Monné     if (mod == NULL)
164*e8234cfeSRoger Pau Monné     	return (NULL);
165*e8234cfeSRoger Pau Monné 
1666ba9413bSMike Smith     curp = mod;
1676ba9413bSMike Smith     for (;;) {
16860ae52f7SEd Schouten 	hdr = (uint32_t *)curp;
1696ba9413bSMike Smith 	/* end of module data? */
170e4f1a52fSPeter Wemm 	if (hdr[0] == 0 && hdr[1] == 0)
1716ba9413bSMike Smith 	    break;
1726ba9413bSMike Smith 	/*
1736ba9413bSMike Smith 	 * We give up once we've looped back to what we were looking at
1746ba9413bSMike Smith 	 * first - this should normally be a MODINFO_NAME field.
1756ba9413bSMike Smith 	 */
1766ba9413bSMike Smith 	if (type == 0) {
1776ba9413bSMike Smith 	    type = hdr[0];
1786ba9413bSMike Smith 	} else {
1796ba9413bSMike Smith 	    if (hdr[0] == type)
1806ba9413bSMike Smith 		break;
1816ba9413bSMike Smith 	}
1826ba9413bSMike Smith 
1836ba9413bSMike Smith 	/*
1846ba9413bSMike Smith 	 * Attribute match? Return pointer to data.
185d7d97eb0SJeroen Ruigrok van der Werven 	 * Consumer may safely assume that size value precedes
1866ba9413bSMike Smith 	 * data.
1876ba9413bSMike Smith 	 */
1886ba9413bSMike Smith 	if (hdr[0] == inf)
18960ae52f7SEd Schouten 	    return(curp + (sizeof(uint32_t) * 2));
1906ba9413bSMike Smith 
1916ba9413bSMike Smith 	/* skip to next field */
19260ae52f7SEd Schouten 	next = sizeof(uint32_t) * 2 + hdr[1];
1932a26e9eaSPeter Wemm 	next = roundup(next, sizeof(u_long));
194e4f1a52fSPeter Wemm 	curp += next;
1956ba9413bSMike Smith     }
1966ba9413bSMike Smith     return(NULL);
1976ba9413bSMike Smith }
1986ba9413bSMike Smith 
199e4f1a52fSPeter Wemm /*
200e4f1a52fSPeter Wemm  * Delete a preload record by name.
201e4f1a52fSPeter Wemm  */
202e4f1a52fSPeter Wemm void
203e4f1a52fSPeter Wemm preload_delete_name(const char *name)
204e4f1a52fSPeter Wemm {
205e4f1a52fSPeter Wemm     caddr_t	curp;
20660ae52f7SEd Schouten     uint32_t	*hdr;
207e4f1a52fSPeter Wemm     int		next;
208e4f1a52fSPeter Wemm     int		clearing;
209e4f1a52fSPeter Wemm 
210e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
211e4f1a52fSPeter Wemm 
212e4f1a52fSPeter Wemm 	clearing = 0;
213e4f1a52fSPeter Wemm 	curp = preload_metadata;
214e4f1a52fSPeter Wemm 	for (;;) {
21560ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
216e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
217e4f1a52fSPeter Wemm 		break;
218e4f1a52fSPeter Wemm 
219e4f1a52fSPeter Wemm 	    /* Search for a MODINFO_NAME field */
220e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME) {
22160ae52f7SEd Schouten 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
222e4f1a52fSPeter Wemm 		    clearing = 1;	/* got it, start clearing */
223e4f1a52fSPeter Wemm 		else if (clearing)
224e4f1a52fSPeter Wemm 		    clearing = 0;	/* at next one now.. better stop */
225e4f1a52fSPeter Wemm 	    }
226e4f1a52fSPeter Wemm 	    if (clearing)
227e4f1a52fSPeter Wemm 		hdr[0] = MODINFO_EMPTY;
228e4f1a52fSPeter Wemm 
229e4f1a52fSPeter Wemm 	    /* skip to next field */
23060ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2312a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
232e4f1a52fSPeter Wemm 	    curp += next;
233e4f1a52fSPeter Wemm 	}
234e4f1a52fSPeter Wemm     }
235e4f1a52fSPeter Wemm }
236e4f1a52fSPeter Wemm 
237278e7970SMarcel Moolenaar void *
238278e7970SMarcel Moolenaar preload_fetch_addr(caddr_t mod)
239278e7970SMarcel Moolenaar {
240278e7970SMarcel Moolenaar 	caddr_t *mdp;
241278e7970SMarcel Moolenaar 
242278e7970SMarcel Moolenaar 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
243278e7970SMarcel Moolenaar 	if (mdp == NULL)
244278e7970SMarcel Moolenaar 		return (NULL);
245278e7970SMarcel Moolenaar 	return (*mdp + preload_addr_relocate);
246278e7970SMarcel Moolenaar }
247278e7970SMarcel Moolenaar 
248278e7970SMarcel Moolenaar size_t
249278e7970SMarcel Moolenaar preload_fetch_size(caddr_t mod)
250278e7970SMarcel Moolenaar {
251278e7970SMarcel Moolenaar 	size_t *mdp;
252278e7970SMarcel Moolenaar 
253278e7970SMarcel Moolenaar 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
254278e7970SMarcel Moolenaar 	if (mdp == NULL)
255278e7970SMarcel Moolenaar 		return (0);
256278e7970SMarcel Moolenaar 	return (*mdp);
257278e7970SMarcel Moolenaar }
258278e7970SMarcel Moolenaar 
25912d7eaa0SWarner Losh /* Called from locore.  Convert physical pointers to kvm. Sigh. */
260e4f1a52fSPeter Wemm void
261e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset)
262e4f1a52fSPeter Wemm {
263e4f1a52fSPeter Wemm     caddr_t	curp;
26460ae52f7SEd Schouten     uint32_t	*hdr;
265e4f1a52fSPeter Wemm     vm_offset_t	*ptr;
266e4f1a52fSPeter Wemm     int		next;
267e4f1a52fSPeter Wemm 
268e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
269e4f1a52fSPeter Wemm 
270e4f1a52fSPeter Wemm 	curp = preload_metadata;
271e4f1a52fSPeter Wemm 	for (;;) {
27260ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
273e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
274e4f1a52fSPeter Wemm 		break;
275e4f1a52fSPeter Wemm 
2762da2eeacSPeter Wemm 	    /* Deal with the ones that we know we have to fix */
2772da2eeacSPeter Wemm 	    switch (hdr[0]) {
2782da2eeacSPeter Wemm 	    case MODINFO_ADDR:
2792da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_SSYM:
2802da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_ESYM:
28160ae52f7SEd Schouten 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
282e4f1a52fSPeter Wemm 		*ptr += offset;
2832da2eeacSPeter Wemm 		break;
284e4f1a52fSPeter Wemm 	    }
285e4f1a52fSPeter Wemm 	    /* The rest is beyond us for now */
286e4f1a52fSPeter Wemm 
287e4f1a52fSPeter Wemm 	    /* skip to next field */
28860ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2892a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
290e4f1a52fSPeter Wemm 	    curp += next;
291e4f1a52fSPeter Wemm 	}
292e4f1a52fSPeter Wemm     }
293e4f1a52fSPeter Wemm }
294