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