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