]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_module.c
usb(4): Remove a double word in a source code comment
[FreeBSD/FreeBSD.git] / sys / kern / subr_module.c
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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");