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