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