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