xref: /freebsd/sys/kern/subr_module.c (revision b72ae900d4348118829fe04abdc11b620930c30f)
16ba9413bSMike Smith /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni  *
46ba9413bSMike Smith  * Copyright (c) 1998 Michael Smith
56ba9413bSMike Smith  * All rights reserved.
622e6a670SMitchell Horne  * Copyright (c) 2020 NetApp Inc.
722e6a670SMitchell Horne  * Copyright (c) 2020 Klara Inc.
86ba9413bSMike Smith  *
96ba9413bSMike Smith  * Redistribution and use in source and binary forms, with or without
106ba9413bSMike Smith  * modification, are permitted provided that the following conditions
116ba9413bSMike Smith  * are met:
126ba9413bSMike Smith  * 1. Redistributions of source code must retain the above copyright
136ba9413bSMike Smith  *    notice, this list of conditions and the following disclaimer.
146ba9413bSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
156ba9413bSMike Smith  *    notice, this list of conditions and the following disclaimer in the
166ba9413bSMike Smith  *    documentation and/or other materials provided with the distribution.
176ba9413bSMike Smith  *
186ba9413bSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
196ba9413bSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
206ba9413bSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
216ba9413bSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
226ba9413bSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
236ba9413bSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
246ba9413bSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256ba9413bSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
266ba9413bSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
276ba9413bSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
286ba9413bSMike Smith  * SUCH DAMAGE.
296ba9413bSMike Smith  */
306ba9413bSMike Smith 
316ba9413bSMike Smith #include <sys/param.h>
326ba9413bSMike Smith #include <sys/systm.h>
336ba9413bSMike Smith #include <sys/linker.h>
3422e6a670SMitchell Horne #include <sys/sbuf.h>
3522e6a670SMitchell Horne #include <sys/sysctl.h>
3622e6a670SMitchell Horne 
3722e6a670SMitchell Horne #include <machine/metadata.h>
386ba9413bSMike Smith 
39483f692eSMark Johnston #include <vm/vm.h>
40483f692eSMark Johnston #include <vm/vm_extern.h>
41483f692eSMark Johnston 
426ba9413bSMike Smith /*
436ba9413bSMike Smith  * Preloaded module support
446ba9413bSMike Smith  */
456ba9413bSMike Smith 
46278e7970SMarcel Moolenaar vm_offset_t preload_addr_relocate = 0;
47*b72ae900SAhmad Khalifa caddr_t preload_metadata, preload_kmdp;
48*b72ae900SAhmad Khalifa 
49*b72ae900SAhmad Khalifa void
50*b72ae900SAhmad Khalifa preload_initkmdp(bool fatal)
51*b72ae900SAhmad Khalifa {
52*b72ae900SAhmad Khalifa 	preload_kmdp = preload_search_by_type("elf kernel");
53*b72ae900SAhmad Khalifa 
54*b72ae900SAhmad Khalifa 	if (preload_kmdp == NULL && fatal)
55*b72ae900SAhmad Khalifa 		panic("unable to find kernel metadata");
56*b72ae900SAhmad Khalifa }
576ba9413bSMike Smith 
586ba9413bSMike Smith /*
596ba9413bSMike Smith  * Search for the preloaded module (name)
606ba9413bSMike Smith  */
616ba9413bSMike Smith caddr_t
62e4f1a52fSPeter Wemm preload_search_by_name(const char *name)
636ba9413bSMike Smith {
646ba9413bSMike Smith     caddr_t	curp;
6560ae52f7SEd Schouten     uint32_t	*hdr;
66e4f1a52fSPeter Wemm     int		next;
676ba9413bSMike Smith 
68e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
69e4f1a52fSPeter Wemm 	curp = preload_metadata;
706ba9413bSMike Smith 	for (;;) {
7160ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
72e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
736ba9413bSMike Smith 		break;
746ba9413bSMike Smith 
756ba9413bSMike Smith 	    /* Search for a MODINFO_NAME field */
766ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_NAME) &&
7760ae52f7SEd Schouten 		!strcmp(name, curp + sizeof(uint32_t) * 2))
786ba9413bSMike Smith 		return(curp);
796ba9413bSMike Smith 
806ba9413bSMike Smith 	    /* skip to next field */
8160ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
822a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
83e4f1a52fSPeter Wemm 	    curp += next;
846ba9413bSMike Smith 	}
856ba9413bSMike Smith     }
866ba9413bSMike Smith     return(NULL);
876ba9413bSMike Smith }
886ba9413bSMike Smith 
896ba9413bSMike Smith /*
906ba9413bSMike Smith  * Search for the first preloaded module of (type)
916ba9413bSMike Smith  */
926ba9413bSMike Smith caddr_t
93e4f1a52fSPeter Wemm preload_search_by_type(const char *type)
946ba9413bSMike Smith {
956ba9413bSMike Smith     caddr_t	curp, lname;
9660ae52f7SEd Schouten     uint32_t	*hdr;
97e4f1a52fSPeter Wemm     int		next;
986ba9413bSMike Smith 
99e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
100e4f1a52fSPeter Wemm 	curp = preload_metadata;
1016ba9413bSMike Smith 	lname = NULL;
1026ba9413bSMike Smith 	for (;;) {
10360ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
104e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
1056ba9413bSMike Smith 		break;
1066ba9413bSMike Smith 
1076ba9413bSMike Smith 	    /* remember the start of each record */
1086ba9413bSMike Smith 	    if (hdr[0] == MODINFO_NAME)
1096ba9413bSMike Smith 		lname = curp;
1106ba9413bSMike Smith 
1116ba9413bSMike Smith 	    /* Search for a MODINFO_TYPE field */
1126ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_TYPE) &&
11360ae52f7SEd Schouten 		!strcmp(type, curp + sizeof(uint32_t) * 2))
1146ba9413bSMike Smith 		return(lname);
1156ba9413bSMike Smith 
1166ba9413bSMike Smith 	    /* skip to next field */
11760ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1182a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
119e4f1a52fSPeter Wemm 	    curp += next;
120e4f1a52fSPeter Wemm 	}
121e4f1a52fSPeter Wemm     }
122e4f1a52fSPeter Wemm     return(NULL);
123e4f1a52fSPeter Wemm }
124e4f1a52fSPeter Wemm 
125e4f1a52fSPeter Wemm /*
126e4f1a52fSPeter Wemm  * Walk through the preloaded module list
127e4f1a52fSPeter Wemm  */
128e4f1a52fSPeter Wemm caddr_t
129e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base)
130e4f1a52fSPeter Wemm {
131e4f1a52fSPeter Wemm     caddr_t	curp;
13260ae52f7SEd Schouten     uint32_t	*hdr;
133e4f1a52fSPeter Wemm     int		next;
134e4f1a52fSPeter Wemm 
135e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
136e4f1a52fSPeter Wemm 	/* Pick up where we left off last time */
137e4f1a52fSPeter Wemm 	if (base) {
138e4f1a52fSPeter Wemm 	    /* skip to next field */
139e4f1a52fSPeter Wemm 	    curp = base;
14060ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
14160ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1422a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
143e4f1a52fSPeter Wemm 	    curp += next;
144e4f1a52fSPeter Wemm 	} else
145e4f1a52fSPeter Wemm 	    curp = preload_metadata;
146e4f1a52fSPeter Wemm 
147e4f1a52fSPeter Wemm 	for (;;) {
14860ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
149e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
150e4f1a52fSPeter Wemm 		break;
151e4f1a52fSPeter Wemm 
152e4f1a52fSPeter Wemm 	    /* Found a new record? */
153e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME)
154e4f1a52fSPeter Wemm 		return curp;
155e4f1a52fSPeter Wemm 
156e4f1a52fSPeter Wemm 	    /* skip to next field */
15760ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1582a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
159e4f1a52fSPeter Wemm 	    curp += next;
1606ba9413bSMike Smith 	}
1616ba9413bSMike Smith     }
1626ba9413bSMike Smith     return(NULL);
1636ba9413bSMike Smith }
1646ba9413bSMike Smith 
1656ba9413bSMike Smith /*
1666ba9413bSMike Smith  * Given a preloaded module handle (mod), return a pointer
1676ba9413bSMike Smith  * to the data for the attribute (inf).
1686ba9413bSMike Smith  */
1696ba9413bSMike Smith caddr_t
170e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf)
1716ba9413bSMike Smith {
1726ba9413bSMike Smith     caddr_t	curp;
17360ae52f7SEd Schouten     uint32_t	*hdr;
17460ae52f7SEd Schouten     uint32_t	type = 0;
175e4f1a52fSPeter Wemm     int		next;
1766ba9413bSMike Smith 
177e8234cfeSRoger Pau Monné     if (mod == NULL)
178e8234cfeSRoger Pau Monné     	return (NULL);
179e8234cfeSRoger Pau Monné 
1806ba9413bSMike Smith     curp = mod;
1816ba9413bSMike Smith     for (;;) {
18260ae52f7SEd Schouten 	hdr = (uint32_t *)curp;
1836ba9413bSMike Smith 	/* end of module data? */
184e4f1a52fSPeter Wemm 	if (hdr[0] == 0 && hdr[1] == 0)
1856ba9413bSMike Smith 	    break;
1866ba9413bSMike Smith 	/*
1876ba9413bSMike Smith 	 * We give up once we've looped back to what we were looking at
1886ba9413bSMike Smith 	 * first - this should normally be a MODINFO_NAME field.
1896ba9413bSMike Smith 	 */
1906ba9413bSMike Smith 	if (type == 0) {
1916ba9413bSMike Smith 	    type = hdr[0];
1926ba9413bSMike Smith 	} else {
1936ba9413bSMike Smith 	    if (hdr[0] == type)
1946ba9413bSMike Smith 		break;
1956ba9413bSMike Smith 	}
1966ba9413bSMike Smith 
1976ba9413bSMike Smith 	/*
1986ba9413bSMike Smith 	 * Attribute match? Return pointer to data.
199d7d97eb0SJeroen Ruigrok van der Werven 	 * Consumer may safely assume that size value precedes
2006ba9413bSMike Smith 	 * data.
2016ba9413bSMike Smith 	 */
2026ba9413bSMike Smith 	if (hdr[0] == inf)
20360ae52f7SEd Schouten 	    return(curp + (sizeof(uint32_t) * 2));
2046ba9413bSMike Smith 
2056ba9413bSMike Smith 	/* skip to next field */
20660ae52f7SEd Schouten 	next = sizeof(uint32_t) * 2 + hdr[1];
2072a26e9eaSPeter Wemm 	next = roundup(next, sizeof(u_long));
208e4f1a52fSPeter Wemm 	curp += next;
2096ba9413bSMike Smith     }
2106ba9413bSMike Smith     return(NULL);
2116ba9413bSMike Smith }
2126ba9413bSMike Smith 
213e4f1a52fSPeter Wemm /*
214e4f1a52fSPeter Wemm  * Delete a preload record by name.
215e4f1a52fSPeter Wemm  */
216e4f1a52fSPeter Wemm void
217e4f1a52fSPeter Wemm preload_delete_name(const char *name)
218e4f1a52fSPeter Wemm {
219483f692eSMark Johnston     caddr_t	addr, curp;
220483f692eSMark Johnston     uint32_t	*hdr, sz;
221e4f1a52fSPeter Wemm     int		next;
222e4f1a52fSPeter Wemm     int		clearing;
223e4f1a52fSPeter Wemm 
224483f692eSMark Johnston     addr = 0;
225483f692eSMark Johnston     sz = 0;
226483f692eSMark Johnston 
227e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
228e4f1a52fSPeter Wemm 	clearing = 0;
229e4f1a52fSPeter Wemm 	curp = preload_metadata;
230e4f1a52fSPeter Wemm 	for (;;) {
23160ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
232483f692eSMark Johnston 	    if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) {
233483f692eSMark Johnston 		/* Free memory used to store the file. */
234483f692eSMark Johnston 		if (addr != 0 && sz != 0)
235483f692eSMark Johnston 		    kmem_bootstrap_free((vm_offset_t)addr, sz);
236483f692eSMark Johnston 		addr = 0;
237483f692eSMark Johnston 		sz = 0;
238e4f1a52fSPeter Wemm 
239483f692eSMark Johnston 		if (hdr[0] == 0)
240483f692eSMark Johnston 		    break;
24160ae52f7SEd Schouten 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
242e4f1a52fSPeter Wemm 		    clearing = 1;	/* got it, start clearing */
243483f692eSMark Johnston 		else if (clearing) {
244e4f1a52fSPeter Wemm 		    clearing = 0;	/* at next one now.. better stop */
245e4f1a52fSPeter Wemm 		}
246483f692eSMark Johnston 	    }
247483f692eSMark Johnston 	    if (clearing) {
248483f692eSMark Johnston 		if (hdr[0] == MODINFO_ADDR)
249483f692eSMark Johnston 		    addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2);
250483f692eSMark Johnston 		else if (hdr[0] == MODINFO_SIZE)
251483f692eSMark Johnston 		    sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2);
252e4f1a52fSPeter Wemm 		hdr[0] = MODINFO_EMPTY;
253483f692eSMark Johnston 	    }
254e4f1a52fSPeter Wemm 
255e4f1a52fSPeter Wemm 	    /* skip to next field */
25660ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2572a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
258e4f1a52fSPeter Wemm 	    curp += next;
259e4f1a52fSPeter Wemm 	}
260e4f1a52fSPeter Wemm     }
261e4f1a52fSPeter Wemm }
262e4f1a52fSPeter Wemm 
263278e7970SMarcel Moolenaar void *
264278e7970SMarcel Moolenaar preload_fetch_addr(caddr_t mod)
265278e7970SMarcel Moolenaar {
266278e7970SMarcel Moolenaar 	caddr_t *mdp;
267278e7970SMarcel Moolenaar 
268278e7970SMarcel Moolenaar 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
269278e7970SMarcel Moolenaar 	if (mdp == NULL)
270278e7970SMarcel Moolenaar 		return (NULL);
271278e7970SMarcel Moolenaar 	return (*mdp + preload_addr_relocate);
272278e7970SMarcel Moolenaar }
273278e7970SMarcel Moolenaar 
274278e7970SMarcel Moolenaar size_t
275278e7970SMarcel Moolenaar preload_fetch_size(caddr_t mod)
276278e7970SMarcel Moolenaar {
277278e7970SMarcel Moolenaar 	size_t *mdp;
278278e7970SMarcel Moolenaar 
279278e7970SMarcel Moolenaar 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
280278e7970SMarcel Moolenaar 	if (mdp == NULL)
281278e7970SMarcel Moolenaar 		return (0);
282278e7970SMarcel Moolenaar 	return (*mdp);
283278e7970SMarcel Moolenaar }
284278e7970SMarcel Moolenaar 
28512d7eaa0SWarner Losh /* Called from locore.  Convert physical pointers to kvm. Sigh. */
286e4f1a52fSPeter Wemm void
287e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset)
288e4f1a52fSPeter Wemm {
289e4f1a52fSPeter Wemm     caddr_t	curp;
29060ae52f7SEd Schouten     uint32_t	*hdr;
291e4f1a52fSPeter Wemm     vm_offset_t	*ptr;
292e4f1a52fSPeter Wemm     int		next;
293e4f1a52fSPeter Wemm 
294e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
295e4f1a52fSPeter Wemm 	curp = preload_metadata;
296e4f1a52fSPeter Wemm 	for (;;) {
29760ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
298e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
299e4f1a52fSPeter Wemm 		break;
300e4f1a52fSPeter Wemm 
3012da2eeacSPeter Wemm 	    /* Deal with the ones that we know we have to fix */
3022da2eeacSPeter Wemm 	    switch (hdr[0]) {
3032da2eeacSPeter Wemm 	    case MODINFO_ADDR:
30493b18e37SToomas Soome 	    case MODINFO_METADATA|MODINFOMD_FONT:
305966e53a4SEmmanuel Vadot 	    case MODINFO_METADATA|MODINFOMD_SPLASH:
3062da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_SSYM:
3072da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_ESYM:
30860ae52f7SEd Schouten 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
309e4f1a52fSPeter Wemm 		*ptr += offset;
3102da2eeacSPeter Wemm 		break;
311e4f1a52fSPeter Wemm 	    }
312e4f1a52fSPeter Wemm 	    /* The rest is beyond us for now */
313e4f1a52fSPeter Wemm 
314e4f1a52fSPeter Wemm 	    /* skip to next field */
31560ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
3162a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
317e4f1a52fSPeter Wemm 	    curp += next;
318e4f1a52fSPeter Wemm 	}
319e4f1a52fSPeter Wemm     }
320e4f1a52fSPeter Wemm }
32122e6a670SMitchell Horne 
32222e6a670SMitchell Horne /*
32322e6a670SMitchell Horne  * Parse the modinfo type and append to the provided sbuf.
32422e6a670SMitchell Horne  */
32522e6a670SMitchell Horne static void
32622e6a670SMitchell Horne preload_modinfo_type(struct sbuf *sbp, int type)
32722e6a670SMitchell Horne {
32822e6a670SMitchell Horne 
32922e6a670SMitchell Horne 	if ((type & MODINFO_METADATA) == 0) {
33022e6a670SMitchell Horne 		switch (type) {
33122e6a670SMitchell Horne 		case MODINFO_END:
33222e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_END");
33322e6a670SMitchell Horne 			break;
33422e6a670SMitchell Horne 		case MODINFO_NAME:
33522e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_NAME");
33622e6a670SMitchell Horne 			break;
33722e6a670SMitchell Horne 		case MODINFO_TYPE:
33822e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_TYPE");
33922e6a670SMitchell Horne 			break;
34022e6a670SMitchell Horne 		case MODINFO_ADDR:
34122e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_ADDR");
34222e6a670SMitchell Horne 			break;
34322e6a670SMitchell Horne 		case MODINFO_SIZE:
34422e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_SIZE");
34522e6a670SMitchell Horne 			break;
34622e6a670SMitchell Horne 		case MODINFO_EMPTY:
34722e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_EMPTY");
34822e6a670SMitchell Horne 			break;
34922e6a670SMitchell Horne 		case MODINFO_ARGS:
35022e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_ARGS");
35122e6a670SMitchell Horne 			break;
35222e6a670SMitchell Horne 		default:
35322e6a670SMitchell Horne 			sbuf_cat(sbp, "unrecognized modinfo attribute");
35422e6a670SMitchell Horne 		}
35522e6a670SMitchell Horne 
35622e6a670SMitchell Horne 		return;
35722e6a670SMitchell Horne 	}
35822e6a670SMitchell Horne 
35922e6a670SMitchell Horne 	sbuf_cat(sbp, "MODINFO_METADATA | ");
36022e6a670SMitchell Horne 	switch (type & ~MODINFO_METADATA) {
36122e6a670SMitchell Horne 	case MODINFOMD_ELFHDR:
36222e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ELFHDR");
36322e6a670SMitchell Horne 		break;
36422e6a670SMitchell Horne 	case MODINFOMD_SSYM:
36522e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SSYM");
36622e6a670SMitchell Horne 		break;
36722e6a670SMitchell Horne 	case MODINFOMD_ESYM:
36822e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ESYM");
36922e6a670SMitchell Horne 		break;
37022e6a670SMitchell Horne 	case MODINFOMD_DYNAMIC:
37122e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
37222e6a670SMitchell Horne 		break;
37322e6a670SMitchell Horne 	case MODINFOMD_ENVP:
37422e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ENVP");
37522e6a670SMitchell Horne 		break;
37622e6a670SMitchell Horne 	case MODINFOMD_HOWTO:
37722e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_HOWTO");
37822e6a670SMitchell Horne 		break;
37922e6a670SMitchell Horne 	case MODINFOMD_KERNEND:
38022e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_KERNEND");
38122e6a670SMitchell Horne 		break;
38222e6a670SMitchell Horne 	case MODINFOMD_SHDR:
38322e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SHDR");
38422e6a670SMitchell Horne 		break;
38522e6a670SMitchell Horne 	case MODINFOMD_CTORS_ADDR:
38622e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
38722e6a670SMitchell Horne 		break;
38822e6a670SMitchell Horne 	case MODINFOMD_CTORS_SIZE:
38922e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
39022e6a670SMitchell Horne 		break;
39122e6a670SMitchell Horne 	case MODINFOMD_FW_HANDLE:
39222e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
39322e6a670SMitchell Horne 		break;
39422e6a670SMitchell Horne 	case MODINFOMD_KEYBUF:
39522e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_KEYBUF");
39622e6a670SMitchell Horne 		break;
39722e6a670SMitchell Horne #ifdef MODINFOMD_SMAP
39822e6a670SMitchell Horne 	case MODINFOMD_SMAP:
39922e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SMAP");
40022e6a670SMitchell Horne 		break;
40122e6a670SMitchell Horne #endif
40222e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR
40322e6a670SMitchell Horne 	case MODINFOMD_SMAP_XATTR:
40422e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
40522e6a670SMitchell Horne 		break;
40622e6a670SMitchell Horne #endif
40722e6a670SMitchell Horne #ifdef MODINFOMD_DTBP
40822e6a670SMitchell Horne 	case MODINFOMD_DTBP:
40922e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_DTBP");
41022e6a670SMitchell Horne 		break;
41122e6a670SMitchell Horne #endif
41222e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP
41322e6a670SMitchell Horne 	case MODINFOMD_EFI_MAP:
41422e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
41522e6a670SMitchell Horne 		break;
41622e6a670SMitchell Horne #endif
41722e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB
41822e6a670SMitchell Horne 	case MODINFOMD_EFI_FB:
41922e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_EFI_FB");
42022e6a670SMitchell Horne 		break;
42122e6a670SMitchell Horne #endif
42222e6a670SMitchell Horne #ifdef MODINFOMD_MODULEP
42322e6a670SMitchell Horne 	case MODINFOMD_MODULEP:
42422e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_MODULEP");
42522e6a670SMitchell Horne 		break;
42622e6a670SMitchell Horne #endif
427a4a10b37SToomas Soome #ifdef MODINFOMD_VBE_FB
428a4a10b37SToomas Soome 	case MODINFOMD_VBE_FB:
429a4a10b37SToomas Soome 		sbuf_cat(sbp, "MODINFOMD_VBE_FB");
430a4a10b37SToomas Soome 		break;
431a4a10b37SToomas Soome #endif
432742653ebSToomas Soome #ifdef MODINFOMD_FONT
433742653ebSToomas Soome 	case MODINFOMD_FONT:
434742653ebSToomas Soome 		sbuf_cat(sbp, "MODINFOMD_FONT");
435742653ebSToomas Soome 		break;
436742653ebSToomas Soome #endif
437966e53a4SEmmanuel Vadot #ifdef MODINFOMD_SPLASH
438966e53a4SEmmanuel Vadot 	case MODINFOMD_SPLASH:
439966e53a4SEmmanuel Vadot 		sbuf_cat(sbp, "MODINFOMD_SPLASH");
440966e53a4SEmmanuel Vadot 		break;
441966e53a4SEmmanuel Vadot #endif
44222e6a670SMitchell Horne 	default:
44322e6a670SMitchell Horne 		sbuf_cat(sbp, "unrecognized metadata type");
44422e6a670SMitchell Horne 	}
44522e6a670SMitchell Horne }
44622e6a670SMitchell Horne 
44722e6a670SMitchell Horne /*
44822e6a670SMitchell Horne  * Print the modinfo value, depending on type.
44922e6a670SMitchell Horne  */
45022e6a670SMitchell Horne static void
45122e6a670SMitchell Horne preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
45222e6a670SMitchell Horne {
45322e6a670SMitchell Horne #ifdef __LP64__
45422e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
45522e6a670SMitchell Horne #else
45622e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
45722e6a670SMitchell Horne #endif
45822e6a670SMitchell Horne 
45922e6a670SMitchell Horne 	switch (type) {
46022e6a670SMitchell Horne 	case MODINFO_NAME:
46122e6a670SMitchell Horne 	case MODINFO_TYPE:
46222e6a670SMitchell Horne 	case MODINFO_ARGS:
46322e6a670SMitchell Horne 		sbuf_printf(sbp, "%s", (char *)bptr);
46422e6a670SMitchell Horne 		break;
46522e6a670SMitchell Horne 	case MODINFO_SIZE:
46622e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
46722e6a670SMitchell Horne 		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
46822e6a670SMitchell Horne 		break;
46922e6a670SMitchell Horne 	case MODINFO_ADDR:
47022e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SSYM:
47122e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ESYM:
47222e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
47322e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_KERNEND:
47422e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ENVP:
47522e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
47622e6a670SMitchell Horne #ifdef MODINFOMD_SMAP
47722e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SMAP:
47822e6a670SMitchell Horne #endif
47922e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR
48022e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
48122e6a670SMitchell Horne #endif
48222e6a670SMitchell Horne #ifdef MODINFOMD_DTBP
48322e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_DTBP:
48422e6a670SMitchell Horne #endif
48522e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB
48622e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_EFI_FB:
48722e6a670SMitchell Horne #endif
488a4a10b37SToomas Soome #ifdef MODINFOMD_VBE_FB
489a4a10b37SToomas Soome 	case MODINFO_METADATA | MODINFOMD_VBE_FB:
490a4a10b37SToomas Soome #endif
491742653ebSToomas Soome #ifdef MODINFOMD_FONT
492742653ebSToomas Soome 	case MODINFO_METADATA | MODINFOMD_FONT:
493742653ebSToomas Soome #endif
494966e53a4SEmmanuel Vadot #ifdef MODINFOMD_SPLASH
495966e53a4SEmmanuel Vadot 	case MODINFO_METADATA | MODINFOMD_SPLASH:
496966e53a4SEmmanuel Vadot #endif
49722e6a670SMitchell Horne 		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
49822e6a670SMitchell Horne 		break;
49922e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_HOWTO:
50022e6a670SMitchell Horne 		sbuf_printf(sbp, "0x%08x", *bptr);
50122e6a670SMitchell Horne 		break;
50222e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SHDR:
50322e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ELFHDR:
50422e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
50522e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_KEYBUF:
50622e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP
50722e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
50822e6a670SMitchell Horne #endif
50922e6a670SMitchell Horne 		/* Don't print data buffers. */
51022e6a670SMitchell Horne 		sbuf_cat(sbp, "buffer contents omitted");
51122e6a670SMitchell Horne 		break;
51222e6a670SMitchell Horne 	default:
51322e6a670SMitchell Horne 		break;
51422e6a670SMitchell Horne 	}
51522e6a670SMitchell Horne #undef sbuf_print_vmoffset
51622e6a670SMitchell Horne }
51722e6a670SMitchell Horne 
51822e6a670SMitchell Horne static void
51922e6a670SMitchell Horne preload_dump_internal(struct sbuf *sbp)
52022e6a670SMitchell Horne {
52122e6a670SMitchell Horne 	uint32_t *bptr, type, len;
52222e6a670SMitchell Horne 
52322e6a670SMitchell Horne 	KASSERT(preload_metadata != NULL,
52422e6a670SMitchell Horne 	    ("%s called without setting up preload_metadata", __func__));
52522e6a670SMitchell Horne 
52622e6a670SMitchell Horne 	/*
52722e6a670SMitchell Horne 	 * Iterate through the TLV-encoded sections.
52822e6a670SMitchell Horne 	 */
52922e6a670SMitchell Horne 	bptr = (uint32_t *)preload_metadata;
53022e6a670SMitchell Horne 	sbuf_putc(sbp, '\n');
531841dad02SMitchell Horne 	while (bptr[0] != MODINFO_END || bptr[1] != MODINFO_END) {
53222e6a670SMitchell Horne 		sbuf_printf(sbp, " %p:\n", bptr);
53322e6a670SMitchell Horne 		type = *bptr++;
53422e6a670SMitchell Horne 		len = *bptr++;
53522e6a670SMitchell Horne 
53622e6a670SMitchell Horne 		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
53722e6a670SMitchell Horne 		preload_modinfo_type(sbp, type);
53822e6a670SMitchell Horne 		sbuf_putc(sbp, '\n');
53922e6a670SMitchell Horne 		sbuf_printf(sbp, "\tlen:\t%u\n", len);
54022e6a670SMitchell Horne 		sbuf_cat(sbp, "\tvalue:\t");
54122e6a670SMitchell Horne 		preload_modinfo_value(sbp, bptr, type, len);
54222e6a670SMitchell Horne 		sbuf_putc(sbp, '\n');
54322e6a670SMitchell Horne 
54422e6a670SMitchell Horne 		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
54522e6a670SMitchell Horne 	}
54622e6a670SMitchell Horne }
54722e6a670SMitchell Horne 
54822e6a670SMitchell Horne /*
54922e6a670SMitchell Horne  * Print the preloaded data to the console. Called from the machine-dependent
55022e6a670SMitchell Horne  * initialization routines, e.g. hammer_time().
55122e6a670SMitchell Horne  */
55222e6a670SMitchell Horne void
55322e6a670SMitchell Horne preload_dump(void)
55422e6a670SMitchell Horne {
55522e6a670SMitchell Horne 	char buf[512];
55622e6a670SMitchell Horne 	struct sbuf sb;
55722e6a670SMitchell Horne 
55822e6a670SMitchell Horne 	/*
55922e6a670SMitchell Horne 	 * This function is expected to be called before malloc is available,
56022e6a670SMitchell Horne 	 * so use a static buffer and struct sbuf.
56122e6a670SMitchell Horne 	 */
56222e6a670SMitchell Horne 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
56322e6a670SMitchell Horne 	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
56422e6a670SMitchell Horne 	preload_dump_internal(&sb);
56522e6a670SMitchell Horne 
56622e6a670SMitchell Horne 	sbuf_finish(&sb);
56722e6a670SMitchell Horne 	sbuf_delete(&sb);
56822e6a670SMitchell Horne }
56922e6a670SMitchell Horne 
57022e6a670SMitchell Horne static int
57122e6a670SMitchell Horne sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
57222e6a670SMitchell Horne {
57322e6a670SMitchell Horne 	struct sbuf sb;
57422e6a670SMitchell Horne 	int error;
57522e6a670SMitchell Horne 
57622e6a670SMitchell Horne 	if (preload_metadata == NULL)
57722e6a670SMitchell Horne 		return (EINVAL);
57822e6a670SMitchell Horne 
57922e6a670SMitchell Horne 	sbuf_new_for_sysctl(&sb, NULL, 512, req);
58022e6a670SMitchell Horne 	preload_dump_internal(&sb);
58122e6a670SMitchell Horne 
58222e6a670SMitchell Horne 	error = sbuf_finish(&sb);
58322e6a670SMitchell Horne 	sbuf_delete(&sb);
58422e6a670SMitchell Horne 
58522e6a670SMitchell Horne 	return (error);
58622e6a670SMitchell Horne }
58722e6a670SMitchell Horne SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
58822e6a670SMitchell Horne     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
58922e6a670SMitchell Horne     NULL, 0, sysctl_preload_dump, "A",
59022e6a670SMitchell Horne     "pretty-print the bootloader metadata");
591