FreeBSD kernel kern code
subr_module.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/linker.h>
37#include <sys/sbuf.h>
38#include <sys/sysctl.h>
39
40#include <machine/metadata.h>
41
42#include <vm/vm.h>
43#include <vm/vm_extern.h>
44
45/*
46 * Preloaded module support
47 */
48
49vm_offset_t preload_addr_relocate = 0;
51
52/*
53 * Search for the preloaded module (name)
54 */
55caddr_t
57{
58 caddr_t curp;
59 uint32_t *hdr;
60 int next;
61
62 if (preload_metadata != NULL) {
63 curp = preload_metadata;
64 for (;;) {
65 hdr = (uint32_t *)curp;
66 if (hdr[0] == 0 && hdr[1] == 0)
67 break;
68
69 /* Search for a MODINFO_NAME field */
70 if ((hdr[0] == MODINFO_NAME) &&
71 !strcmp(name, curp + sizeof(uint32_t) * 2))
72 return(curp);
73
74 /* skip to next field */
75 next = sizeof(uint32_t) * 2 + hdr[1];
76 next = roundup(next, sizeof(u_long));
77 curp += next;
78 }
79 }
80 return(NULL);
81}
82
83/*
84 * Search for the first preloaded module of (type)
85 */
86caddr_t
88{
89 caddr_t curp, lname;
90 uint32_t *hdr;
91 int next;
92
93 if (preload_metadata != NULL) {
94 curp = preload_metadata;
95 lname = NULL;
96 for (;;) {
97 hdr = (uint32_t *)curp;
98 if (hdr[0] == 0 && hdr[1] == 0)
99 break;
100
101 /* remember the start of each record */
102 if (hdr[0] == MODINFO_NAME)
103 lname = curp;
104
105 /* Search for a MODINFO_TYPE field */
106 if ((hdr[0] == MODINFO_TYPE) &&
107 !strcmp(type, curp + sizeof(uint32_t) * 2))
108 return(lname);
109
110 /* skip to next field */
111 next = sizeof(uint32_t) * 2 + hdr[1];
112 next = roundup(next, sizeof(u_long));
113 curp += next;
114 }
115 }
116 return(NULL);
117}
118
119/*
120 * Walk through the preloaded module list
121 */
122caddr_t
124{
125 caddr_t curp;
126 uint32_t *hdr;
127 int next;
128
129 if (preload_metadata != NULL) {
130 /* Pick up where we left off last time */
131 if (base) {
132 /* skip to next field */
133 curp = base;
134 hdr = (uint32_t *)curp;
135 next = sizeof(uint32_t) * 2 + hdr[1];
136 next = roundup(next, sizeof(u_long));
137 curp += next;
138 } else
139 curp = preload_metadata;
140
141 for (;;) {
142 hdr = (uint32_t *)curp;
143 if (hdr[0] == 0 && hdr[1] == 0)
144 break;
145
146 /* Found a new record? */
147 if (hdr[0] == MODINFO_NAME)
148 return curp;
149
150 /* skip to next field */
151 next = sizeof(uint32_t) * 2 + hdr[1];
152 next = roundup(next, sizeof(u_long));
153 curp += next;
154 }
155 }
156 return(NULL);
157}
158
159/*
160 * Given a preloaded module handle (mod), return a pointer
161 * to the data for the attribute (inf).
162 */
163caddr_t
164preload_search_info(caddr_t mod, int inf)
165{
166 caddr_t curp;
167 uint32_t *hdr;
168 uint32_t type = 0;
169 int next;
170
171 if (mod == NULL)
172 return (NULL);
173
174 curp = mod;
175 for (;;) {
176 hdr = (uint32_t *)curp;
177 /* end of module data? */
178 if (hdr[0] == 0 && hdr[1] == 0)
179 break;
180 /*
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.
183 */
184 if (type == 0) {
185 type = hdr[0];
186 } else {
187 if (hdr[0] == type)
188 break;
189 }
190
191 /*
192 * Attribute match? Return pointer to data.
193 * Consumer may safely assume that size value precedes
194 * data.
195 */
196 if (hdr[0] == inf)
197 return(curp + (sizeof(uint32_t) * 2));
198
199 /* skip to next field */
200 next = sizeof(uint32_t) * 2 + hdr[1];
201 next = roundup(next, sizeof(u_long));
202 curp += next;
203 }
204 return(NULL);
205}
206
207/*
208 * Delete a preload record by name.
209 */
210void
212{
213 caddr_t addr, curp;
214 uint32_t *hdr, sz;
215 int next;
216 int clearing;
217
218 addr = 0;
219 sz = 0;
220
221 if (preload_metadata != NULL) {
222 clearing = 0;
223 curp = preload_metadata;
224 for (;;) {
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);
230 addr = 0;
231 sz = 0;
232
233 if (hdr[0] == 0)
234 break;
235 if (!strcmp(name, curp + sizeof(uint32_t) * 2))
236 clearing = 1; /* got it, start clearing */
237 else if (clearing) {
238 clearing = 0; /* at next one now.. better stop */
239 }
240 }
241 if (clearing) {
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;
247 }
248
249 /* skip to next field */
250 next = sizeof(uint32_t) * 2 + hdr[1];
251 next = roundup(next, sizeof(u_long));
252 curp += next;
253 }
254 }
255}
256
257void *
259{
260 caddr_t *mdp;
261
262 mdp = (caddr_t *)preload_search_info(mod, MODINFO_ADDR);
263 if (mdp == NULL)
264 return (NULL);
265 return (*mdp + preload_addr_relocate);
266}
267
268size_t
270{
271 size_t *mdp;
272
273 mdp = (size_t *)preload_search_info(mod, MODINFO_SIZE);
274 if (mdp == NULL)
275 return (0);
276 return (*mdp);
277}
278
279/* Called from locore. Convert physical pointers to kvm. Sigh. */
280void
281preload_bootstrap_relocate(vm_offset_t offset)
282{
283 caddr_t curp;
284 uint32_t *hdr;
285 vm_offset_t *ptr;
286 int next;
287
288 if (preload_metadata != NULL) {
289 curp = preload_metadata;
290 for (;;) {
291 hdr = (uint32_t *)curp;
292 if (hdr[0] == 0 && hdr[1] == 0)
293 break;
294
295 /* Deal with the ones that we know we have to fix */
296 switch (hdr[0]) {
297 case MODINFO_ADDR:
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));
302 *ptr += offset;
303 break;
304 }
305 /* The rest is beyond us for now */
306
307 /* skip to next field */
308 next = sizeof(uint32_t) * 2 + hdr[1];
309 next = roundup(next, sizeof(u_long));
310 curp += next;
311 }
312 }
313}
314
315/*
316 * Parse the modinfo type and append to the provided sbuf.
317 */
318static void
319preload_modinfo_type(struct sbuf *sbp, int type)
320{
321
322 if ((type & MODINFO_METADATA) == 0) {
323 switch (type) {
324 case MODINFO_END:
325 sbuf_cat(sbp, "MODINFO_END");
326 break;
327 case MODINFO_NAME:
328 sbuf_cat(sbp, "MODINFO_NAME");
329 break;
330 case MODINFO_TYPE:
331 sbuf_cat(sbp, "MODINFO_TYPE");
332 break;
333 case MODINFO_ADDR:
334 sbuf_cat(sbp, "MODINFO_ADDR");
335 break;
336 case MODINFO_SIZE:
337 sbuf_cat(sbp, "MODINFO_SIZE");
338 break;
339 case MODINFO_EMPTY:
340 sbuf_cat(sbp, "MODINFO_EMPTY");
341 break;
342 case MODINFO_ARGS:
343 sbuf_cat(sbp, "MODINFO_ARGS");
344 break;
345 default:
346 sbuf_cat(sbp, "unrecognized modinfo attribute");
347 }
348
349 return;
350 }
351
352 sbuf_cat(sbp, "MODINFO_METADATA | ");
353 switch (type & ~MODINFO_METADATA) {
354 case MODINFOMD_ELFHDR:
355 sbuf_cat(sbp, "MODINFOMD_ELFHDR");
356 break;
357 case MODINFOMD_SSYM:
358 sbuf_cat(sbp, "MODINFOMD_SSYM");
359 break;
360 case MODINFOMD_ESYM:
361 sbuf_cat(sbp, "MODINFOMD_ESYM");
362 break;
363 case MODINFOMD_DYNAMIC:
364 sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
365 break;
366 case MODINFOMD_ENVP:
367 sbuf_cat(sbp, "MODINFOMD_ENVP");
368 break;
369 case MODINFOMD_HOWTO:
370 sbuf_cat(sbp, "MODINFOMD_HOWTO");
371 break;
372 case MODINFOMD_KERNEND:
373 sbuf_cat(sbp, "MODINFOMD_KERNEND");
374 break;
375 case MODINFOMD_SHDR:
376 sbuf_cat(sbp, "MODINFOMD_SHDR");
377 break;
378 case MODINFOMD_CTORS_ADDR:
379 sbuf_cat(sbp, "MODINFOMD_CTORS_ADDR");
380 break;
381 case MODINFOMD_CTORS_SIZE:
382 sbuf_cat(sbp, "MODINFOMD_CTORS_SIZE");
383 break;
384 case MODINFOMD_FW_HANDLE:
385 sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
386 break;
387 case MODINFOMD_KEYBUF:
388 sbuf_cat(sbp, "MODINFOMD_KEYBUF");
389 break;
390#ifdef MODINFOMD_SMAP
391 case MODINFOMD_SMAP:
392 sbuf_cat(sbp, "MODINFOMD_SMAP");
393 break;
394#endif
395#ifdef MODINFOMD_SMAP_XATTR
396 case MODINFOMD_SMAP_XATTR:
397 sbuf_cat(sbp, "MODINFOMD_SMAP_XATTR");
398 break;
399#endif
400#ifdef MODINFOMD_DTBP
401 case MODINFOMD_DTBP:
402 sbuf_cat(sbp, "MODINFOMD_DTBP");
403 break;
404#endif
405#ifdef MODINFOMD_EFI_MAP
406 case MODINFOMD_EFI_MAP:
407 sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
408 break;
409#endif
410#ifdef MODINFOMD_EFI_FB
411 case MODINFOMD_EFI_FB:
412 sbuf_cat(sbp, "MODINFOMD_EFI_FB");
413 break;
414#endif
415#ifdef MODINFOMD_MODULEP
416 case MODINFOMD_MODULEP:
417 sbuf_cat(sbp, "MODINFOMD_MODULEP");
418 break;
419#endif
420#ifdef MODINFOMD_VBE_FB
421 case MODINFOMD_VBE_FB:
422 sbuf_cat(sbp, "MODINFOMD_VBE_FB");
423 break;
424#endif
425#ifdef MODINFOMD_FONT
426 case MODINFOMD_FONT:
427 sbuf_cat(sbp, "MODINFOMD_FONT");
428 break;
429#endif
430 default:
431 sbuf_cat(sbp, "unrecognized metadata type");
432 }
433}
434
435/*
436 * Print the modinfo value, depending on type.
437 */
438static void
439preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
440{
441#ifdef __LP64__
442#define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%016lx", o);
443#else
444#define sbuf_print_vmoffset(sb, o) sbuf_printf(sb, "0x%08x", o);
445#endif
446
447 switch (type) {
448 case MODINFO_NAME:
449 case MODINFO_TYPE:
450 case MODINFO_ARGS:
451 sbuf_printf(sbp, "%s", (char *)bptr);
452 break;
453 case MODINFO_SIZE:
454 case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
455 sbuf_printf(sbp, "%lu", *(u_long *)bptr);
456 break;
457 case MODINFO_ADDR:
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:
466#endif
467#ifdef MODINFOMD_SMAP_XATTR
468 case MODINFO_METADATA | MODINFOMD_SMAP_XATTR:
469#endif
470#ifdef MODINFOMD_DTBP
471 case MODINFO_METADATA | MODINFOMD_DTBP:
472#endif
473#ifdef MODINFOMD_EFI_FB
474 case MODINFO_METADATA | MODINFOMD_EFI_FB:
475#endif
476#ifdef MODINFOMD_VBE_FB
477 case MODINFO_METADATA | MODINFOMD_VBE_FB:
478#endif
479#ifdef MODINFOMD_FONT
480 case MODINFO_METADATA | MODINFOMD_FONT:
481#endif
482 sbuf_print_vmoffset(sbp, *(vm_offset_t *)bptr);
483 break;
484 case MODINFO_METADATA | MODINFOMD_HOWTO:
485 sbuf_printf(sbp, "0x%08x", *bptr);
486 break;
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:
493#endif
494 /* Don't print data buffers. */
495 sbuf_cat(sbp, "buffer contents omitted");
496 break;
497 default:
498 break;
499 }
500#undef sbuf_print_vmoffset
501}
502
503static void
504preload_dump_internal(struct sbuf *sbp)
505{
506 uint32_t *bptr, type, len;
507
508 KASSERT(preload_metadata != NULL,
509 ("%s called without setting up preload_metadata", __func__));
510
511 /*
512 * Iterate through the TLV-encoded sections.
513 */
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);
518 type = *bptr++;
519 len = *bptr++;
520
521 sbuf_printf(sbp, "\ttype:\t(%#04x) ", 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');
528
529 bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
530 }
531}
532
533/*
534 * Print the preloaded data to the console. Called from the machine-dependent
535 * initialization routines, e.g. hammer_time().
536 */
537void
539{
540 char buf[512];
541 struct sbuf sb;
542
543 /*
544 * This function is expected to be called before malloc is available,
545 * so use a static buffer and struct sbuf.
546 */
547 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
550
551 sbuf_finish(&sb);
552 sbuf_delete(&sb);
553}
554
555static int
556sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
557{
558 struct sbuf sb;
559 int error;
560
561 if (preload_metadata == NULL)
562 return (EINVAL);
563
564 sbuf_new_for_sysctl(&sb, NULL, 512, req);
566
567 error = sbuf_finish(&sb);
568 sbuf_delete(&sb);
569
570 return (error);
571}
572SYSCTL_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");
device_property_type_t type
Definition: bus_if.m:941
const char * name
Definition: kern_fail.c:145
struct sbuf * sbuf_new_for_sysctl(struct sbuf *s, char *buf, int length, struct sysctl_req *req)
Definition: kern_sysctl.c:2503
uint64_t * addr
Definition: msi_if.m:89
static void preload_dump_internal(struct sbuf *sbp)
Definition: subr_module.c:504
static int sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
Definition: subr_module.c:556
static void preload_modinfo_type(struct sbuf *sbp, int type)
Definition: subr_module.c:319
#define sbuf_print_vmoffset(sb, o)
caddr_t preload_search_info(caddr_t mod, int inf)
Definition: subr_module.c:164
caddr_t preload_search_by_name(const char *name)
Definition: subr_module.c:56
__FBSDID("$FreeBSD$")
size_t preload_fetch_size(caddr_t mod)
Definition: subr_module.c:269
void preload_delete_name(const char *name)
Definition: subr_module.c:211
caddr_t preload_search_by_type(const char *type)
Definition: subr_module.c:87
void preload_bootstrap_relocate(vm_offset_t offset)
Definition: subr_module.c:281
vm_offset_t preload_addr_relocate
Definition: subr_module.c:49
void preload_dump(void)
Definition: subr_module.c:538
caddr_t preload_search_next_name(caddr_t base)
Definition: subr_module.c:123
void * preload_fetch_addr(caddr_t mod)
Definition: subr_module.c:258
caddr_t preload_metadata
Definition: subr_module.c:50
SYSCTL_PROC(_debug, OID_AUTO, dump_modinfo, CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, 0, sysctl_preload_dump, "A", "pretty-print the bootloader metadata")
static void preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
Definition: subr_module.c:439
int sbuf_printf_drain(void *arg, const char *data, int len)
Definition: subr_prf.c:1298
int sbuf_finish(struct sbuf *s)
Definition: subr_sbuf.c:833
int sbuf_putc(struct sbuf *s, int c)
Definition: subr_sbuf.c:754
void sbuf_delete(struct sbuf *s)
Definition: subr_sbuf.c:898
int sbuf_printf(struct sbuf *s, const char *fmt,...)
Definition: subr_sbuf.c:739
void sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
Definition: subr_sbuf.c:376
struct sbuf * sbuf_new(struct sbuf *s, char *buf, int length, int flags)
Definition: subr_sbuf.c:196
int sbuf_cat(struct sbuf *s, const char *str)
Definition: subr_sbuf.c:566
struct stat * buf