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