xref: /freebsd/sys/kern/subr_module.c (revision 22e6a670868487bc17e36270eb34f34074693b6a)
16ba9413bSMike Smith /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
38a36da99SPedro F. Giffuni  *
46ba9413bSMike Smith  * Copyright (c) 1998 Michael Smith
56ba9413bSMike Smith  * All rights reserved.
6*22e6a670SMitchell Horne  * Copyright (c) 2020 NetApp Inc.
7*22e6a670SMitchell 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 
31677b542eSDavid E. O'Brien #include <sys/cdefs.h>
32677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
33677b542eSDavid E. O'Brien 
346ba9413bSMike Smith #include <sys/param.h>
356ba9413bSMike Smith #include <sys/systm.h>
366ba9413bSMike Smith #include <sys/linker.h>
37*22e6a670SMitchell Horne #include <sys/sbuf.h>
38*22e6a670SMitchell Horne #include <sys/sysctl.h>
39*22e6a670SMitchell Horne 
40*22e6a670SMitchell Horne #include <machine/metadata.h>
416ba9413bSMike Smith 
42483f692eSMark Johnston #include <vm/vm.h>
43483f692eSMark Johnston #include <vm/vm_extern.h>
44483f692eSMark Johnston 
456ba9413bSMike Smith /*
466ba9413bSMike Smith  * Preloaded module support
476ba9413bSMike Smith  */
486ba9413bSMike Smith 
49278e7970SMarcel Moolenaar vm_offset_t preload_addr_relocate = 0;
50e4f1a52fSPeter Wemm caddr_t preload_metadata;
516ba9413bSMike Smith 
526ba9413bSMike Smith /*
536ba9413bSMike Smith  * Search for the preloaded module (name)
546ba9413bSMike Smith  */
556ba9413bSMike Smith caddr_t
56e4f1a52fSPeter Wemm preload_search_by_name(const char *name)
576ba9413bSMike Smith {
586ba9413bSMike Smith     caddr_t	curp;
5960ae52f7SEd Schouten     uint32_t	*hdr;
60e4f1a52fSPeter Wemm     int		next;
616ba9413bSMike Smith 
62e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
63e4f1a52fSPeter Wemm 	curp = preload_metadata;
646ba9413bSMike Smith 	for (;;) {
6560ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
66e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
676ba9413bSMike Smith 		break;
686ba9413bSMike Smith 
696ba9413bSMike Smith 	    /* Search for a MODINFO_NAME field */
706ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_NAME) &&
7160ae52f7SEd Schouten 		!strcmp(name, curp + sizeof(uint32_t) * 2))
726ba9413bSMike Smith 		return(curp);
736ba9413bSMike Smith 
746ba9413bSMike Smith 	    /* skip to next field */
7560ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
762a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
77e4f1a52fSPeter Wemm 	    curp += next;
786ba9413bSMike Smith 	}
796ba9413bSMike Smith     }
806ba9413bSMike Smith     return(NULL);
816ba9413bSMike Smith }
826ba9413bSMike Smith 
836ba9413bSMike Smith /*
846ba9413bSMike Smith  * Search for the first preloaded module of (type)
856ba9413bSMike Smith  */
866ba9413bSMike Smith caddr_t
87e4f1a52fSPeter Wemm preload_search_by_type(const char *type)
886ba9413bSMike Smith {
896ba9413bSMike Smith     caddr_t	curp, lname;
9060ae52f7SEd Schouten     uint32_t	*hdr;
91e4f1a52fSPeter Wemm     int		next;
926ba9413bSMike Smith 
93e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
94e4f1a52fSPeter Wemm 	curp = preload_metadata;
956ba9413bSMike Smith 	lname = NULL;
966ba9413bSMike Smith 	for (;;) {
9760ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
98e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
996ba9413bSMike Smith 		break;
1006ba9413bSMike Smith 
1016ba9413bSMike Smith 	    /* remember the start of each record */
1026ba9413bSMike Smith 	    if (hdr[0] == MODINFO_NAME)
1036ba9413bSMike Smith 		lname = curp;
1046ba9413bSMike Smith 
1056ba9413bSMike Smith 	    /* Search for a MODINFO_TYPE field */
1066ba9413bSMike Smith 	    if ((hdr[0] == MODINFO_TYPE) &&
10760ae52f7SEd Schouten 		!strcmp(type, curp + sizeof(uint32_t) * 2))
1086ba9413bSMike Smith 		return(lname);
1096ba9413bSMike Smith 
1106ba9413bSMike Smith 	    /* skip to next field */
11160ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1122a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
113e4f1a52fSPeter Wemm 	    curp += next;
114e4f1a52fSPeter Wemm 	}
115e4f1a52fSPeter Wemm     }
116e4f1a52fSPeter Wemm     return(NULL);
117e4f1a52fSPeter Wemm }
118e4f1a52fSPeter Wemm 
119e4f1a52fSPeter Wemm /*
120e4f1a52fSPeter Wemm  * Walk through the preloaded module list
121e4f1a52fSPeter Wemm  */
122e4f1a52fSPeter Wemm caddr_t
123e4f1a52fSPeter Wemm preload_search_next_name(caddr_t base)
124e4f1a52fSPeter Wemm {
125e4f1a52fSPeter Wemm     caddr_t	curp;
12660ae52f7SEd Schouten     uint32_t	*hdr;
127e4f1a52fSPeter Wemm     int		next;
128e4f1a52fSPeter Wemm 
129e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
130e4f1a52fSPeter Wemm 	/* Pick up where we left off last time */
131e4f1a52fSPeter Wemm 	if (base) {
132e4f1a52fSPeter Wemm 	    /* skip to next field */
133e4f1a52fSPeter Wemm 	    curp = base;
13460ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
13560ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1362a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
137e4f1a52fSPeter Wemm 	    curp += next;
138e4f1a52fSPeter Wemm 	} else
139e4f1a52fSPeter Wemm 	    curp = preload_metadata;
140e4f1a52fSPeter Wemm 
141e4f1a52fSPeter Wemm 	for (;;) {
14260ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
143e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
144e4f1a52fSPeter Wemm 		break;
145e4f1a52fSPeter Wemm 
146e4f1a52fSPeter Wemm 	    /* Found a new record? */
147e4f1a52fSPeter Wemm 	    if (hdr[0] == MODINFO_NAME)
148e4f1a52fSPeter Wemm 		return curp;
149e4f1a52fSPeter Wemm 
150e4f1a52fSPeter Wemm 	    /* skip to next field */
15160ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
1522a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
153e4f1a52fSPeter Wemm 	    curp += next;
1546ba9413bSMike Smith 	}
1556ba9413bSMike Smith     }
1566ba9413bSMike Smith     return(NULL);
1576ba9413bSMike Smith }
1586ba9413bSMike Smith 
1596ba9413bSMike Smith /*
1606ba9413bSMike Smith  * Given a preloaded module handle (mod), return a pointer
1616ba9413bSMike Smith  * to the data for the attribute (inf).
1626ba9413bSMike Smith  */
1636ba9413bSMike Smith caddr_t
164e4f1a52fSPeter Wemm preload_search_info(caddr_t mod, int inf)
1656ba9413bSMike Smith {
1666ba9413bSMike Smith     caddr_t	curp;
16760ae52f7SEd Schouten     uint32_t	*hdr;
16860ae52f7SEd Schouten     uint32_t	type = 0;
169e4f1a52fSPeter Wemm     int		next;
1706ba9413bSMike Smith 
171e8234cfeSRoger Pau Monné     if (mod == NULL)
172e8234cfeSRoger Pau Monné     	return (NULL);
173e8234cfeSRoger Pau Monné 
1746ba9413bSMike Smith     curp = mod;
1756ba9413bSMike Smith     for (;;) {
17660ae52f7SEd Schouten 	hdr = (uint32_t *)curp;
1776ba9413bSMike Smith 	/* end of module data? */
178e4f1a52fSPeter Wemm 	if (hdr[0] == 0 && hdr[1] == 0)
1796ba9413bSMike Smith 	    break;
1806ba9413bSMike Smith 	/*
1816ba9413bSMike Smith 	 * We give up once we've looped back to what we were looking at
1826ba9413bSMike Smith 	 * first - this should normally be a MODINFO_NAME field.
1836ba9413bSMike Smith 	 */
1846ba9413bSMike Smith 	if (type == 0) {
1856ba9413bSMike Smith 	    type = hdr[0];
1866ba9413bSMike Smith 	} else {
1876ba9413bSMike Smith 	    if (hdr[0] == type)
1886ba9413bSMike Smith 		break;
1896ba9413bSMike Smith 	}
1906ba9413bSMike Smith 
1916ba9413bSMike Smith 	/*
1926ba9413bSMike Smith 	 * Attribute match? Return pointer to data.
193d7d97eb0SJeroen Ruigrok van der Werven 	 * Consumer may safely assume that size value precedes
1946ba9413bSMike Smith 	 * data.
1956ba9413bSMike Smith 	 */
1966ba9413bSMike Smith 	if (hdr[0] == inf)
19760ae52f7SEd Schouten 	    return(curp + (sizeof(uint32_t) * 2));
1986ba9413bSMike Smith 
1996ba9413bSMike Smith 	/* skip to next field */
20060ae52f7SEd Schouten 	next = sizeof(uint32_t) * 2 + hdr[1];
2012a26e9eaSPeter Wemm 	next = roundup(next, sizeof(u_long));
202e4f1a52fSPeter Wemm 	curp += next;
2036ba9413bSMike Smith     }
2046ba9413bSMike Smith     return(NULL);
2056ba9413bSMike Smith }
2066ba9413bSMike Smith 
207e4f1a52fSPeter Wemm /*
208e4f1a52fSPeter Wemm  * Delete a preload record by name.
209e4f1a52fSPeter Wemm  */
210e4f1a52fSPeter Wemm void
211e4f1a52fSPeter Wemm preload_delete_name(const char *name)
212e4f1a52fSPeter Wemm {
213483f692eSMark Johnston     caddr_t	addr, curp;
214483f692eSMark Johnston     uint32_t	*hdr, sz;
215e4f1a52fSPeter Wemm     int		next;
216e4f1a52fSPeter Wemm     int		clearing;
217e4f1a52fSPeter Wemm 
218483f692eSMark Johnston     addr = 0;
219483f692eSMark Johnston     sz = 0;
220483f692eSMark Johnston 
221e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
222e4f1a52fSPeter Wemm 	clearing = 0;
223e4f1a52fSPeter Wemm 	curp = preload_metadata;
224e4f1a52fSPeter Wemm 	for (;;) {
22560ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
226483f692eSMark Johnston 	    if (hdr[0] == MODINFO_NAME || (hdr[0] == 0 && hdr[1] == 0)) {
227483f692eSMark Johnston 		/* Free memory used to store the file. */
228483f692eSMark Johnston 		if (addr != 0 && sz != 0)
229483f692eSMark Johnston 		    kmem_bootstrap_free((vm_offset_t)addr, sz);
230483f692eSMark Johnston 		addr = 0;
231483f692eSMark Johnston 		sz = 0;
232e4f1a52fSPeter Wemm 
233483f692eSMark Johnston 		if (hdr[0] == 0)
234483f692eSMark Johnston 		    break;
23560ae52f7SEd Schouten 		if (!strcmp(name, curp + sizeof(uint32_t) * 2))
236e4f1a52fSPeter Wemm 		    clearing = 1;	/* got it, start clearing */
237483f692eSMark Johnston 		else if (clearing) {
238e4f1a52fSPeter Wemm 		    clearing = 0;	/* at next one now.. better stop */
239e4f1a52fSPeter Wemm 		}
240483f692eSMark Johnston 	    }
241483f692eSMark Johnston 	    if (clearing) {
242483f692eSMark Johnston 		if (hdr[0] == MODINFO_ADDR)
243483f692eSMark Johnston 		    addr = *(caddr_t *)(curp + sizeof(uint32_t) * 2);
244483f692eSMark Johnston 		else if (hdr[0] == MODINFO_SIZE)
245483f692eSMark Johnston 		    sz = *(uint32_t *)(curp + sizeof(uint32_t) * 2);
246e4f1a52fSPeter Wemm 		hdr[0] = MODINFO_EMPTY;
247483f692eSMark Johnston 	    }
248e4f1a52fSPeter Wemm 
249e4f1a52fSPeter Wemm 	    /* skip to next field */
25060ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
2512a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
252e4f1a52fSPeter Wemm 	    curp += next;
253e4f1a52fSPeter Wemm 	}
254e4f1a52fSPeter Wemm     }
255e4f1a52fSPeter Wemm }
256e4f1a52fSPeter Wemm 
257278e7970SMarcel Moolenaar void *
258278e7970SMarcel Moolenaar preload_fetch_addr(caddr_t mod)
259278e7970SMarcel Moolenaar {
260278e7970SMarcel Moolenaar 	caddr_t *mdp;
261278e7970SMarcel Moolenaar 
262278e7970SMarcel Moolenaar 	mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
263278e7970SMarcel Moolenaar 	if (mdp == NULL)
264278e7970SMarcel Moolenaar 		return (NULL);
265278e7970SMarcel Moolenaar 	return (*mdp + preload_addr_relocate);
266278e7970SMarcel Moolenaar }
267278e7970SMarcel Moolenaar 
268278e7970SMarcel Moolenaar size_t
269278e7970SMarcel Moolenaar preload_fetch_size(caddr_t mod)
270278e7970SMarcel Moolenaar {
271278e7970SMarcel Moolenaar 	size_t *mdp;
272278e7970SMarcel Moolenaar 
273278e7970SMarcel Moolenaar 	mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
274278e7970SMarcel Moolenaar 	if (mdp == NULL)
275278e7970SMarcel Moolenaar 		return (0);
276278e7970SMarcel Moolenaar 	return (*mdp);
277278e7970SMarcel Moolenaar }
278278e7970SMarcel Moolenaar 
27912d7eaa0SWarner Losh /* Called from locore.  Convert physical pointers to kvm. Sigh. */
280e4f1a52fSPeter Wemm void
281e4f1a52fSPeter Wemm preload_bootstrap_relocate(vm_offset_t offset)
282e4f1a52fSPeter Wemm {
283e4f1a52fSPeter Wemm     caddr_t	curp;
28460ae52f7SEd Schouten     uint32_t	*hdr;
285e4f1a52fSPeter Wemm     vm_offset_t	*ptr;
286e4f1a52fSPeter Wemm     int		next;
287e4f1a52fSPeter Wemm 
288e4f1a52fSPeter Wemm     if (preload_metadata != NULL) {
289e4f1a52fSPeter Wemm 	curp = preload_metadata;
290e4f1a52fSPeter Wemm 	for (;;) {
29160ae52f7SEd Schouten 	    hdr = (uint32_t *)curp;
292e4f1a52fSPeter Wemm 	    if (hdr[0] == 0 && hdr[1] == 0)
293e4f1a52fSPeter Wemm 		break;
294e4f1a52fSPeter Wemm 
2952da2eeacSPeter Wemm 	    /* Deal with the ones that we know we have to fix */
2962da2eeacSPeter Wemm 	    switch (hdr[0]) {
2972da2eeacSPeter Wemm 	    case MODINFO_ADDR:
2982da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_SSYM:
2992da2eeacSPeter Wemm 	    case MODINFO_METADATA|MODINFOMD_ESYM:
30060ae52f7SEd Schouten 		ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2));
301e4f1a52fSPeter Wemm 		*ptr += offset;
3022da2eeacSPeter Wemm 		break;
303e4f1a52fSPeter Wemm 	    }
304e4f1a52fSPeter Wemm 	    /* The rest is beyond us for now */
305e4f1a52fSPeter Wemm 
306e4f1a52fSPeter Wemm 	    /* skip to next field */
30760ae52f7SEd Schouten 	    next = sizeof(uint32_t) * 2 + hdr[1];
3082a26e9eaSPeter Wemm 	    next = roundup(next, sizeof(u_long));
309e4f1a52fSPeter Wemm 	    curp += next;
310e4f1a52fSPeter Wemm 	}
311e4f1a52fSPeter Wemm     }
312e4f1a52fSPeter Wemm }
313*22e6a670SMitchell Horne 
314*22e6a670SMitchell Horne /*
315*22e6a670SMitchell Horne  * Parse the modinfo type and append to the provided sbuf.
316*22e6a670SMitchell Horne  */
317*22e6a670SMitchell Horne static void
318*22e6a670SMitchell Horne preload_modinfo_type(struct sbuf *sbp, int type)
319*22e6a670SMitchell Horne {
320*22e6a670SMitchell Horne 
321*22e6a670SMitchell Horne 	if ((type & MODINFO_METADATA) == 0) {
322*22e6a670SMitchell Horne 		switch (type) {
323*22e6a670SMitchell Horne 		case MODINFO_END:
324*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_END");
325*22e6a670SMitchell Horne 			break;
326*22e6a670SMitchell Horne 		case MODINFO_NAME:
327*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_NAME");
328*22e6a670SMitchell Horne 			break;
329*22e6a670SMitchell Horne 		case MODINFO_TYPE:
330*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_TYPE");
331*22e6a670SMitchell Horne 			break;
332*22e6a670SMitchell Horne 		case MODINFO_ADDR:
333*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_ADDR");
334*22e6a670SMitchell Horne 			break;
335*22e6a670SMitchell Horne 		case MODINFO_SIZE:
336*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_SIZE");
337*22e6a670SMitchell Horne 			break;
338*22e6a670SMitchell Horne 		case MODINFO_EMPTY:
339*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_EMPTY");
340*22e6a670SMitchell Horne 			break;
341*22e6a670SMitchell Horne 		case MODINFO_ARGS:
342*22e6a670SMitchell Horne 			sbuf_cat(sbp, "MODINFO_ARGS");
343*22e6a670SMitchell Horne 			break;
344*22e6a670SMitchell Horne 		default:
345*22e6a670SMitchell Horne 			sbuf_cat(sbp, "unrecognized modinfo attribute");
346*22e6a670SMitchell Horne 		}
347*22e6a670SMitchell Horne 
348*22e6a670SMitchell Horne 		return;
349*22e6a670SMitchell Horne 	}
350*22e6a670SMitchell Horne 
351*22e6a670SMitchell Horne 	sbuf_cat(sbp, "MODINFO_METADATA | ");
352*22e6a670SMitchell Horne 	switch (type & ~MODINFO_METADATA) {
353*22e6a670SMitchell Horne 	case MODINFOMD_ELFHDR:
354*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ELFHDR");
355*22e6a670SMitchell Horne 		break;
356*22e6a670SMitchell Horne 	case MODINFOMD_SSYM:
357*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SSYM");
358*22e6a670SMitchell Horne 		break;
359*22e6a670SMitchell Horne 	case MODINFOMD_ESYM:
360*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ESYM");
361*22e6a670SMitchell Horne 		break;
362*22e6a670SMitchell Horne 	case MODINFOMD_DYNAMIC:
363*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
364*22e6a670SMitchell Horne 		break;
365*22e6a670SMitchell Horne 	case MODINFOMD_ENVP:
366*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_ENVP");
367*22e6a670SMitchell Horne 		break;
368*22e6a670SMitchell Horne 	case MODINFOMD_HOWTO:
369*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_HOWTO");
370*22e6a670SMitchell Horne 		break;
371*22e6a670SMitchell Horne 	case MODINFOMD_KERNEND:
372*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_KERNEND");
373*22e6a670SMitchell Horne 		break;
374*22e6a670SMitchell Horne 	case MODINFOMD_SHDR:
375*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SHDR");
376*22e6a670SMitchell Horne 		break;
377*22e6a670SMitchell Horne 	case MODINFOMD_CTORS_ADDR:
378*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
379*22e6a670SMitchell Horne 		break;
380*22e6a670SMitchell Horne 	case MODINFOMD_CTORS_SIZE:
381*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
382*22e6a670SMitchell Horne 		break;
383*22e6a670SMitchell Horne 	case MODINFOMD_FW_HANDLE:
384*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
385*22e6a670SMitchell Horne 		break;
386*22e6a670SMitchell Horne 	case MODINFOMD_KEYBUF:
387*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_KEYBUF");
388*22e6a670SMitchell Horne 		break;
389*22e6a670SMitchell Horne #ifdef MODINFOMD_SMAP
390*22e6a670SMitchell Horne 	case MODINFOMD_SMAP:
391*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SMAP");
392*22e6a670SMitchell Horne 		break;
393*22e6a670SMitchell Horne #endif
394*22e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR
395*22e6a670SMitchell Horne 	case MODINFOMD_SMAP_XATTR:
396*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
397*22e6a670SMitchell Horne 		break;
398*22e6a670SMitchell Horne #endif
399*22e6a670SMitchell Horne #ifdef MODINFOMD_DTBP
400*22e6a670SMitchell Horne 	case MODINFOMD_DTBP:
401*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_DTBP");
402*22e6a670SMitchell Horne 		break;
403*22e6a670SMitchell Horne #endif
404*22e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP
405*22e6a670SMitchell Horne 	case MODINFOMD_EFI_MAP:
406*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
407*22e6a670SMitchell Horne 		break;
408*22e6a670SMitchell Horne #endif
409*22e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB
410*22e6a670SMitchell Horne 	case MODINFOMD_EFI_FB:
411*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_EFI_FB");
412*22e6a670SMitchell Horne 		break;
413*22e6a670SMitchell Horne #endif
414*22e6a670SMitchell Horne #ifdef MODINFOMD_MODULEP
415*22e6a670SMitchell Horne 	case MODINFOMD_MODULEP:
416*22e6a670SMitchell Horne 		sbuf_cat(sbp, "MODINFOMD_MODULEP");
417*22e6a670SMitchell Horne 		break;
418*22e6a670SMitchell Horne #endif
419*22e6a670SMitchell Horne 	default:
420*22e6a670SMitchell Horne 		sbuf_cat(sbp, "unrecognized metadata type");
421*22e6a670SMitchell Horne 	}
422*22e6a670SMitchell Horne }
423*22e6a670SMitchell Horne 
424*22e6a670SMitchell Horne /*
425*22e6a670SMitchell Horne  * Print the modinfo value, depending on type.
426*22e6a670SMitchell Horne  */
427*22e6a670SMitchell Horne static void
428*22e6a670SMitchell Horne preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
429*22e6a670SMitchell Horne {
430*22e6a670SMitchell Horne #ifdef __LP64__
431*22e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%016lx", o);
432*22e6a670SMitchell Horne #else
433*22e6a670SMitchell Horne #define sbuf_print_vmoffset(sb, o)	sbuf_printf(sb, "0x%08x", o);
434*22e6a670SMitchell Horne #endif
435*22e6a670SMitchell Horne 
436*22e6a670SMitchell Horne 	switch (type) {
437*22e6a670SMitchell Horne 	case MODINFO_NAME:
438*22e6a670SMitchell Horne 	case MODINFO_TYPE:
439*22e6a670SMitchell Horne 	case MODINFO_ARGS:
440*22e6a670SMitchell Horne 		sbuf_printf(sbp, "%s", (char *)bptr);
441*22e6a670SMitchell Horne 		break;
442*22e6a670SMitchell Horne 	case MODINFO_SIZE:
443*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
444*22e6a670SMitchell Horne 		sbuf_printf(sbp, "%lu", *(u_long *)bptr);
445*22e6a670SMitchell Horne 		break;
446*22e6a670SMitchell Horne 	case MODINFO_ADDR:
447*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SSYM:
448*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ESYM:
449*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_DYNAMIC:
450*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_KERNEND:
451*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ENVP:
452*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
453*22e6a670SMitchell Horne #ifdef MODINFOMD_SMAP
454*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SMAP:
455*22e6a670SMitchell Horne #endif
456*22e6a670SMitchell Horne #ifdef MODINFOMD_SMAP_XATTR
457*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
458*22e6a670SMitchell Horne #endif
459*22e6a670SMitchell Horne #ifdef MODINFOMD_DTBP
460*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_DTBP:
461*22e6a670SMitchell Horne #endif
462*22e6a670SMitchell Horne #ifdef MODINFOMD_EFI_FB
463*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_EFI_FB:
464*22e6a670SMitchell Horne #endif
465*22e6a670SMitchell Horne 		sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
466*22e6a670SMitchell Horne 		break;
467*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_HOWTO:
468*22e6a670SMitchell Horne 		sbuf_printf(sbp, "0x%08x", *bptr);
469*22e6a670SMitchell Horne 		break;
470*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_SHDR:
471*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_ELFHDR:
472*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
473*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_KEYBUF:
474*22e6a670SMitchell Horne #ifdef MODINFOMD_EFI_MAP
475*22e6a670SMitchell Horne 	case MODINFO_METADATA | MODINFOMD_EFI_MAP:
476*22e6a670SMitchell Horne #endif
477*22e6a670SMitchell Horne 		/* Don't print data buffers. */
478*22e6a670SMitchell Horne 		sbuf_cat(sbp, "buffer contents omitted");
479*22e6a670SMitchell Horne 		break;
480*22e6a670SMitchell Horne 	default:
481*22e6a670SMitchell Horne 		break;
482*22e6a670SMitchell Horne 	}
483*22e6a670SMitchell Horne #undef sbuf_print_vmoffset
484*22e6a670SMitchell Horne }
485*22e6a670SMitchell Horne 
486*22e6a670SMitchell Horne static void
487*22e6a670SMitchell Horne preload_dump_internal(struct sbuf *sbp)
488*22e6a670SMitchell Horne {
489*22e6a670SMitchell Horne 	uint32_t *bptr, type, len;
490*22e6a670SMitchell Horne 
491*22e6a670SMitchell Horne 	KASSERT(preload_metadata != NULL,
492*22e6a670SMitchell Horne 	    ("%s called without setting up preload_metadata", __func__));
493*22e6a670SMitchell Horne 
494*22e6a670SMitchell Horne 	/*
495*22e6a670SMitchell Horne 	 * Iterate through the TLV-encoded sections.
496*22e6a670SMitchell Horne 	 */
497*22e6a670SMitchell Horne 	bptr = (uint32_t *)preload_metadata;
498*22e6a670SMitchell Horne 	sbuf_putc(sbp, '\n');
499*22e6a670SMitchell Horne 	while (bptr[0] != MODINFO_END || bptr[0] != MODINFO_END) {
500*22e6a670SMitchell Horne 		sbuf_printf(sbp, " %p:\n", bptr);
501*22e6a670SMitchell Horne 		type = *bptr++;
502*22e6a670SMitchell Horne 		len = *bptr++;
503*22e6a670SMitchell Horne 
504*22e6a670SMitchell Horne 		sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
505*22e6a670SMitchell Horne 		preload_modinfo_type(sbp, type);
506*22e6a670SMitchell Horne 		sbuf_putc(sbp, '\n');
507*22e6a670SMitchell Horne 		sbuf_printf(sbp, "\tlen:\t%u\n", len);
508*22e6a670SMitchell Horne 		sbuf_cat(sbp, "\tvalue:\t");
509*22e6a670SMitchell Horne 		preload_modinfo_value(sbp, bptr, type, len);
510*22e6a670SMitchell Horne 		sbuf_putc(sbp, '\n');
511*22e6a670SMitchell Horne 
512*22e6a670SMitchell Horne 		bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
513*22e6a670SMitchell Horne 	}
514*22e6a670SMitchell Horne }
515*22e6a670SMitchell Horne 
516*22e6a670SMitchell Horne /*
517*22e6a670SMitchell Horne  * Print the preloaded data to the console. Called from the machine-dependent
518*22e6a670SMitchell Horne  * initialization routines, e.g. hammer_time().
519*22e6a670SMitchell Horne  */
520*22e6a670SMitchell Horne void
521*22e6a670SMitchell Horne preload_dump(void)
522*22e6a670SMitchell Horne {
523*22e6a670SMitchell Horne 	char buf[512];
524*22e6a670SMitchell Horne 	struct sbuf sb;
525*22e6a670SMitchell Horne 
526*22e6a670SMitchell Horne 	/*
527*22e6a670SMitchell Horne 	 * This function is expected to be called before malloc is available,
528*22e6a670SMitchell Horne 	 * so use a static buffer and struct sbuf.
529*22e6a670SMitchell Horne 	 */
530*22e6a670SMitchell Horne 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
531*22e6a670SMitchell Horne 	sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
532*22e6a670SMitchell Horne 	preload_dump_internal(&sb);
533*22e6a670SMitchell Horne 
534*22e6a670SMitchell Horne 	sbuf_finish(&sb);
535*22e6a670SMitchell Horne 	sbuf_delete(&sb);
536*22e6a670SMitchell Horne }
537*22e6a670SMitchell Horne 
538*22e6a670SMitchell Horne static int
539*22e6a670SMitchell Horne sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
540*22e6a670SMitchell Horne {
541*22e6a670SMitchell Horne 	struct sbuf sb;
542*22e6a670SMitchell Horne 	int error;
543*22e6a670SMitchell Horne 
544*22e6a670SMitchell Horne 	if (preload_metadata == NULL)
545*22e6a670SMitchell Horne 		return (EINVAL);
546*22e6a670SMitchell Horne 
547*22e6a670SMitchell Horne 	sbuf_new_for_sysctl(&sb, NULL, 512, req);
548*22e6a670SMitchell Horne 	preload_dump_internal(&sb);
549*22e6a670SMitchell Horne 
550*22e6a670SMitchell Horne 	error = sbuf_finish(&sb);
551*22e6a670SMitchell Horne 	sbuf_delete(&sb);
552*22e6a670SMitchell Horne 
553*22e6a670SMitchell Horne 	return (error);
554*22e6a670SMitchell Horne }
555*22e6a670SMitchell Horne SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
556*22e6a670SMitchell Horne     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
557*22e6a670SMitchell Horne     NULL, 0, sysctl_preload_dump, "A",
558*22e6a670SMitchell Horne     "pretty-print the bootloader metadata");
559