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");