xref: /dragonfly/sys/kern/subr_module.c (revision 22cd51fe)
1 /*-
2  * Copyright (c) 1998 Michael Smith
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32 #include <sys/sbuf.h>
33 #include <sys/sysctl.h>
34 
35 #include <machine/metadata.h>
36 
37 /*
38  * Preloaded module support
39  */
40 
41 caddr_t	preload_metadata;
42 
43 /*
44  * Search for the preloaded module (name)
45  */
46 caddr_t
47 preload_search_by_name(const char *name)
48 {
49     caddr_t	curp;
50     u_int32_t	*hdr;
51     int		next;
52     int		i;
53     char	*scanname;
54 
55     if (preload_metadata == NULL)
56 	return(NULL);
57 
58     curp = preload_metadata;
59     for (;;) {
60 	hdr = (u_int32_t *)curp;
61 	if (hdr[0] == 0 && hdr[1] == 0)
62 	    break;
63 
64 	/*
65 	 * Search for a MODINFO_NAME field.  the boot loader really
66 	 * ought to strip the path names
67 	 */
68 	if (hdr[0] == MODINFO_NAME) {
69 	    scanname = curp + sizeof(u_int32_t) * 2;
70 	    i = strlen(scanname);
71 	    while (i > 0 && scanname[i-1] != '/')
72 		--i;
73 	    if (strcmp(name, scanname) == 0)
74 		return(curp);
75 	    if (strcmp(name, scanname + i) == 0)
76 		return(curp);
77 	}
78 	/* skip to next field */
79 	next = sizeof(u_int32_t) * 2 + hdr[1];
80 	next = roundup(next, sizeof(u_long));
81 	curp += next;
82     }
83     return(NULL);
84 }
85 
86 /*
87  * Search for the first preloaded module of (type)
88  */
89 caddr_t
90 preload_search_by_type(const char *type)
91 {
92     caddr_t	curp, lname;
93     u_int32_t	*hdr;
94     int		next;
95 
96     if (preload_metadata != NULL) {
97 
98 	curp = preload_metadata;
99 	lname = NULL;
100 	for (;;) {
101 	    hdr = (u_int32_t *)curp;
102 	    if (hdr[0] == 0 && hdr[1] == 0)
103 		break;
104 
105 	    /* remember the start of each record */
106 	    if (hdr[0] == MODINFO_NAME)
107 		lname = curp;
108 
109 	    /* Search for a MODINFO_TYPE field */
110 	    if ((hdr[0] == MODINFO_TYPE) &&
111 		!strcmp(type, curp + sizeof(u_int32_t) * 2))
112 		return(lname);
113 
114 	    /* skip to next field */
115 	    next = sizeof(u_int32_t) * 2 + hdr[1];
116 	    next = roundup(next, sizeof(u_long));
117 	    curp += next;
118 	}
119     }
120     return(NULL);
121 }
122 
123 /*
124  * Walk through the preloaded module list
125  */
126 caddr_t
127 preload_search_next_name(caddr_t base)
128 {
129     caddr_t	curp;
130     u_int32_t	*hdr;
131     int		next;
132 
133     if (preload_metadata != NULL) {
134 
135 	/* Pick up where we left off last time */
136 	if (base) {
137 	    /* skip to next field */
138 	    curp = base;
139 	    hdr = (u_int32_t *)curp;
140 	    next = sizeof(u_int32_t) * 2 + hdr[1];
141 	    next = roundup(next, sizeof(u_long));
142 	    curp += next;
143 	} else
144 	    curp = preload_metadata;
145 
146 	for (;;) {
147 	    hdr = (u_int32_t *)curp;
148 	    if (hdr[0] == 0 && hdr[1] == 0)
149 		break;
150 
151 	    /* Found a new record? */
152 	    if (hdr[0] == MODINFO_NAME)
153 		return curp;
154 
155 	    /* skip to next field */
156 	    next = sizeof(u_int32_t) * 2 + hdr[1];
157 	    next = roundup(next, sizeof(u_long));
158 	    curp += next;
159 	}
160     }
161     return(NULL);
162 }
163 
164 /*
165  * Given a preloaded module handle (mod), return a pointer
166  * to the data for the attribute (inf).
167  */
168 caddr_t
169 preload_search_info(caddr_t mod, int inf)
170 {
171     caddr_t	curp;
172     u_int32_t	*hdr;
173     u_int32_t	type = 0;
174     int		next;
175 
176     curp = mod;
177     for (;;) {
178 	hdr = (u_int32_t *)curp;
179 	/* end of module data? */
180 	if (hdr[0] == 0 && hdr[1] == 0)
181 	    break;
182 	/*
183 	 * We give up once we've looped back to what we were looking at
184 	 * first - this should normally be a MODINFO_NAME field.
185 	 */
186 	if (type == 0) {
187 	    type = hdr[0];
188 	} else {
189 	    if (hdr[0] == type)
190 		break;
191 	}
192 
193 	/*
194 	 * Attribute match? Return pointer to data.
195 	 * Consumer may safely assume that size value preceeds
196 	 * data.
197 	 */
198 	if (hdr[0] == inf)
199 	    return(curp + (sizeof(u_int32_t) * 2));
200 
201 	/* skip to next field */
202 	next = sizeof(u_int32_t) * 2 + hdr[1];
203 	next = roundup(next, sizeof(u_long));
204 	curp += next;
205     }
206     return(NULL);
207 }
208 
209 /*
210  * Delete a preload record by path name.
211  */
212 void
213 preload_delete_name(const char *name)
214 {
215     caddr_t	curp;
216     u_int32_t	*hdr;
217     int		next;
218     int		clearing;
219 
220     if (preload_metadata != NULL) {
221 	clearing = 0;
222 	curp = preload_metadata;
223 	for (;;) {
224 	    hdr = (u_int32_t *)curp;
225 	    if (hdr[0] == 0 && hdr[1] == 0)
226 		break;
227 
228 	    /* Search for a MODINFO_NAME field */
229 	    if (hdr[0] == MODINFO_NAME) {
230 		if (strcmp(name, curp + sizeof(u_int32_t) * 2) == 0)
231 		    clearing = 1;	/* start clearing */
232 		else if (clearing)
233 		    clearing = 0;	/* at next module now, stop clearing */
234 	    }
235 	    if (clearing)
236 		hdr[0] = MODINFO_EMPTY;
237 
238 	    /* skip to next field */
239 	    next = sizeof(u_int32_t) * 2 + hdr[1];
240 	    next = roundup(next, sizeof(u_long));
241 	    curp += next;
242 	}
243     }
244 }
245 
246 /* Called from hammer_time() on pc64.  Convert physical pointers to kvm. Sigh. */
247 void
248 preload_bootstrap_relocate(vm_offset_t offset)
249 {
250     caddr_t	curp;
251     u_int32_t	*hdr;
252     vm_offset_t	*ptr;
253     int		next;
254 
255     if (preload_metadata != NULL) {
256 
257 	curp = preload_metadata;
258 	for (;;) {
259 	    hdr = (u_int32_t *)curp;
260 	    if (hdr[0] == 0 && hdr[1] == 0)
261 		break;
262 
263 	    /* Deal with the ones that we know we have to fix */
264 	    switch (hdr[0]) {
265 	    case MODINFO_ADDR:
266 	    case MODINFO_METADATA|MODINFOMD_SSYM:
267 	    case MODINFO_METADATA|MODINFOMD_ESYM:
268 		ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
269 		*ptr += offset;
270 		break;
271 	    }
272 	    /* The rest is beyond us for now */
273 
274 	    /* skip to next field */
275 	    next = sizeof(u_int32_t) * 2 + hdr[1];
276 	    next = roundup(next, sizeof(u_long));
277 	    curp += next;
278 	}
279     }
280 }
281 
282 /*
283  * Parse the modinfo type and append to the sbuf.
284  */
285 static void
286 preload_modinfo_type(struct sbuf *sbp, int type)
287 {
288     if ((type & MODINFO_METADATA) == 0) {
289 	switch (type) {
290 	case MODINFO_END:
291 	    sbuf_cat(sbp, "MODINFO_END");
292 	    break;
293 	case MODINFO_NAME:
294 	    sbuf_cat(sbp, "MODINFO_NAME");
295 	    break;
296 	case MODINFO_TYPE:
297 	    sbuf_cat(sbp, "MODINFO_TYPE");
298 	    break;
299 	case MODINFO_ADDR:
300 	    sbuf_cat(sbp, "MODINFO_ADDR");
301 	    break;
302 	case MODINFO_SIZE:
303 	    sbuf_cat(sbp, "MODINFO_SIZE");
304 	    break;
305 	case MODINFO_EMPTY:
306 	    sbuf_cat(sbp, "MODINFO_EMPTY");
307 	    break;
308 	case MODINFO_ARGS:
309 	    sbuf_cat(sbp, "MODINFO_ARGS");
310 	    break;
311 	default:
312 	    sbuf_cat(sbp, "unrecognized modinfo attribute");
313 	}
314 
315 	return;
316     }
317 
318     sbuf_cat(sbp, "MODINFO_METADATA | ");
319     switch (type & ~MODINFO_METADATA) {
320     case MODINFOMD_ELFHDR:
321 	sbuf_cat(sbp, "MODINFOMD_ELFHDR");
322 	break;
323     case MODINFOMD_SSYM:
324 	sbuf_cat(sbp, "MODINFOMD_SSYM");
325 	break;
326     case MODINFOMD_ESYM:
327 	sbuf_cat(sbp, "MODINFOMD_ESYM");
328 	break;
329     case MODINFOMD_DYNAMIC:
330 	sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
331 	break;
332     case MODINFOMD_ENVP:
333 	sbuf_cat(sbp, "MODINFOMD_ENVP");
334 	break;
335     case MODINFOMD_HOWTO:
336 	sbuf_cat(sbp, "MODINFOMD_HOWTO");
337 	break;
338     case MODINFOMD_KERNEND:
339 	sbuf_cat(sbp, "MODINFOMD_KERNEND");
340 	break;
341     case MODINFOMD_SHDR:
342 	sbuf_cat(sbp, "MODINFOMD_SHDR");
343 	break;
344     case MODINFOMD_FW_HANDLE:
345 	sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
346 	break;
347     case MODINFOMD_SMAP:
348 	sbuf_cat(sbp, "MODINFOMD_SMAP");
349 	break;
350     case MODINFOMD_EFI_MAP:
351 	sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
352 	break;
353     case MODINFOMD_EFI_FB:
354 	sbuf_cat(sbp, "MODINFOMD_EFI_FB");
355 	break;
356     default:
357 	sbuf_cat(sbp, "unrecognized metadata type");
358     }
359 }
360 
361 /*
362  * Print the modinfo value, depending on type.
363  */
364 static void
365 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
366 {
367     switch (type) {
368     case MODINFO_NAME:
369     case MODINFO_TYPE:
370     case MODINFO_ARGS:
371 	sbuf_printf(sbp, "%s", (char *)bptr);
372 	break;
373     case MODINFO_SIZE:
374 	sbuf_printf(sbp, "%lu", *(u_long *)bptr);
375 	break;
376     case MODINFO_ADDR:
377     case MODINFO_METADATA | MODINFOMD_SSYM:
378     case MODINFO_METADATA | MODINFOMD_ESYM:
379     case MODINFO_METADATA | MODINFOMD_DYNAMIC:
380     case MODINFO_METADATA | MODINFOMD_KERNEND:
381     case MODINFO_METADATA | MODINFOMD_ENVP:
382     case MODINFO_METADATA | MODINFOMD_SMAP:
383     case MODINFO_METADATA | MODINFOMD_EFI_FB:
384 	sbuf_printf(sbp, "0x%016lx", *(vm_offset_t *)bptr);
385 	break;
386     case MODINFO_METADATA | MODINFOMD_HOWTO:
387 	sbuf_printf(sbp, "0x%08x", *bptr);
388 	break;
389     case MODINFO_METADATA | MODINFOMD_SHDR:
390     case MODINFO_METADATA | MODINFOMD_ELFHDR:
391     case MODINFO_METADATA | MODINFOMD_FW_HANDLE:
392     case MODINFO_METADATA | MODINFOMD_EFI_MAP:
393 	/* Don't print data buffers. */
394 	sbuf_cat(sbp, "buffer contents omitted");
395 	break;
396     default:
397 	break;
398     }
399 }
400 
401 static void
402 preload_dump_internal(struct sbuf *sbp)
403 {
404     uint32_t *bptr, type, len;
405 
406     sbuf_putc(sbp, '\n');
407 
408     /* Iterate through the TLV-encoded sections. */
409     bptr = (uint32_t *)preload_metadata;
410     while (bptr[0] != MODINFO_END) {
411 	sbuf_printf(sbp, " %p:\n", bptr);
412 
413 	type = *bptr++;
414 	sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
415 	preload_modinfo_type(sbp, type);
416 	sbuf_putc(sbp, '\n');
417 
418 	len = *bptr++;
419 	sbuf_printf(sbp, "\tlen:\t%u\n", len);
420 
421 	sbuf_cat(sbp, "\tvalue:\t");
422 	preload_modinfo_value(sbp, bptr, type, len);
423 	sbuf_putc(sbp, '\n');
424 
425 	bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
426     }
427 }
428 
429 static int
430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
431 {
432     struct sbuf sb;
433     int error;
434 
435     if (preload_metadata == NULL)
436 	return (EINVAL);
437 
438     sbuf_new_for_sysctl(&sb, NULL, 512, req);
439     preload_dump_internal(&sb);
440 
441     error = sbuf_finish(&sb);
442     sbuf_delete(&sb);
443 
444     return (error);
445 }
446 
447 SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo,
448 	    CTLTYPE_STRING | CTLFLAG_RD,
449 	    NULL, 0, sysctl_preload_dump, "A",
450 	    "pretty-print the bootloader metadata");
451