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