xref: /freebsd/sys/kern/subr_module.c (revision 1f474190)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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_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
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 	default:
420 		sbuf_cat(sbp, "unrecognized metadata type");
421 	}
422 }
423 
424 /*
425  * Print the modinfo value, depending on type.
426  */
427 static void
428 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
429 {
430 #ifdef __LP64__
431 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
432 #else
433 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
434 #endif
435 
436 	switch (type) {
437 	case MODINFO_NAME:
438 	case MODINFO_TYPE:
439 	case MODINFO_ARGS:
440 		sbuf_printf(sbp, "%s", (char *)bptr);
441 		break;
442 	case MODINFO_SIZE:
443 	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
444 		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
445 		break;
446 	case MODINFO_ADDR:
447 	case MODINFO_METADATA | MODINFOMD_SSYM:
448 	case MODINFO_METADATA | MODINFOMD_ESYM:
449 	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
450 	case MODINFO_METADATA | MODINFOMD_KERNEND:
451 	case MODINFO_METADATA | MODINFOMD_ENVP:
452 	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
453 #ifdef MODINFOMD_SMAP
454 	case MODINFO_METADATA | MODINFOMD_SMAP:
455 #endif
456 #ifdef MODINFOMD_SMAP_XATTR
457 	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
458 #endif
459 #ifdef MODINFOMD_DTBP
460 	case MODINFO_METADATA | MODINFOMD_DTBP:
461 #endif
462 #ifdef MODINFOMD_EFI_FB
463 	case MODINFO_METADATA | MODINFOMD_EFI_FB:
464 #endif
465 		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
466 		break;
467 	case MODINFO_METADATA | MODINFOMD_HOWTO:
468 		sbuf_printf(sbp, "0x%08x", *bptr);
469 		break;
470 	case MODINFO_METADATA | MODINFOMD_SHDR:
471 	case MODINFO_METADATA | MODINFOMD_ELFHDR:
472 	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
473 	case MODINFO_METADATA | MODINFOMD_KEYBUF:
474 #ifdef MODINFOMD_EFI_MAP
475 	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
476 #endif
477 		/* Don't print data buffers. */
478 		sbuf_cat(sbp, "buffer contents omitted");
479 		break;
480 	default:
481 		break;
482 	}
483 #undef sbuf_print_vmoffset
484 }
485 
486 static void
487 preload_dump_internal(struct sbuf *sbp)
488 {
489 	uint32_t *bptr, type, len;
490 
491 	KASSERT(preload_metadata != NULL,
492 	    ("%s called without setting up preload_metadata", __func__));
493 
494 	/*
495 	 * Iterate through the TLV-encoded sections.
496 	 */
497 	bptr = (uint32_t *)preload_metadata;
498 	sbuf_putc(sbp, '\n');
499 	while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) {
500 		sbuf_printf(sbp, " %p:\n", bptr);
501 		type = *bptr++;
502 		len = *bptr++;
503 
504 		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
505 		preload_modinfo_type(sbp, type);
506 		sbuf_putc(sbp, '\n');
507 		sbuf_printf(sbp, "\tlen:\t%u\n", len);
508 		sbuf_cat(sbp, "\tvalue:\t");
509 		preload_modinfo_value(sbp, bptr, type, len);
510 		sbuf_putc(sbp, '\n');
511 
512 		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
513 	}
514 }
515 
516 /*
517  * Print the preloaded data to the console. Called from the machine-dependent
518  * initialization routines, e.g. hammer_time().
519  */
520 void
521 preload_dump(void)
522 {
523 	char buf[512];
524 	struct sbuf sb;
525 
526 	/*
527 	 * This function is expected to be called before malloc is available,
528 	 * so use a static buffer and struct sbuf.
529 	 */
530 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
531 	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
532 	preload_dump_internal(&sb);
533 
534 	sbuf_finish(&sb);
535 	sbuf_delete(&sb);
536 }
537 
538 static int
539 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
540 {
541 	struct sbuf sb;
542 	int error;
543 
544 	if (preload_metadata == NULL)
545 		return (EINVAL);
546 
547 	sbuf_new_for_sysctl(&sb, NULL, 512, req);
548 	preload_dump_internal(&sb);
549 
550 	error = sbuf_finish(&sb);
551 	sbuf_delete(&sb);
552 
553 	return (error);
554 }
555 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
556     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
557     NULL, 0, sysctl_preload_dump, "A",
558     "pretty-print the bootloader metadata");
559