rc.d/wg: Match wg ifnames on wg_start
[dragonfly.git] / sys / kern / subr_module.c
1 /*-
2  * Copyright (c) 1998 Michael Smith
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/kern/subr_module.c,v 1.6 1999/10/11 15:19:10 peter Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker.h>
32 #include <sys/sbuf.h>
33 #include <sys/sysctl.h>
34
35 #include <machine/metadata.h>
36
37 /*
38  * Preloaded module support
39  */
40
41 caddr_t preload_metadata;
42
43 /*
44  * Search for the preloaded module (name)
45  */
46 caddr_t
47 preload_search_by_name(const char *name)
48 {
49     caddr_t     curp;
50     u_int32_t   *hdr;
51     int         next;
52     int         i;
53     char        *scanname;
54
55     if (preload_metadata == NULL)
56         return(NULL);
57
58     curp = preload_metadata;
59     for (;;) {
60         hdr = (u_int32_t *)curp;
61         if (hdr[0] == 0 && hdr[1] == 0)
62             break;
63
64         /*
65          * Search for a MODINFO_NAME field.  the boot loader really
66          * ought to strip the path names
67          */
68         if (hdr[0] == MODINFO_NAME) {
69             scanname = curp + sizeof(u_int32_t) * 2;
70             i = strlen(scanname);
71             while (i > 0 && scanname[i-1] != '/')
72                 --i;
73             if (strcmp(name, scanname) == 0)
74                 return(curp);
75             if (strcmp(name, scanname + i) == 0)
76                 return(curp);
77         }
78         /* skip to next field */
79         next = sizeof(u_int32_t) * 2 + hdr[1];
80         next = roundup(next, sizeof(u_long));
81         curp += next;
82     }
83     return(NULL);
84 }
85
86 /*
87  * Search for the first preloaded module of (type)
88  */
89 caddr_t
90 preload_search_by_type(const char *type)
91 {
92     caddr_t     curp, lname;
93     u_int32_t   *hdr;
94     int         next;
95
96     if (preload_metadata != NULL) {
97
98         curp = preload_metadata;
99         lname = NULL;
100         for (;;) {
101             hdr = (u_int32_t *)curp;
102             if (hdr[0] == 0 && hdr[1] == 0)
103                 break;
104
105             /* remember the start of each record */
106             if (hdr[0] == MODINFO_NAME)
107                 lname = curp;
108
109             /* Search for a MODINFO_TYPE field */
110             if ((hdr[0] == MODINFO_TYPE) &&
111                 !strcmp(type, curp + sizeof(u_int32_t) * 2))
112                 return(lname);
113
114             /* skip to next field */
115             next = sizeof(u_int32_t) * 2 + hdr[1];
116             next = roundup(next, sizeof(u_long));
117             curp += next;
118         }
119     }
120     return(NULL);
121 }
122
123 /*
124  * Walk through the preloaded module list
125  */
126 caddr_t
127 preload_search_next_name(caddr_t base)
128 {
129     caddr_t     curp;
130     u_int32_t   *hdr;
131     int         next;
132
133     if (preload_metadata != NULL) {
134
135         /* Pick up where we left off last time */
136         if (base) {
137             /* skip to next field */
138             curp = base;
139             hdr = (u_int32_t *)curp;
140             next = sizeof(u_int32_t) * 2 + hdr[1];
141             next = roundup(next, sizeof(u_long));
142             curp += next;
143         } else
144             curp = preload_metadata;
145
146         for (;;) {
147             hdr = (u_int32_t *)curp;
148             if (hdr[0] == 0 && hdr[1] == 0)
149                 break;
150
151             /* Found a new record? */
152             if (hdr[0] == MODINFO_NAME)
153                 return curp;
154
155             /* skip to next field */
156             next = sizeof(u_int32_t) * 2 + hdr[1];
157             next = roundup(next, sizeof(u_long));
158             curp += next;
159         }
160     }
161     return(NULL);
162 }
163
164 /*
165  * Given a preloaded module handle (mod), return a pointer
166  * to the data for the attribute (inf).
167  */
168 caddr_t
169 preload_search_info(caddr_t mod, int inf)
170 {
171     caddr_t     curp;
172     u_int32_t   *hdr;
173     u_int32_t   type = 0;
174     int         next;
175
176     curp = mod;
177     for (;;) {
178         hdr = (u_int32_t *)curp;
179         /* end of module data? */
180         if (hdr[0] == 0 && hdr[1] == 0)
181             break;
182         /*
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.
185          */
186         if (type == 0) {
187             type = hdr[0];
188         } else {
189             if (hdr[0] == type)
190                 break;
191         }
192
193         /*
194          * Attribute match? Return pointer to data.
195          * Consumer may safely assume that size value preceeds
196          * data.
197          */
198         if (hdr[0] == inf)
199             return(curp + (sizeof(u_int32_t) * 2));
200
201         /* skip to next field */
202         next = sizeof(u_int32_t) * 2 + hdr[1];
203         next = roundup(next, sizeof(u_long));
204         curp += next;
205     }
206     return(NULL);
207 }
208
209 /*
210  * Delete a preload record by path name.
211  */
212 void
213 preload_delete_name(const char *name)
214 {
215     caddr_t     curp;
216     u_int32_t   *hdr;
217     int         next;
218     int         clearing;
219
220     if (preload_metadata != NULL) {
221         clearing = 0;
222         curp = preload_metadata;
223         for (;;) {
224             hdr = (u_int32_t *)curp;
225             if (hdr[0] == 0 && hdr[1] == 0)
226                 break;
227
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 */
232                 else if (clearing)
233                     clearing = 0;       /* at next module now, stop clearing */
234             }
235             if (clearing)
236                 hdr[0] = MODINFO_EMPTY;
237
238             /* skip to next field */
239             next = sizeof(u_int32_t) * 2 + hdr[1];
240             next = roundup(next, sizeof(u_long));
241             curp += next;
242         }
243     }
244 }
245
246 /* Called from hammer_time() on pc64.  Convert physical pointers to kvm. Sigh. */
247 void
248 preload_bootstrap_relocate(vm_offset_t offset)
249 {
250     caddr_t     curp;
251     u_int32_t   *hdr;
252     vm_offset_t *ptr;
253     int         next;
254
255     if (preload_metadata != NULL) {
256
257         curp = preload_metadata;
258         for (;;) {
259             hdr = (u_int32_t *)curp;
260             if (hdr[0] == 0 && hdr[1] == 0)
261                 break;
262
263             /* Deal with the ones that we know we have to fix */
264             switch (hdr[0]) {
265             case MODINFO_ADDR:
266             case MODINFO_METADATA|MODINFOMD_SSYM:
267             case MODINFO_METADATA|MODINFOMD_ESYM:
268                 ptr = (vm_offset_t *)(curp + (sizeof(u_int32_t) * 2));
269                 *ptr += offset;
270                 break;
271             }
272             /* The rest is beyond us for now */
273
274             /* skip to next field */
275             next = sizeof(u_int32_t) * 2 + hdr[1];
276             next = roundup(next, sizeof(u_long));
277             curp += next;
278         }
279     }
280 }
281
282 /*
283  * Parse the modinfo type and append to the sbuf.
284  */
285 static void
286 preload_modinfo_type(struct sbuf *sbp, int type)
287 {
288     if ((type & MODINFO_METADATA) == 0) {
289         switch (type) {
290         case MODINFO_END:
291             sbuf_cat(sbp, "MODINFO_END");
292             break;
293         case MODINFO_NAME:
294             sbuf_cat(sbp, "MODINFO_NAME");
295             break;
296         case MODINFO_TYPE:
297             sbuf_cat(sbp, "MODINFO_TYPE");
298             break;
299         case MODINFO_ADDR:
300             sbuf_cat(sbp, "MODINFO_ADDR");
301             break;
302         case MODINFO_SIZE:
303             sbuf_cat(sbp, "MODINFO_SIZE");
304             break;
305         case MODINFO_EMPTY:
306             sbuf_cat(sbp, "MODINFO_EMPTY");
307             break;
308         case MODINFO_ARGS:
309             sbuf_cat(sbp, "MODINFO_ARGS");
310             break;
311         default:
312             sbuf_cat(sbp, "unrecognized modinfo attribute");
313         }
314
315         return;
316     }
317
318     sbuf_cat(sbp, "MODINFO_METADATA | ");
319     switch (type & ~MODINFO_METADATA) {
320     case MODINFOMD_ELFHDR:
321         sbuf_cat(sbp, "MODINFOMD_ELFHDR");
322         break;
323     case MODINFOMD_SSYM:
324         sbuf_cat(sbp, "MODINFOMD_SSYM");
325         break;
326     case MODINFOMD_ESYM:
327         sbuf_cat(sbp, "MODINFOMD_ESYM");
328         break;
329     case MODINFOMD_DYNAMIC:
330         sbuf_cat(sbp, "MODINFOMD_DYNAMIC");
331         break;
332     case MODINFOMD_ENVP:
333         sbuf_cat(sbp, "MODINFOMD_ENVP");
334         break;
335     case MODINFOMD_HOWTO:
336         sbuf_cat(sbp, "MODINFOMD_HOWTO");
337         break;
338     case MODINFOMD_KERNEND:
339         sbuf_cat(sbp, "MODINFOMD_KERNEND");
340         break;
341     case MODINFOMD_SHDR:
342         sbuf_cat(sbp, "MODINFOMD_SHDR");
343         break;
344     case MODINFOMD_FW_HANDLE:
345         sbuf_cat(sbp, "MODINFOMD_FW_HANDLE");
346         break;
347     case MODINFOMD_SMAP:
348         sbuf_cat(sbp, "MODINFOMD_SMAP");
349         break;
350     case MODINFOMD_EFI_MAP:
351         sbuf_cat(sbp, "MODINFOMD_EFI_MAP");
352         break;
353     case MODINFOMD_EFI_FB:
354         sbuf_cat(sbp, "MODINFOMD_EFI_FB");
355         break;
356     default:
357         sbuf_cat(sbp, "unrecognized metadata type");
358     }
359 }
360
361 /*
362  * Print the modinfo value, depending on type.
363  */
364 static void
365 preload_modinfo_value(struct sbuf *sbp, uint32_t *bptr, int type, int len)
366 {
367     switch (type) {
368     case MODINFO_NAME:
369     case MODINFO_TYPE:
370     case MODINFO_ARGS:
371         sbuf_printf(sbp, "%s", (char *)bptr);
372         break;
373     case MODINFO_SIZE:
374         sbuf_printf(sbp, "%lu", *(u_long *)bptr);
375         break;
376     case MODINFO_ADDR:
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);
385         break;
386     case MODINFO_METADATA | MODINFOMD_HOWTO:
387         sbuf_printf(sbp, "0x%08x", *bptr);
388         break;
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");
395         break;
396     default:
397         break;
398     }
399 }
400
401 static void
402 preload_dump_internal(struct sbuf *sbp)
403 {
404     uint32_t *bptr, type, len;
405
406     sbuf_putc(sbp, '\n');
407
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);
412
413         type = *bptr++;
414         sbuf_printf(sbp, "\ttype:\t(%#04x) ", type);
415         preload_modinfo_type(sbp, type);
416         sbuf_putc(sbp, '\n');
417
418         len = *bptr++;
419         sbuf_printf(sbp, "\tlen:\t%u\n", len);
420
421         sbuf_cat(sbp, "\tvalue:\t");
422         preload_modinfo_value(sbp, bptr, type, len);
423         sbuf_putc(sbp, '\n');
424
425         bptr += roundup(len, sizeof(u_long)) / sizeof(uint32_t);
426     }
427 }
428
429 static int
430 sysctl_preload_dump(SYSCTL_HANDLER_ARGS)
431 {
432     struct sbuf sb;
433     int error;
434
435     if (preload_metadata == NULL)
436         return (EINVAL);
437
438     sbuf_new_for_sysctl(&sb, NULL, 512, req);
439     preload_dump_internal(&sb);
440
441     error = sbuf_finish(&sb);
442     sbuf_delete(&sb);
443
444     return (error);
445 }
446
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");