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 * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32 #include <sys/sbuf.h>
33 #include <sys/sysctl.h>
34
35 #include <machine/metadata.h>
36
37 /*
38 * Preloaded module support
39 */
40
41 caddr_t preload_metadata;
42
43 /*
44 * Search for the preloaded module (name)
45 */
46 caddr_t
preload_search_by_name(const char * name)47 preload_search_by_name(const char *name)
48 {
49 caddr_t curp;
50 u_int32_t *hdr;
51 int next;
52 int i;
53 char *scanname;
54
55 if (preload_metadata == NULL)
56 return(NULL);
57
58 curp = preload_metadata;
59 for (;;) {
60 hdr = (u_int32_t *)curp;
61 if (hdr[0] == 0 && hdr[1] == 0)
62 break;
63
64 /*
65 * Search for a MODINFO_NAME field. the boot loader really
66 * ought to strip the path names
67 */
68 if (hdr[0] == MODINFO_NAME) {
69 scanname = curp + sizeof(u_int32_t) * 2;
70 i = strlen(scanname);
71 while (i > 0 && scanname[i-1] != '/')
72 --i;
73 if (strcmp(name, scanname) == 0)
74 return(curp);
75 if (strcmp(name, scanname + i) == 0)
76 return(curp);
77 }
78 /* skip to next field */
79 next = sizeof(u_int32_t) * 2 + hdr[1];
80 next = roundup(next, sizeof(u_long));
81 curp += next;
82 }
83 return(NULL);
84 }
85
86 /*
87 * Search for the first preloaded module of (type)
88 */
89 caddr_t
preload_search_by_type(const char * type)90 preload_search_by_type(const char *type)
91 {
92 caddr_t curp, lname;
93 u_int32_t *hdr;
94 int next;
95
96 if (preload_metadata != NULL) {
97
98 curp = preload_metadata;
99 lname = NULL;
100 for (;;) {
101 hdr = (u_int32_t *)curp;
102 if (hdr[0] == 0 && hdr[1] == 0)
103 break;
104
105 /* remember the start of each record */
106 if (hdr[0] == MODINFO_NAME)
107 lname = curp;
108
109 /* Search for a MODINFO_TYPE field */
110 if ((hdr[0] == MODINFO_TYPE) &&
111 !strcmp(type, curp + sizeof(u_int32_t) * 2))
112 return(lname);
113
114 /* skip to next field */
115 next = sizeof(u_int32_t) * 2 + hdr[1];
116 next = roundup(next, sizeof(u_long));
117 curp += next;
118 }
119 }
120 return(NULL);
121 }
122
123 /*
124 * Walk through the preloaded module list
125 */
126 caddr_t
preload_search_next_name(caddr_t base)127 preload_search_next_name(caddr_t base)
128 {
129 caddr_t curp;
130 u_int32_t *hdr;
131 int next;
132
133 if (preload_metadata != NULL) {
134
135 /* Pick up where we left off last time */
136 if (base) {
137 /* skip to next field */
138 curp = base;
139 hdr = (u_int32_t *)curp;
140 next = sizeof(u_int32_t) * 2 + hdr[1];
141 next = roundup(next, sizeof(u_long));
142 curp += next;
143 } else
144 curp = preload_metadata;
145
146 for (;;) {
147 hdr = (u_int32_t *)curp;
148 if (hdr[0] == 0 && hdr[1] == 0)
149 break;
150
151 /* Found a new record? */
152 if (hdr[0] == MODINFO_NAME)
153 return curp;
154
155 /* skip to next field */
156 next = sizeof(u_int32_t) * 2 + hdr[1];
157 next = roundup(next, sizeof(u_long));
158 curp += next;
159 }
160 }
161 return(NULL);
162 }
163
164 /*
165 * Given a preloaded module handle (mod), return a pointer
166 * to the data for the attribute (inf).
167 */
168 caddr_t
preload_search_info(caddr_t mod,int inf)169 preload_search_info(caddr_t mod, int inf)
170 {
171 caddr_t curp;
172 u_int32_t *hdr;
173 u_int32_t type = 0;
174 int next;
175
176 curp = mod;
177 for (;;) {
178 hdr = (u_int32_t *)curp;
179 /* end of module data? */
180 if (hdr[0] == 0 && hdr[1] == 0)
181 break;
182 /*
183 * We give up once we've looped back to what we were looking at
184 * first - this should normally be a MODINFO_NAME field.
185 */
186 if (type == 0) {
187 type = hdr[0];
188 } else {
189 if (hdr[0] == type)
190 break;
191 }
192
193 /*
194 * Attribute match? Return pointer to data.
195 * Consumer may safely assume that size value preceeds
196 * data.
197 */
198 if (hdr[0] == inf)
199 return(curp + (sizeof(u_int32_t) * 2));
200
201 /* skip to next field */
202 next = sizeof(u_int32_t) * 2 + hdr[1];
203 next = roundup(next, sizeof(u_long));
204 curp += next;
205 }
206 return(NULL);
207 }
208
209 /*
210 * Delete a preload record by path name.
211 */
212 void
preload_delete_name(const char * name)213 preload_delete_name(const char *name)
214 {
215 caddr_t curp;
216 u_int32_t *hdr;
217 int next;
218 int clearing;
219
220 if (preload_metadata != NULL) {
221 clearing = 0;
222 curp = preload_metadata;
223 for (;;) {
224 hdr = (u_int32_t *)curp;
225 if (hdr[0] == 0 && hdr[1] == 0)
226 break;
227
228 /* Search for a MODINFO_NAME field */
229 if (hdr[0] == MODINFO_NAME) {
230 if (strcmp(name, curp + sizeof(u_int32_t) * 2) == 0)
231 clearing = 1; /* start clearing */
232 else if (clearing)
233 clearing = 0; /* at next module now, stop clearing */
234 }
235 if (clearing)
236 hdr[0] = MODINFO_EMPTY;
237
238 /* skip to next field */
239 next = sizeof(u_int32_t) * 2 + hdr[1];
240 next = roundup(next, sizeof(u_long));
241 curp += next;
242 }
243 }
244 }
245
246 /* Called from hammer_time() on pc64. Convert physical pointers to kvm. Sigh. */
247 void
preload_bootstrap_relocate(vm_offset_t offset)248 preload_bootstrap_relocate(vm_offset_t offset)
249 {
250 caddr_t curp;
251 u_int32_t *hdr;
252 vm_offset_t *ptr;
253 int next;
254
255 if (preload_metadata != NULL) {
256
257 curp = preload_metadata;
258 for (;;) {
259 hdr = (u_int32_t *)curp;
260 if (hdr[0] == 0 && hdr[1] == 0)
261 break;
262
263 /* Deal with the ones that we know we have to fix */
264 switch (hdr[0]) {
265 case MODINFO_ADDR:
266 case MODINFO_METADATA|MODINFOMD_SSYM:
267 case MODINFO_METADATA|MODINFOMD_ESYM:
268 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
269 *ptr += offset;
270 break;
271 }
272 /* The rest is beyond us for now */
273
274 /* skip to next field */
275 next = sizeof(u_int32_t) * 2 + hdr[1];
276 next = roundup(next, sizeof(u_long));
277 curp += next;
278 }
279 }
280 }
281
282 /*
283 * Parse the modinfo type and append to the sbuf.
284 */
285 static void
preload_modinfo_type(struct sbuf * sbp,int type)286 preload_modinfo_type(struct sbuf *sbp, int type)
287 {
288 if ((type & MODINFO_METADATA) == 0) {
289 switch (type) {
290 case MODINFO_END:
291 sbuf_cat(sbp, "MODINFO_END");
292 break;
293 case MODINFO_NAME:
294 sbuf_cat(sbp, "MODINFO_NAME");
295 break;
296 case MODINFO_TYPE:
297 sbuf_cat(sbp, "MODINFO_TYPE");
298 break;
299 case MODINFO_ADDR:
300 sbuf_cat(sbp, "MODINFO_ADDR");
301 break;
302 case MODINFO_SIZE:
303 sbuf_cat(sbp, "MODINFO_SIZE");
304 break;
305 case MODINFO_EMPTY:
306 sbuf_cat(sbp, "MODINFO_EMPTY");
307 break;
308 case MODINFO_ARGS:
309 sbuf_cat(sbp, "MODINFO_ARGS");
310 break;
311 default:
312 sbuf_cat(sbp, "unrecognized modinfo attribute");
313 }
314
315 return;
316 }
317
318 sbuf_cat(sbp, "MODINFO_METADATA | ");
319 switch (type & ~MODINFO_METADATA) {
320 case MODINFOMD_ELFHDR:
321 sbuf_cat(sbp, "MODINFOMD_ELFHDR");
322 break;
323 case MODINFOMD_SSYM:
324 sbuf_cat(sbp, "MODINFOMD_SSYM");
325 break;
326 case MODINFOMD_ESYM:
327 sbuf_cat(sbp, "MODINFOMD_ESYM");
328 break;
329 case MODINFOMD_DYNAMIC:
330 sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
331 break;
332 case MODINFOMD_ENVP:
333 sbuf_cat(sbp, "MODINFOMD_ENVP");
334 break;
335 case MODINFOMD_HOWTO:
336 sbuf_cat(sbp, "MODINFOMD_HOWTO");
337 break;
338 case MODINFOMD_KERNEND:
339 sbuf_cat(sbp, "MODINFOMD_KERNEND");
340 break;
341 case MODINFOMD_SHDR:
342 sbuf_cat(sbp, "MODINFOMD_SHDR");
343 break;
344 case MODINFOMD_FW_HANDLE:
345 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
346 break;
347 case MODINFOMD_SMAP:
348 sbuf_cat(sbp, "MODINFOMD_SMAP");
349 break;
350 case MODINFOMD_EFI_MAP:
351 sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
352 break;
353 case MODINFOMD_EFI_FB:
354 sbuf_cat(sbp, "MODINFOMD_EFI_FB");
355 break;
356 default:
357 sbuf_cat(sbp, "unrecognized metadata type");
358 }
359 }
360
361 /*
362 * Print the modinfo value, depending on type.
363 */
364 static void
preload_modinfo_value(struct sbuf * sbp,uint32_t * bptr,int type,int len)365 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
366 {
367 switch (type) {
368 case MODINFO_NAME:
369 case MODINFO_TYPE:
370 case MODINFO_ARGS:
371 sbuf_printf(sbp, "%s", (char *)bptr);
372 break;
373 case MODINFO_SIZE:
374 sbuf_printf(sbp, "%lu", *(u_long *)bptr);
375 break;
376 case MODINFO_ADDR:
377 case MODINFO_METADATA | MODINFOMD_SSYM:
378 case MODINFO_METADATA | MODINFOMD_ESYM:
379 case MODINFO_METADATA | MODINFOMD_DYNAMIC:
380 case MODINFO_METADATA | MODINFOMD_KERNEND:
381 case MODINFO_METADATA | MODINFOMD_ENVP:
382 case MODINFO_METADATA | MODINFOMD_SMAP:
383 case MODINFO_METADATA | MODINFOMD_EFI_FB:
384 sbuf_printf(sbp, "0x%016lx", *(vm_offset_t *)bptr);
385 break;
386 case MODINFO_METADATA | MODINFOMD_HOWTO:
387 sbuf_printf(sbp, "0x%08x", *bptr);
388 break;
389 case MODINFO_METADATA | MODINFOMD_SHDR:
390 case MODINFO_METADATA | MODINFOMD_ELFHDR:
391 case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
392 case MODINFO_METADATA | MODINFOMD_EFI_MAP:
393 /* Don't print data buffers. */
394 sbuf_cat(sbp, "buffer contents omitted");
395 break;
396 default:
397 break;
398 }
399 }
400
401 static void
preload_dump_internal(struct sbuf * sbp)402 preload_dump_internal(struct sbuf *sbp)
403 {
404 uint32_t *bptr, type, len;
405
406 sbuf_putc(sbp, '\n');
407
408 /* Iterate through the TLV-encoded sections. */
409 bptr = (uint32_t *)preload_metadata;
410 while (bptr[0] != MODINFO_END) {
411 sbuf_printf(sbp, " %p:\n", bptr);
412
413 type = *bptr++;
414 sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
415 preload_modinfo_type(sbp, type);
416 sbuf_putc(sbp, '\n');
417
418 len = *bptr++;
419 sbuf_printf(sbp, "\tlen:\t%u\n", len);
420
421 sbuf_cat(sbp, "\tvalue:\t");
422 preload_modinfo_value(sbp, bptr, type, len);
423 sbuf_putc(sbp, '\n');
424
425 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
426 }
427 }
428
429 static int
sysctl_preload_dump(SYSCTL_HANDLER_ARGS)430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
431 {
432 struct sbuf sb;
433 int error;
434
435 if (preload_metadata == NULL)
436 return (EINVAL);
437
438 sbuf_new_for_sysctl(&sb, NULL, 512, req);
439 preload_dump_internal(&sb);
440
441 error = sbuf_finish(&sb);
442 sbuf_delete(&sb);
443
444 return (error);
445 }
446
447 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
448 CTLTYPE_STRING | CTLFLAG_RD,
449 NULL, 0, sysctl_preload_dump, "A",
450 "pretty-print the bootloader metadata");
451