xref: /freebsd/sys/kern/subr_module.c (revision 7937bfbc0ca53fe7cdd0d54414f9296e273a518e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1998 Michael Smith
5  * All rights reserved.
6  * Copyright (c) 2020 NetApp Inc.
7  * Copyright (c) 2020 Klara Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/linker.h>
34 #include <sys/sbuf.h>
35 #include <sys/sysctl.h>
36 
37 #include <machine/metadata.h>
38 
39 #include <vm/vm.h>
40 #include <vm/vm_extern.h>
41 
42 /*
43  * Preloaded module support
44  */
45 
46 vm_offset_t preload_addr_relocate = 0;
47 caddr_t preload_metadata;
48 
49 /*
50  * Search for the preloaded module (name)
51  */
52 caddr_t
53 preload_search_by_name(const char *name)
54 {
55     caddr_t	curp;
56     uint32_t	*hdr;
57     int		next;
58 
59     if (preload_metadata != NULL) {
60 	curp = preload_metadata;
61 	for (;;) {
62 	    hdr = (uint32_t *)curp;
63 	    if (hdr[0] == 0 && hdr[1] == 0)
64 		break;
65 
66 	    /* Search for a MODINFO_NAME field */
67 	    if ((hdr[0] == MODINFO_NAME) &&
68 		!strcmp(name, curp + sizeof(uint32_t) * 2))
69 		return(curp);
70 
71 	    /* skip to next field */
72 	    next = sizeof(uint32_t) * 2 + hdr[1];
73 	    next = roundup(next, sizeof(u_long));
74 	    curp += next;
75 	}
76     }
77     return(NULL);
78 }
79 
80 /*
81  * Search for the first preloaded module of (type)
82  */
83 caddr_t
84 preload_search_by_type(const char *type)
85 {
86     caddr_t	curp, lname;
87     uint32_t	*hdr;
88     int		next;
89 
90     if (preload_metadata != NULL) {
91 	curp = preload_metadata;
92 	lname = NULL;
93 	for (;;) {
94 	    hdr = (uint32_t *)curp;
95 	    if (hdr[0] == 0 && hdr[1] == 0)
96 		break;
97 
98 	    /* remember the start of each record */
99 	    if (hdr[0] == MODINFO_NAME)
100 		lname = curp;
101 
102 	    /* Search for a MODINFO_TYPE field */
103 	    if ((hdr[0] == MODINFO_TYPE) &&
104 		!strcmp(type, curp + sizeof(uint32_t) * 2))
105 		return(lname);
106 
107 	    /* skip to next field */
108 	    next = sizeof(uint32_t) * 2 + hdr[1];
109 	    next = roundup(next, sizeof(u_long));
110 	    curp += next;
111 	}
112     }
113     return(NULL);
114 }
115 
116 /*
117  * Walk through the preloaded module list
118  */
119 caddr_t
120 preload_search_next_name(caddr_t base)
121 {
122     caddr_t	curp;
123     uint32_t	*hdr;
124     int		next;
125 
126     if (preload_metadata != NULL) {
127 	/* Pick up where we left off last time */
128 	if (base) {
129 	    /* skip to next field */
130 	    curp = base;
131 	    hdr = (uint32_t *)curp;
132 	    next = sizeof(uint32_t) * 2 + hdr[1];
133 	    next = roundup(next, sizeof(u_long));
134 	    curp += next;
135 	} else
136 	    curp = preload_metadata;
137 
138 	for (;;) {
139 	    hdr = (uint32_t *)curp;
140 	    if (hdr[0] == 0 && hdr[1] == 0)
141 		break;
142 
143 	    /* Found a new record? */
144 	    if (hdr[0] == MODINFO_NAME)
145 		return curp;
146 
147 	    /* skip to next field */
148 	    next = sizeof(uint32_t) * 2 + hdr[1];
149 	    next = roundup(next, sizeof(u_long));
150 	    curp += next;
151 	}
152     }
153     return(NULL);
154 }
155 
156 /*
157  * Given a preloaded module handle (mod), return a pointer
158  * to the data for the attribute (inf).
159  */
160 caddr_t
161 preload_search_info(caddr_t mod, int inf)
162 {
163     caddr_t	curp;
164     uint32_t	*hdr;
165     uint32_t	type = 0;
166     int		next;
167 
168     if (mod == NULL)
169     	return (NULL);
170 
171     curp = mod;
172     for (;;) {
173 	hdr = (uint32_t *)curp;
174 	/* end of module data? */
175 	if (hdr[0] == 0 && hdr[1] == 0)
176 	    break;
177 	/*
178 	 * We give up once we've looped back to what we were looking at
179 	 * first - this should normally be a MODINFO_NAME field.
180 	 */
181 	if (type == 0) {
182 	    type = hdr[0];
183 	} else {
184 	    if (hdr[0] == type)
185 		break;
186 	}
187 
188 	/*
189 	 * Attribute match? Return pointer to data.
190 	 * Consumer may safely assume that size value precedes
191 	 * data.
192 	 */
193 	if (hdr[0] == inf)
194 	    return(curp + (sizeof(uint32_t) * 2));
195 
196 	/* skip to next field */
197 	next = sizeof(uint32_t) * 2 + hdr[1];
198 	next = roundup(next, sizeof(u_long));
199 	curp += next;
200     }
201     return(NULL);
202 }
203 
204 /*
205  * Delete a preload record by name.
206  */
207 void
208 preload_delete_name(const char *name)
209 {
210     caddr_t	addr, curp;
211     uint32_t	*hdr, sz;
212     int		next;
213     int		clearing;
214 
215     addr = 0;
216     sz = 0;
217 
218     if (preload_metadata != NULL) {
219 	clearing = 0;
220 	curp = preload_metadata;
221 	for (;;) {
222 	    hdr = (uint32_t *)curp;
223 	    if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) {
224 		/* Free memory used to store the file. */
225 		if (addr != 0 && sz != 0)
226 		    kmem_bootstrap_free((vm_offset_t)addr, sz);
227 		addr = 0;
228 		sz = 0;
229 
230 		if (hdr[0] == 0)
231 		    break;
232 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
233 		    clearing = 1;	/* got it, start clearing */
234 		else if (clearing) {
235 		    clearing = 0;	/* at next one now.. better stop */
236 		}
237 	    }
238 	    if (clearing) {
239 		if (hdr[0] == MODINFO_ADDR)
240 		    addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2);
241 		else if (hdr[0] == MODINFO_SIZE)
242 		    sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2);
243 		hdr[0] = MODINFO_EMPTY;
244 	    }
245 
246 	    /* skip to next field */
247 	    next = sizeof(uint32_t) * 2 + hdr[1];
248 	    next = roundup(next, sizeof(u_long));
249 	    curp += next;
250 	}
251     }
252 }
253 
254 void *
255 preload_fetch_addr(caddr_t mod)
256 {
257 	caddr_t *mdp;
258 
259 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
260 	if (mdp == NULL)
261 		return (NULL);
262 	return (*mdp + preload_addr_relocate);
263 }
264 
265 size_t
266 preload_fetch_size(caddr_t mod)
267 {
268 	size_t *mdp;
269 
270 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
271 	if (mdp == NULL)
272 		return (0);
273 	return (*mdp);
274 }
275 
276 /* Called from locore.  Convert physical pointers to kvm. Sigh. */
277 void
278 preload_bootstrap_relocate(vm_offset_t offset)
279 {
280     caddr_t	curp;
281     uint32_t	*hdr;
282     vm_offset_t	*ptr;
283     int		next;
284 
285     if (preload_metadata != NULL) {
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_FONT:
296 	    case MODINFO_METADATA|MODINFOMD_SPLASH:
297 	    case MODINFO_METADATA|MODINFOMD_SSYM:
298 	    case MODINFO_METADATA|MODINFOMD_ESYM:
299 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
300 		*ptr += offset;
301 		break;
302 	    }
303 	    /* The rest is beyond us for now */
304 
305 	    /* skip to next field */
306 	    next = sizeof(uint32_t) * 2 + hdr[1];
307 	    next = roundup(next, sizeof(u_long));
308 	    curp += next;
309 	}
310     }
311 }
312 
313 /*
314  * Parse the modinfo type and append to the provided sbuf.
315  */
316 static void
317 preload_modinfo_type(struct sbuf *sbp, int type)
318 {
319 
320 	if ((type & MODINFO_METADATA) == 0) {
321 		switch (type) {
322 		case MODINFO_END:
323 			sbuf_cat(sbp, "MODINFO_END");
324 			break;
325 		case MODINFO_NAME:
326 			sbuf_cat(sbp, "MODINFO_NAME");
327 			break;
328 		case MODINFO_TYPE:
329 			sbuf_cat(sbp, "MODINFO_TYPE");
330 			break;
331 		case MODINFO_ADDR:
332 			sbuf_cat(sbp, "MODINFO_ADDR");
333 			break;
334 		case MODINFO_SIZE:
335 			sbuf_cat(sbp, "MODINFO_SIZE");
336 			break;
337 		case MODINFO_EMPTY:
338 			sbuf_cat(sbp, "MODINFO_EMPTY");
339 			break;
340 		case MODINFO_ARGS:
341 			sbuf_cat(sbp, "MODINFO_ARGS");
342 			break;
343 		default:
344 			sbuf_cat(sbp, "unrecognized modinfo attribute");
345 		}
346 
347 		return;
348 	}
349 
350 	sbuf_cat(sbp, "MODINFO_METADATA | ");
351 	switch (type & ~MODINFO_METADATA) {
352 	case MODINFOMD_ELFHDR:
353 		sbuf_cat(sbp, "MODINFOMD_ELFHDR");
354 		break;
355 	case MODINFOMD_SSYM:
356 		sbuf_cat(sbp, "MODINFOMD_SSYM");
357 		break;
358 	case MODINFOMD_ESYM:
359 		sbuf_cat(sbp, "MODINFOMD_ESYM");
360 		break;
361 	case MODINFOMD_DYNAMIC:
362 		sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
363 		break;
364 	case MODINFOMD_ENVP:
365 		sbuf_cat(sbp, "MODINFOMD_ENVP");
366 		break;
367 	case MODINFOMD_HOWTO:
368 		sbuf_cat(sbp, "MODINFOMD_HOWTO");
369 		break;
370 	case MODINFOMD_KERNEND:
371 		sbuf_cat(sbp, "MODINFOMD_KERNEND");
372 		break;
373 	case MODINFOMD_SHDR:
374 		sbuf_cat(sbp, "MODINFOMD_SHDR");
375 		break;
376 	case MODINFOMD_CTORS_ADDR:
377 		sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
378 		break;
379 	case MODINFOMD_CTORS_SIZE:
380 		sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
381 		break;
382 	case MODINFOMD_FW_HANDLE:
383 		sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
384 		break;
385 	case MODINFOMD_KEYBUF:
386 		sbuf_cat(sbp, "MODINFOMD_KEYBUF");
387 		break;
388 #ifdef MODINFOMD_SMAP
389 	case MODINFOMD_SMAP:
390 		sbuf_cat(sbp, "MODINFOMD_SMAP");
391 		break;
392 #endif
393 #ifdef MODINFOMD_SMAP_XATTR
394 	case MODINFOMD_SMAP_XATTR:
395 		sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
396 		break;
397 #endif
398 #ifdef MODINFOMD_DTBP
399 	case MODINFOMD_DTBP:
400 		sbuf_cat(sbp, "MODINFOMD_DTBP");
401 		break;
402 #endif
403 #ifdef MODINFOMD_EFI_MAP
404 	case MODINFOMD_EFI_MAP:
405 		sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
406 		break;
407 #endif
408 #ifdef MODINFOMD_EFI_FB
409 	case MODINFOMD_EFI_FB:
410 		sbuf_cat(sbp, "MODINFOMD_EFI_FB");
411 		break;
412 #endif
413 #ifdef MODINFOMD_MODULEP
414 	case MODINFOMD_MODULEP:
415 		sbuf_cat(sbp, "MODINFOMD_MODULEP");
416 		break;
417 #endif
418 #ifdef MODINFOMD_VBE_FB
419 	case MODINFOMD_VBE_FB:
420 		sbuf_cat(sbp, "MODINFOMD_VBE_FB");
421 		break;
422 #endif
423 #ifdef MODINFOMD_FONT
424 	case MODINFOMD_FONT:
425 		sbuf_cat(sbp, "MODINFOMD_FONT");
426 		break;
427 #endif
428 #ifdef MODINFOMD_SPLASH
429 	case MODINFOMD_SPLASH:
430 		sbuf_cat(sbp, "MODINFOMD_SPLASH");
431 		break;
432 #endif
433 	default:
434 		sbuf_cat(sbp, "unrecognized metadata type");
435 	}
436 }
437 
438 /*
439  * Print the modinfo value, depending on type.
440  */
441 static void
442 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
443 {
444 #ifdef __LP64__
445 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
446 #else
447 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
448 #endif
449 
450 	switch (type) {
451 	case MODINFO_NAME:
452 	case MODINFO_TYPE:
453 	case MODINFO_ARGS:
454 		sbuf_printf(sbp, "%s", (char *)bptr);
455 		break;
456 	case MODINFO_SIZE:
457 	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
458 		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
459 		break;
460 	case MODINFO_ADDR:
461 	case MODINFO_METADATA | MODINFOMD_SSYM:
462 	case MODINFO_METADATA | MODINFOMD_ESYM:
463 	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
464 	case MODINFO_METADATA | MODINFOMD_KERNEND:
465 	case MODINFO_METADATA | MODINFOMD_ENVP:
466 	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
467 #ifdef MODINFOMD_SMAP
468 	case MODINFO_METADATA | MODINFOMD_SMAP:
469 #endif
470 #ifdef MODINFOMD_SMAP_XATTR
471 	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
472 #endif
473 #ifdef MODINFOMD_DTBP
474 	case MODINFO_METADATA | MODINFOMD_DTBP:
475 #endif
476 #ifdef MODINFOMD_EFI_FB
477 	case MODINFO_METADATA | MODINFOMD_EFI_FB:
478 #endif
479 #ifdef MODINFOMD_VBE_FB
480 	case MODINFO_METADATA | MODINFOMD_VBE_FB:
481 #endif
482 #ifdef MODINFOMD_FONT
483 	case MODINFO_METADATA | MODINFOMD_FONT:
484 #endif
485 #ifdef MODINFOMD_SPLASH
486 	case MODINFO_METADATA | MODINFOMD_SPLASH:
487 #endif
488 		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
489 		break;
490 	case MODINFO_METADATA | MODINFOMD_HOWTO:
491 		sbuf_printf(sbp, "0x%08x", *bptr);
492 		break;
493 	case MODINFO_METADATA | MODINFOMD_SHDR:
494 	case MODINFO_METADATA | MODINFOMD_ELFHDR:
495 	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
496 	case MODINFO_METADATA | MODINFOMD_KEYBUF:
497 #ifdef MODINFOMD_EFI_MAP
498 	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
499 #endif
500 		/* Don't print data buffers. */
501 		sbuf_cat(sbp, "buffer contents omitted");
502 		break;
503 	default:
504 		break;
505 	}
506 #undef sbuf_print_vmoffset
507 }
508 
509 static void
510 preload_dump_internal(struct sbuf *sbp)
511 {
512 	uint32_t *bptr, type, len;
513 
514 	KASSERT(preload_metadata != NULL,
515 	    ("%s called without setting up preload_metadata", __func__));
516 
517 	/*
518 	 * Iterate through the TLV-encoded sections.
519 	 */
520 	bptr = (uint32_t *)preload_metadata;
521 	sbuf_putc(sbp, '\n');
522 	while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) {
523 		sbuf_printf(sbp, " %p:\n", bptr);
524 		type = *bptr++;
525 		len = *bptr++;
526 
527 		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
528 		preload_modinfo_type(sbp, type);
529 		sbuf_putc(sbp, '\n');
530 		sbuf_printf(sbp, "\tlen:\t%u\n", len);
531 		sbuf_cat(sbp, "\tvalue:\t");
532 		preload_modinfo_value(sbp, bptr, type, len);
533 		sbuf_putc(sbp, '\n');
534 
535 		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
536 	}
537 }
538 
539 /*
540  * Print the preloaded data to the console. Called from the machine-dependent
541  * initialization routines, e.g. hammer_time().
542  */
543 void
544 preload_dump(void)
545 {
546 	char buf[512];
547 	struct sbuf sb;
548 
549 	/*
550 	 * This function is expected to be called before malloc is available,
551 	 * so use a static buffer and struct sbuf.
552 	 */
553 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
554 	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
555 	preload_dump_internal(&sb);
556 
557 	sbuf_finish(&sb);
558 	sbuf_delete(&sb);
559 }
560 
561 static int
562 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
563 {
564 	struct sbuf sb;
565 	int error;
566 
567 	if (preload_metadata == NULL)
568 		return (EINVAL);
569 
570 	sbuf_new_for_sysctl(&sb, NULL, 512, req);
571 	preload_dump_internal(&sb);
572 
573 	error = sbuf_finish(&sb);
574 	sbuf_delete(&sb);
575 
576 	return (error);
577 }
578 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
579     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
580     NULL, 0, sysctl_preload_dump, "A",
581     "pretty-print the bootloader metadata");
582