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: stable/11/sys/kern/subr_module.c 337262 2018-08-03 15:42:39Z markj $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/linker.h>
33
34#include <vm/vm.h>
35#include <vm/vm_extern.h>
36
37/*
38 * Preloaded module support
39 */
40
41vm_offset_t preload_addr_relocate = 0;
42caddr_t preload_metadata;
43
44/*
45 * Search for the preloaded module (name)
46 */
47caddr_t
48preload_search_by_name(const char *name)
49{
50    caddr_t	curp;
51    uint32_t	*hdr;
52    int		next;
53
54    if (preload_metadata != NULL) {
55
56	curp = preload_metadata;
57	for (;;) {
58	    hdr = (uint32_t *)curp;
59	    if (hdr[0] == 0 && hdr[1] == 0)
60		break;
61
62	    /* Search for a MODINFO_NAME field */
63	    if ((hdr[0] == MODINFO_NAME) &&
64		!strcmp(name, curp + sizeof(uint32_t) * 2))
65		return(curp);
66
67	    /* skip to next field */
68	    next = sizeof(uint32_t) * 2 + hdr[1];
69	    next = roundup(next, sizeof(u_long));
70	    curp += next;
71	}
72    }
73    return(NULL);
74}
75
76/*
77 * Search for the first preloaded module of (type)
78 */
79caddr_t
80preload_search_by_type(const char *type)
81{
82    caddr_t	curp, lname;
83    uint32_t	*hdr;
84    int		next;
85
86    if (preload_metadata != NULL) {
87
88	curp = preload_metadata;
89	lname = NULL;
90	for (;;) {
91	    hdr = (uint32_t *)curp;
92	    if (hdr[0] == 0 && hdr[1] == 0)
93		break;
94
95	    /* remember the start of each record */
96	    if (hdr[0] == MODINFO_NAME)
97		lname = curp;
98
99	    /* Search for a MODINFO_TYPE field */
100	    if ((hdr[0] == MODINFO_TYPE) &&
101		!strcmp(type, curp + sizeof(uint32_t) * 2))
102		return(lname);
103
104	    /* skip to next field */
105	    next = sizeof(uint32_t) * 2 + hdr[1];
106	    next = roundup(next, sizeof(u_long));
107	    curp += next;
108	}
109    }
110    return(NULL);
111}
112
113/*
114 * Walk through the preloaded module list
115 */
116caddr_t
117preload_search_next_name(caddr_t base)
118{
119    caddr_t	curp;
120    uint32_t	*hdr;
121    int		next;
122
123    if (preload_metadata != NULL) {
124
125	/* Pick up where we left off last time */
126	if (base) {
127	    /* skip to next field */
128	    curp = base;
129	    hdr = (uint32_t *)curp;
130	    next = sizeof(uint32_t) * 2 + hdr[1];
131	    next = roundup(next, sizeof(u_long));
132	    curp += next;
133	} else
134	    curp = preload_metadata;
135
136	for (;;) {
137	    hdr = (uint32_t *)curp;
138	    if (hdr[0] == 0 && hdr[1] == 0)
139		break;
140
141	    /* Found a new record? */
142	    if (hdr[0] == MODINFO_NAME)
143		return curp;
144
145	    /* skip to next field */
146	    next = sizeof(uint32_t) * 2 + hdr[1];
147	    next = roundup(next, sizeof(u_long));
148	    curp += next;
149	}
150    }
151    return(NULL);
152}
153
154/*
155 * Given a preloaded module handle (mod), return a pointer
156 * to the data for the attribute (inf).
157 */
158caddr_t
159preload_search_info(caddr_t mod, int inf)
160{
161    caddr_t	curp;
162    uint32_t	*hdr;
163    uint32_t	type = 0;
164    int		next;
165
166    if (mod == NULL)
167    	return (NULL);
168
169    curp = mod;
170    for (;;) {
171	hdr = (uint32_t *)curp;
172	/* end of module data? */
173	if (hdr[0] == 0 && hdr[1] == 0)
174	    break;
175	/*
176	 * We give up once we've looped back to what we were looking at
177	 * first - this should normally be a MODINFO_NAME field.
178	 */
179	if (type == 0) {
180	    type = hdr[0];
181	} else {
182	    if (hdr[0] == type)
183		break;
184	}
185
186	/*
187	 * Attribute match? Return pointer to data.
188	 * Consumer may safely assume that size value precedes
189	 * data.
190	 */
191	if (hdr[0] == inf)
192	    return(curp + (sizeof(uint32_t) * 2));
193
194	/* skip to next field */
195	next = sizeof(uint32_t) * 2 + hdr[1];
196	next = roundup(next, sizeof(u_long));
197	curp += next;
198    }
199    return(NULL);
200}
201
202/*
203 * Delete a preload record by name.
204 */
205void
206preload_delete_name(const char *name)
207{
208    caddr_t	addr, curp;
209    uint32_t	*hdr, sz;
210    int		next;
211    int		clearing;
212
213    addr = 0;
214    sz = 0;
215
216    if (preload_metadata != NULL) {
217
218	clearing = 0;
219	curp = preload_metadata;
220	for (;;) {
221	    hdr = (uint32_t *)curp;
222	    if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) {
223		/* Free memory used to store the file. */
224		if (addr != 0 && sz != 0)
225		    kmem_bootstrap_free((vm_offset_t)addr, sz);
226		addr = 0;
227		sz = 0;
228
229		if (hdr[0] == 0)
230		    break;
231		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
232		    clearing = 1;	/* got it, start clearing */
233		else if (clearing) {
234		    clearing = 0;	/* at next one now.. better stop */
235		}
236	    }
237	    if (clearing) {
238		if (hdr[0] == MODINFO_ADDR)
239		    addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2);
240		else if (hdr[0] == MODINFO_SIZE)
241		    sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2);
242		hdr[0] = MODINFO_EMPTY;
243	    }
244
245	    /* skip to next field */
246	    next = sizeof(uint32_t) * 2 + hdr[1];
247	    next = roundup(next, sizeof(u_long));
248	    curp += next;
249	}
250    }
251}
252
253void *
254preload_fetch_addr(caddr_t mod)
255{
256	caddr_t *mdp;
257
258	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
259	if (mdp == NULL)
260		return (NULL);
261	return (*mdp + preload_addr_relocate);
262}
263
264size_t
265preload_fetch_size(caddr_t mod)
266{
267	size_t *mdp;
268
269	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
270	if (mdp == NULL)
271		return (0);
272	return (*mdp);
273}
274
275/* Called from locore.  Convert physical pointers to kvm. Sigh. */
276void
277preload_bootstrap_relocate(vm_offset_t offset)
278{
279    caddr_t	curp;
280    uint32_t	*hdr;
281    vm_offset_t	*ptr;
282    int		next;
283
284    if (preload_metadata != NULL) {
285
286	curp = preload_metadata;
287	for (;;) {
288	    hdr = (uint32_t *)curp;
289	    if (hdr[0] == 0 && hdr[1] == 0)
290		break;
291
292	    /* Deal with the ones that we know we have to fix */
293	    switch (hdr[0]) {
294	    case MODINFO_ADDR:
295	    case MODINFO_METADATA|MODINFOMD_SSYM:
296	    case MODINFO_METADATA|MODINFOMD_ESYM:
297		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
298		*ptr += offset;
299		break;
300	    }
301	    /* The rest is beyond us for now */
302
303	    /* skip to next field */
304	    next = sizeof(uint32_t) * 2 + hdr[1];
305	    next = roundup(next, sizeof(u_long));
306	    curp += next;
307	}
308    }
309}
310