xref: /freebsd/sys/kern/subr_module.c (revision 4b9d6057)
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_SSYM:
297 	    case MODINFO_METADATA|MODINFOMD_ESYM:
298 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
299 		*ptr += offset;
300 		break;
301 	    }
302 	    /* The rest is beyond us for now */
303 
304 	    /* skip to next field */
305 	    next = sizeof(uint32_t) * 2 + hdr[1];
306 	    next = roundup(next, sizeof(u_long));
307 	    curp += next;
308 	}
309     }
310 }
311 
312 /*
313  * Parse the modinfo type and append to the provided sbuf.
314  */
315 static void
316 preload_modinfo_type(struct sbuf *sbp, int type)
317 {
318 
319 	if ((type & MODINFO_METADATA) == 0) {
320 		switch (type) {
321 		case MODINFO_END:
322 			sbuf_cat(sbp, "MODINFO_END");
323 			break;
324 		case MODINFO_NAME:
325 			sbuf_cat(sbp, "MODINFO_NAME");
326 			break;
327 		case MODINFO_TYPE:
328 			sbuf_cat(sbp, "MODINFO_TYPE");
329 			break;
330 		case MODINFO_ADDR:
331 			sbuf_cat(sbp, "MODINFO_ADDR");
332 			break;
333 		case MODINFO_SIZE:
334 			sbuf_cat(sbp, "MODINFO_SIZE");
335 			break;
336 		case MODINFO_EMPTY:
337 			sbuf_cat(sbp, "MODINFO_EMPTY");
338 			break;
339 		case MODINFO_ARGS:
340 			sbuf_cat(sbp, "MODINFO_ARGS");
341 			break;
342 		default:
343 			sbuf_cat(sbp, "unrecognized modinfo attribute");
344 		}
345 
346 		return;
347 	}
348 
349 	sbuf_cat(sbp, "MODINFO_METADATA | ");
350 	switch (type & ~MODINFO_METADATA) {
351 	case MODINFOMD_ELFHDR:
352 		sbuf_cat(sbp, "MODINFOMD_ELFHDR");
353 		break;
354 	case MODINFOMD_SSYM:
355 		sbuf_cat(sbp, "MODINFOMD_SSYM");
356 		break;
357 	case MODINFOMD_ESYM:
358 		sbuf_cat(sbp, "MODINFOMD_ESYM");
359 		break;
360 	case MODINFOMD_DYNAMIC:
361 		sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
362 		break;
363 	case MODINFOMD_ENVP:
364 		sbuf_cat(sbp, "MODINFOMD_ENVP");
365 		break;
366 	case MODINFOMD_HOWTO:
367 		sbuf_cat(sbp, "MODINFOMD_HOWTO");
368 		break;
369 	case MODINFOMD_KERNEND:
370 		sbuf_cat(sbp, "MODINFOMD_KERNEND");
371 		break;
372 	case MODINFOMD_SHDR:
373 		sbuf_cat(sbp, "MODINFOMD_SHDR");
374 		break;
375 	case MODINFOMD_CTORS_ADDR:
376 		sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
377 		break;
378 	case MODINFOMD_CTORS_SIZE:
379 		sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
380 		break;
381 	case MODINFOMD_FW_HANDLE:
382 		sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
383 		break;
384 	case MODINFOMD_KEYBUF:
385 		sbuf_cat(sbp, "MODINFOMD_KEYBUF");
386 		break;
387 #ifdef MODINFOMD_SMAP
388 	case MODINFOMD_SMAP:
389 		sbuf_cat(sbp, "MODINFOMD_SMAP");
390 		break;
391 #endif
392 #ifdef MODINFOMD_SMAP_XATTR
393 	case MODINFOMD_SMAP_XATTR:
394 		sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
395 		break;
396 #endif
397 #ifdef MODINFOMD_DTBP
398 	case MODINFOMD_DTBP:
399 		sbuf_cat(sbp, "MODINFOMD_DTBP");
400 		break;
401 #endif
402 #ifdef MODINFOMD_EFI_MAP
403 	case MODINFOMD_EFI_MAP:
404 		sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
405 		break;
406 #endif
407 #ifdef MODINFOMD_EFI_FB
408 	case MODINFOMD_EFI_FB:
409 		sbuf_cat(sbp, "MODINFOMD_EFI_FB");
410 		break;
411 #endif
412 #ifdef MODINFOMD_MODULEP
413 	case MODINFOMD_MODULEP:
414 		sbuf_cat(sbp, "MODINFOMD_MODULEP");
415 		break;
416 #endif
417 #ifdef MODINFOMD_VBE_FB
418 	case MODINFOMD_VBE_FB:
419 		sbuf_cat(sbp, "MODINFOMD_VBE_FB");
420 		break;
421 #endif
422 #ifdef MODINFOMD_FONT
423 	case MODINFOMD_FONT:
424 		sbuf_cat(sbp, "MODINFOMD_FONT");
425 		break;
426 #endif
427 	default:
428 		sbuf_cat(sbp, "unrecognized metadata type");
429 	}
430 }
431 
432 /*
433  * Print the modinfo value, depending on type.
434  */
435 static void
436 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
437 {
438 #ifdef __LP64__
439 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
440 #else
441 #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
442 #endif
443 
444 	switch (type) {
445 	case MODINFO_NAME:
446 	case MODINFO_TYPE:
447 	case MODINFO_ARGS:
448 		sbuf_printf(sbp, "%s", (char *)bptr);
449 		break;
450 	case MODINFO_SIZE:
451 	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
452 		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
453 		break;
454 	case MODINFO_ADDR:
455 	case MODINFO_METADATA | MODINFOMD_SSYM:
456 	case MODINFO_METADATA | MODINFOMD_ESYM:
457 	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
458 	case MODINFO_METADATA | MODINFOMD_KERNEND:
459 	case MODINFO_METADATA | MODINFOMD_ENVP:
460 	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
461 #ifdef MODINFOMD_SMAP
462 	case MODINFO_METADATA | MODINFOMD_SMAP:
463 #endif
464 #ifdef MODINFOMD_SMAP_XATTR
465 	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
466 #endif
467 #ifdef MODINFOMD_DTBP
468 	case MODINFO_METADATA | MODINFOMD_DTBP:
469 #endif
470 #ifdef MODINFOMD_EFI_FB
471 	case MODINFO_METADATA | MODINFOMD_EFI_FB:
472 #endif
473 #ifdef MODINFOMD_VBE_FB
474 	case MODINFO_METADATA | MODINFOMD_VBE_FB:
475 #endif
476 #ifdef MODINFOMD_FONT
477 	case MODINFO_METADATA | MODINFOMD_FONT:
478 #endif
479 		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
480 		break;
481 	case MODINFO_METADATA | MODINFOMD_HOWTO:
482 		sbuf_printf(sbp, "0x%08x", *bptr);
483 		break;
484 	case MODINFO_METADATA | MODINFOMD_SHDR:
485 	case MODINFO_METADATA | MODINFOMD_ELFHDR:
486 	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
487 	case MODINFO_METADATA | MODINFOMD_KEYBUF:
488 #ifdef MODINFOMD_EFI_MAP
489 	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
490 #endif
491 		/* Don't print data buffers. */
492 		sbuf_cat(sbp, "buffer contents omitted");
493 		break;
494 	default:
495 		break;
496 	}
497 #undef sbuf_print_vmoffset
498 }
499 
500 static void
501 preload_dump_internal(struct sbuf *sbp)
502 {
503 	uint32_t *bptr, type, len;
504 
505 	KASSERT(preload_metadata != NULL,
506 	    ("%s called without setting up preload_metadata", __func__));
507 
508 	/*
509 	 * Iterate through the TLV-encoded sections.
510 	 */
511 	bptr = (uint32_t *)preload_metadata;
512 	sbuf_putc(sbp, '\n');
513 	while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) {
514 		sbuf_printf(sbp, " %p:\n", bptr);
515 		type = *bptr++;
516 		len = *bptr++;
517 
518 		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
519 		preload_modinfo_type(sbp, type);
520 		sbuf_putc(sbp, '\n');
521 		sbuf_printf(sbp, "\tlen:\t%u\n", len);
522 		sbuf_cat(sbp, "\tvalue:\t");
523 		preload_modinfo_value(sbp, bptr, type, len);
524 		sbuf_putc(sbp, '\n');
525 
526 		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
527 	}
528 }
529 
530 /*
531  * Print the preloaded data to the console. Called from the machine-dependent
532  * initialization routines, e.g. hammer_time().
533  */
534 void
535 preload_dump(void)
536 {
537 	char buf[512];
538 	struct sbuf sb;
539 
540 	/*
541 	 * This function is expected to be called before malloc is available,
542 	 * so use a static buffer and struct sbuf.
543 	 */
544 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
545 	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
546 	preload_dump_internal(&sb);
547 
548 	sbuf_finish(&sb);
549 	sbuf_delete(&sb);
550 }
551 
552 static int
553 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
554 {
555 	struct sbuf sb;
556 	int error;
557 
558 	if (preload_metadata == NULL)
559 		return (EINVAL);
560 
561 	sbuf_new_for_sysctl(&sb, NULL, 512, req);
562 	preload_dump_internal(&sb);
563 
564 	error = sbuf_finish(&sb);
565 	sbuf_delete(&sb);
566 
567 	return (error);
568 }
569 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
570     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
571     NULL, 0, sysctl_preload_dump, "A",
572     "pretty-print the bootloader metadata");
573