2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 1998 Michael Smith
6 * Copyright (c) 2020 NetApp Inc.
7 * Copyright (c) 2020 Klara Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/linker.h>
38 #include <sys/sysctl.h>
40 #include <machine/metadata.h>
43 #include <vm/vm_extern.h>
46 * Preloaded module support
49 vm_offset_t preload_addr_relocate = 0;
50 caddr_t preload_metadata;
53 * Search for the preloaded module (name)
56 preload_search_by_name(const char *name)
62 if (preload_metadata != NULL) {
63 curp = preload_metadata;
65 hdr = (uint32_t *)curp;
66 if (hdr[0] == 0 && hdr[1] == 0)
69 /* Search for a MODINFO_NAME field */
70 if ((hdr[0] == MODINFO_NAME) &&
71 !strcmp(name, curp + sizeof(uint32_t) * 2))
74 /* skip to next field */
75 next = sizeof(uint32_t) * 2 + hdr[1];
76 next = roundup(next, sizeof(u_long));
84 * Search for the first preloaded module of (type)
87 preload_search_by_type(const char *type)
93 if (preload_metadata != NULL) {
94 curp = preload_metadata;
97 hdr = (uint32_t *)curp;
98 if (hdr[0] == 0 && hdr[1] == 0)
101 /* remember the start of each record */
102 if (hdr[0] == MODINFO_NAME)
105 /* Search for a MODINFO_TYPE field */
106 if ((hdr[0] == MODINFO_TYPE) &&
107 !strcmp(type, curp + sizeof(uint32_t) * 2))
110 /* skip to next field */
111 next = sizeof(uint32_t) * 2 + hdr[1];
112 next = roundup(next, sizeof(u_long));
120 * Walk through the preloaded module list
123 preload_search_next_name(caddr_t base)
129 if (preload_metadata != NULL) {
130 /* Pick up where we left off last time */
132 /* skip to next field */
134 hdr = (uint32_t *)curp;
135 next = sizeof(uint32_t) * 2 + hdr[1];
136 next = roundup(next, sizeof(u_long));
139 curp = preload_metadata;
142 hdr = (uint32_t *)curp;
143 if (hdr[0] == 0 && hdr[1] == 0)
146 /* Found a new record? */
147 if (hdr[0] == MODINFO_NAME)
150 /* skip to next field */
151 next = sizeof(uint32_t) * 2 + hdr[1];
152 next = roundup(next, sizeof(u_long));
160 * Given a preloaded module handle (mod), return a pointer
161 * to the data for the attribute (inf).
164 preload_search_info(caddr_t mod, int inf)
176 hdr = (uint32_t *)curp;
177 /* end of module data? */
178 if (hdr[0] == 0 && hdr[1] == 0)
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.
192 * Attribute match? Return pointer to data.
193 * Consumer may safely assume that size value precedes
197 return(curp + (sizeof(uint32_t) * 2));
199 /* skip to next field */
200 next = sizeof(uint32_t) * 2 + hdr[1];
201 next = roundup(next, sizeof(u_long));
208 * Delete a preload record by name.
211 preload_delete_name(const char *name)
221 if (preload_metadata != NULL) {
223 curp = preload_metadata;
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);
235 if (!strcmp(name, curp + sizeof(uint32_t) * 2))
236 clearing = 1; /* got it, start clearing */
238 clearing = 0; /* at next one now.. better stop */
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;
249 /* skip to next field */
250 next = sizeof(uint32_t) * 2 + hdr[1];
251 next = roundup(next, sizeof(u_long));
258 preload_fetch_addr(caddr_t mod)
262 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
265 return (*mdp + preload_addr_relocate);
269 preload_fetch_size(caddr_t mod)
273 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
279 /* Called from locore. Convert physical pointers to kvm. Sigh. */
281 preload_bootstrap_relocate(vm_offset_t offset)
288 if (preload_metadata != NULL) {
289 curp = preload_metadata;
291 hdr = (uint32_t *)curp;
292 if (hdr[0] == 0 && hdr[1] == 0)
295 /* Deal with the ones that we know we have to fix */
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));
305 /* The rest is beyond us for now */
307 /* skip to next field */
308 next = sizeof(uint32_t) * 2 + hdr[1];
309 next = roundup(next, sizeof(u_long));
316 * Parse the modinfo type and append to the provided sbuf.
319 preload_modinfo_type(struct sbuf *sbp, int type)
322 if ((type & MODINFO_METADATA) == 0) {
325 sbuf_cat(sbp, "MODINFO_END");
328 sbuf_cat(sbp, "MODINFO_NAME");
331 sbuf_cat(sbp, "MODINFO_TYPE");
334 sbuf_cat(sbp, "MODINFO_ADDR");
337 sbuf_cat(sbp, "MODINFO_SIZE");
340 sbuf_cat(sbp, "MODINFO_EMPTY");
343 sbuf_cat(sbp, "MODINFO_ARGS");
346 sbuf_cat(sbp, "unrecognized modinfo attribute");
352 sbuf_cat(sbp, "MODINFO_METADATA | ");
353 switch (type & ~MODINFO_METADATA) {
354 case MODINFOMD_ELFHDR:
355 sbuf_cat(sbp, "MODINFOMD_ELFHDR");
358 sbuf_cat(sbp, "MODINFOMD_SSYM");
361 sbuf_cat(sbp, "MODINFOMD_ESYM");
363 case MODINFOMD_DYNAMIC:
364 sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
367 sbuf_cat(sbp, "MODINFOMD_ENVP");
369 case MODINFOMD_HOWTO:
370 sbuf_cat(sbp, "MODINFOMD_HOWTO");
372 case MODINFOMD_KERNEND:
373 sbuf_cat(sbp, "MODINFOMD_KERNEND");
376 sbuf_cat(sbp, "MODINFOMD_SHDR");
378 case MODINFOMD_CTORS_ADDR:
379 sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
381 case MODINFOMD_CTORS_SIZE:
382 sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
384 case MODINFOMD_FW_HANDLE:
385 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
387 case MODINFOMD_KEYBUF:
388 sbuf_cat(sbp, "MODINFOMD_KEYBUF");
390 #ifdef MODINFOMD_SMAP
392 sbuf_cat(sbp, "MODINFOMD_SMAP");
395 #ifdef MODINFOMD_SMAP_XATTR
396 case MODINFOMD_SMAP_XATTR:
397 sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
400 #ifdef MODINFOMD_DTBP
402 sbuf_cat(sbp, "MODINFOMD_DTBP");
405 #ifdef MODINFOMD_EFI_MAP
406 case MODINFOMD_EFI_MAP:
407 sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
410 #ifdef MODINFOMD_EFI_FB
411 case MODINFOMD_EFI_FB:
412 sbuf_cat(sbp, "MODINFOMD_EFI_FB");
415 #ifdef MODINFOMD_MODULEP
416 case MODINFOMD_MODULEP:
417 sbuf_cat(sbp, "MODINFOMD_MODULEP");
420 #ifdef MODINFOMD_VBE_FB
421 case MODINFOMD_VBE_FB:
422 sbuf_cat(sbp, "MODINFOMD_VBE_FB");
425 #ifdef MODINFOMD_FONT
427 sbuf_cat(sbp, "MODINFOMD_FONT");
431 sbuf_cat(sbp, "unrecognized metadata type");
436 * Print the modinfo value, depending on type.
439 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
442 #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%016lx", o);
444 #define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%08x", o);
451 sbuf_printf(sbp, "%s", (char *)bptr);
454 case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
455 sbuf_printf(sbp, "%lu", *(u_long *)bptr);
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:
467 #ifdef MODINFOMD_SMAP_XATTR
468 case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
470 #ifdef MODINFOMD_DTBP
471 case MODINFO_METADATA | MODINFOMD_DTBP:
473 #ifdef MODINFOMD_EFI_FB
474 case MODINFO_METADATA | MODINFOMD_EFI_FB:
476 #ifdef MODINFOMD_VBE_FB
477 case MODINFO_METADATA | MODINFOMD_VBE_FB:
479 #ifdef MODINFOMD_FONT
480 case MODINFO_METADATA | MODINFOMD_FONT:
482 sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
484 case MODINFO_METADATA | MODINFOMD_HOWTO:
485 sbuf_printf(sbp, "0x%08x", *bptr);
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:
494 /* Don't print data buffers. */
495 sbuf_cat(sbp, "buffer contents omitted");
500 #undef sbuf_print_vmoffset
504 preload_dump_internal(struct sbuf *sbp)
506 uint32_t *bptr, type, len;
508 KASSERT(preload_metadata != NULL,
509 ("%s called without setting up preload_metadata", __func__));
512 * Iterate through the TLV-encoded sections.
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);
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');
529 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
534 * Print the preloaded data to the console. Called from the machine-dependent
535 * initialization routines, e.g. hammer_time().
544 * This function is expected to be called before malloc is available,
545 * so use a static buffer and struct sbuf.
547 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
548 sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
549 preload_dump_internal(&sb);
556 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
561 if (preload_metadata == NULL)
564 sbuf_new_for_sysctl(&sb, NULL, 512, req);
565 preload_dump_internal(&sb);
567 error = sbuf_finish(&sb);
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");