2 * Copyright (c) 1998 Michael Smith
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
33 #include <sys/sysctl.h>
35 #include <machine/metadata.h>
38 * Preloaded module support
41 caddr_t preload_metadata
;
44 * Search for the preloaded module (name)
47 preload_search_by_name(const char *name
)
55 if (preload_metadata
== NULL
)
58 curp
= preload_metadata
;
60 hdr
= (u_int32_t
*)curp
;
61 if (hdr
[0] == 0 && hdr
[1] == 0)
65 * Search for a MODINFO_NAME field. the boot loader really
66 * ought to strip the path names
68 if (hdr
[0] == MODINFO_NAME
) {
69 scanname
= curp
+ sizeof(u_int32_t
) * 2;
71 while (i
> 0 && scanname
[i
-1] != '/')
73 if (strcmp(name
, scanname
) == 0)
75 if (strcmp(name
, scanname
+ i
) == 0)
78 /* skip to next field */
79 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
80 next
= roundup(next
, sizeof(u_long
));
87 * Search for the first preloaded module of (type)
90 preload_search_by_type(const char *type
)
96 if (preload_metadata
!= NULL
) {
98 curp
= preload_metadata
;
101 hdr
= (u_int32_t
*)curp
;
102 if (hdr
[0] == 0 && hdr
[1] == 0)
105 /* remember the start of each record */
106 if (hdr
[0] == MODINFO_NAME
)
109 /* Search for a MODINFO_TYPE field */
110 if ((hdr
[0] == MODINFO_TYPE
) &&
111 !strcmp(type
, curp
+ sizeof(u_int32_t
) * 2))
114 /* skip to next field */
115 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
116 next
= roundup(next
, sizeof(u_long
));
124 * Walk through the preloaded module list
127 preload_search_next_name(caddr_t base
)
133 if (preload_metadata
!= NULL
) {
135 /* Pick up where we left off last time */
137 /* skip to next field */
139 hdr
= (u_int32_t
*)curp
;
140 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
141 next
= roundup(next
, sizeof(u_long
));
144 curp
= preload_metadata
;
147 hdr
= (u_int32_t
*)curp
;
148 if (hdr
[0] == 0 && hdr
[1] == 0)
151 /* Found a new record? */
152 if (hdr
[0] == MODINFO_NAME
)
155 /* skip to next field */
156 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
157 next
= roundup(next
, sizeof(u_long
));
165 * Given a preloaded module handle (mod), return a pointer
166 * to the data for the attribute (inf).
169 preload_search_info(caddr_t mod
, int inf
)
178 hdr
= (u_int32_t
*)curp
;
179 /* end of module data? */
180 if (hdr
[0] == 0 && hdr
[1] == 0)
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.
194 * Attribute match? Return pointer to data.
195 * Consumer may safely assume that size value preceeds
199 return(curp
+ (sizeof(u_int32_t
) * 2));
201 /* skip to next field */
202 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
203 next
= roundup(next
, sizeof(u_long
));
210 * Delete a preload record by path name.
213 preload_delete_name(const char *name
)
220 if (preload_metadata
!= NULL
) {
222 curp
= preload_metadata
;
224 hdr
= (u_int32_t
*)curp
;
225 if (hdr
[0] == 0 && hdr
[1] == 0)
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 */
233 clearing
= 0; /* at next module now, stop clearing */
236 hdr
[0] = MODINFO_EMPTY
;
238 /* skip to next field */
239 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
240 next
= roundup(next
, sizeof(u_long
));
246 /* Called from hammer_time() on pc64. Convert physical pointers to kvm. Sigh. */
248 preload_bootstrap_relocate(vm_offset_t offset
)
255 if (preload_metadata
!= NULL
) {
257 curp
= preload_metadata
;
259 hdr
= (u_int32_t
*)curp
;
260 if (hdr
[0] == 0 && hdr
[1] == 0)
263 /* Deal with the ones that we know we have to fix */
266 case MODINFO_METADATA
|MODINFOMD_SSYM
:
267 case MODINFO_METADATA
|MODINFOMD_ESYM
:
268 ptr
= (vm_offset_t
*)(curp
+ (sizeof(u_int32_t
) * 2));
272 /* The rest is beyond us for now */
274 /* skip to next field */
275 next
= sizeof(u_int32_t
) * 2 + hdr
[1];
276 next
= roundup(next
, sizeof(u_long
));
283 * Parse the modinfo type and append to the sbuf.
286 preload_modinfo_type(struct sbuf
*sbp
, int type
)
288 if ((type
& MODINFO_METADATA
) == 0) {
291 sbuf_cat(sbp
, "MODINFO_END");
294 sbuf_cat(sbp
, "MODINFO_NAME");
297 sbuf_cat(sbp
, "MODINFO_TYPE");
300 sbuf_cat(sbp
, "MODINFO_ADDR");
303 sbuf_cat(sbp
, "MODINFO_SIZE");
306 sbuf_cat(sbp
, "MODINFO_EMPTY");
309 sbuf_cat(sbp
, "MODINFO_ARGS");
312 sbuf_cat(sbp
, "unrecognized modinfo attribute");
318 sbuf_cat(sbp
, "MODINFO_METADATA | ");
319 switch (type
& ~MODINFO_METADATA
) {
320 case MODINFOMD_ELFHDR
:
321 sbuf_cat(sbp
, "MODINFOMD_ELFHDR");
324 sbuf_cat(sbp
, "MODINFOMD_SSYM");
327 sbuf_cat(sbp
, "MODINFOMD_ESYM");
329 case MODINFOMD_DYNAMIC
:
330 sbuf_cat(sbp
, "MODINFOMD_DYNAMIC");
333 sbuf_cat(sbp
, "MODINFOMD_ENVP");
335 case MODINFOMD_HOWTO
:
336 sbuf_cat(sbp
, "MODINFOMD_HOWTO");
338 case MODINFOMD_KERNEND
:
339 sbuf_cat(sbp
, "MODINFOMD_KERNEND");
342 sbuf_cat(sbp
, "MODINFOMD_SHDR");
344 case MODINFOMD_FW_HANDLE
:
345 sbuf_cat(sbp
, "MODINFOMD_FW_HANDLE");
348 sbuf_cat(sbp
, "MODINFOMD_SMAP");
350 case MODINFOMD_EFI_MAP
:
351 sbuf_cat(sbp
, "MODINFOMD_EFI_MAP");
353 case MODINFOMD_EFI_FB
:
354 sbuf_cat(sbp
, "MODINFOMD_EFI_FB");
357 sbuf_cat(sbp
, "unrecognized metadata type");
362 * Print the modinfo value, depending on type.
365 preload_modinfo_value(struct sbuf
*sbp
, uint32_t *bptr
, int type
, int len
)
371 sbuf_printf(sbp
, "%s", (char *)bptr
);
374 sbuf_printf(sbp
, "%lu", *(u_long
*)bptr
);
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
);
386 case MODINFO_METADATA
| MODINFOMD_HOWTO
:
387 sbuf_printf(sbp
, "0x%08x", *bptr
);
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");
402 preload_dump_internal(struct sbuf
*sbp
)
404 uint32_t *bptr
, type
, len
;
406 sbuf_putc(sbp
, '\n');
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
);
414 sbuf_printf(sbp
, "\ttype:\t(%#04x) ", type
);
415 preload_modinfo_type(sbp
, type
);
416 sbuf_putc(sbp
, '\n');
419 sbuf_printf(sbp
, "\tlen:\t%u\n", len
);
421 sbuf_cat(sbp
, "\tvalue:\t");
422 preload_modinfo_value(sbp
, bptr
, type
, len
);
423 sbuf_putc(sbp
, '\n');
425 bptr
+= roundup(len
, sizeof(u_long
)) / sizeof(uint32_t);
430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS
)
435 if (preload_metadata
== NULL
)
438 sbuf_new_for_sysctl(&sb
, NULL
, 512, req
);
439 preload_dump_internal(&sb
);
441 error
= sbuf_finish(&sb
);
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");