Unleashed v1.4
[unleashed.git] / usr / src / boot / sys / boot / common / module.c
blob220e30218c5c8433c2946311b70b3d02234d5957
1 /*
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
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.
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.
27 #include <sys/cdefs.h>
30 * file/module function dispatcher, support, etc.
33 #include <stand.h>
34 #include <string.h>
35 #include <sys/param.h>
36 #include <sys/linker.h>
37 #include <sys/module.h>
38 #include <sys/queue.h>
39 #include <sys/stdint.h>
40 #include <sys/tem_impl.h>
41 #include <sys/font.h>
42 #include <sys/sha1.h>
44 #include "bootstrap.h"
46 #if defined(EFI)
47 #define PTOV(pa) ((void *)pa)
48 #else
49 #include "../i386/btx/lib/btxv86.h"
50 #endif
52 #define MDIR_REMOVED 0x0001
53 #define MDIR_NOHINTS 0x0002
55 struct moduledir {
56 char *d_path; /* path of modules directory */
57 u_char *d_hints; /* content of linker.hints file */
58 int d_hintsz; /* size of hints data */
59 int d_flags;
60 STAILQ_ENTRY(moduledir) d_link;
63 static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
64 static int file_load_dependencies(struct preloaded_file *base_mod);
65 static char * file_search(const char *name, const char **extlist);
66 static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
67 static int file_havepath(const char *name);
68 static char *mod_searchmodule(char *name, struct mod_depend *verinfo);
69 static void file_insert_tail(struct preloaded_file *mp);
70 struct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
71 static void moduledir_readhints(struct moduledir *mdp);
72 static void moduledir_rebuild(void);
74 /* load address should be tweaked by first module loaded (kernel) */
75 static vm_offset_t loadaddr = 0;
77 #if defined(LOADER_FDT_SUPPORT)
78 static const char *default_searchpath =
79 "/boot/kernel;/boot/modules;/boot/dtb";
80 #else
81 static const char *default_searchpath ="/platform";
82 #endif
84 static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
86 struct preloaded_file *preloaded_files = NULL;
88 static const char *kld_ext_list[] = {
89 ".ko",
90 "",
91 ".debug",
92 NULL
97 * load an object, either a disk file or code module.
99 * To load a file, the syntax is:
101 * load -t <type> <path>
103 * code modules are loaded as:
105 * load <path> <options>
108 COMMAND_SET(load, "load", "load a kernel or module", command_load);
110 static int
111 command_load(int argc, char *argv[])
113 char *typestr;
114 int dofile, dokld, ch, error;
116 dokld = dofile = 0;
117 optind = 1;
118 optreset = 1;
119 typestr = NULL;
120 if (argc == 1) {
121 command_errmsg = "no filename specified";
122 return (CMD_CRIT);
124 while ((ch = getopt(argc, argv, "kt:")) != -1) {
125 switch(ch) {
126 case 'k':
127 dokld = 1;
128 break;
129 case 't':
130 typestr = optarg;
131 dofile = 1;
132 break;
133 case '?':
134 default:
135 /* getopt has already reported an error */
136 return (CMD_OK);
139 argv += (optind - 1);
140 argc -= (optind - 1);
142 printf("Loading %s...\n", argv[1]);
144 * Request to load a raw file?
146 if (dofile) {
147 if ((typestr == NULL) || (*typestr == 0)) {
148 command_errmsg = "invalid load type";
149 return (CMD_CRIT);
152 if (file_findfile(argv[1], typestr) != NULL) {
153 snprintf(command_errbuf, sizeof (command_errbuf),
154 "warning: file '%s' already loaded", argv[1]);
155 return (CMD_WARN);
158 if (file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1) != NULL)
159 return (CMD_OK);
161 /* Failing to load mfs_root is never going to end well! */
162 if (strcmp("mfs_root", typestr) == 0)
163 return (CMD_FATAL);
165 return (CMD_ERROR);
168 * Do we have explicit KLD load ?
170 if (dokld || file_havepath(argv[1])) {
171 error = mod_loadkld(argv[1], argc - 2, argv + 2);
172 if (error == EEXIST) {
173 snprintf(command_errbuf, sizeof (command_errbuf),
174 "warning: KLD '%s' already loaded", argv[1]);
175 return (CMD_WARN);
178 return (error == 0 ? CMD_OK : CMD_CRIT);
181 * Looks like a request for a module.
183 error = mod_load(argv[1], NULL, argc - 2, argv + 2);
184 if (error == EEXIST) {
185 snprintf(command_errbuf, sizeof (command_errbuf),
186 "warning: module '%s' already loaded", argv[1]);
187 return (CMD_WARN);
190 return (error == 0 ? CMD_OK : CMD_CRIT);
193 #ifdef __FreeBSD__
194 COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
196 static int
197 command_load_geli(int argc, char *argv[])
199 char typestr[80];
200 char *cp;
201 int ch, num;
203 if (argc < 3) {
204 command_errmsg = "usage is [-n key#] <prov> <file>";
205 return(CMD_ERROR);
208 num = 0;
209 optind = 1;
210 optreset = 1;
211 while ((ch = getopt(argc, argv, "n:")) != -1) {
212 switch(ch) {
213 case 'n':
214 num = strtol(optarg, &cp, 0);
215 if (cp == optarg) {
216 snprintf(command_errbuf, sizeof (command_errbuf),
217 "bad key index '%s'", optarg);
218 return(CMD_ERROR);
220 break;
221 case '?':
222 default:
223 /* getopt has already reported an error */
224 return(CMD_OK);
227 argv += (optind - 1);
228 argc -= (optind - 1);
229 sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
230 return (file_loadraw(argv[2], typestr, 0, NULL, 1) ? CMD_OK : CMD_ERROR);
232 #endif /* __FreeBSD__ */
234 void
235 unload(void)
237 struct preloaded_file *fp;
239 while (preloaded_files != NULL) {
240 fp = preloaded_files;
241 preloaded_files = preloaded_files->f_next;
242 file_discard(fp);
244 loadaddr = 0;
245 unsetenv("kernelname");
248 COMMAND_SET(unload, "unload", "unload all modules", command_unload);
250 static int
251 command_unload(int argc __attribute((unused)),
252 char *argv[] __attribute((unused)))
254 unload();
255 return(CMD_OK);
258 COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
260 static int
261 command_lsmod(int argc, char *argv[])
263 struct preloaded_file *fp;
264 struct kernel_module *mp;
265 struct file_metadata *md;
266 char lbuf[80];
267 int ch, verbose, hash, ret = 0;
269 verbose = 0;
270 hash = 0;
271 optind = 1;
272 optreset = 1;
273 while ((ch = getopt(argc, argv, "vs")) != -1) {
274 switch(ch) {
275 case 'v':
276 verbose = 1;
277 break;
278 case 's':
279 hash = 1;
280 break;
281 case '?':
282 default:
283 /* getopt has already reported an error */
284 return(CMD_OK);
288 pager_open();
289 for (fp = preloaded_files; fp; fp = fp->f_next) {
290 sprintf(lbuf, " %p: ", (void *) fp->f_addr);
291 pager_output(lbuf);
292 pager_output(fp->f_name);
293 sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size);
294 if (pager_output(lbuf))
295 break;
296 if (fp->f_args != NULL) {
297 pager_output(" args: ");
298 pager_output(fp->f_args);
299 if (pager_output("\n"))
300 break;
301 if (strcmp(fp->f_type, "hash") == 0) {
302 pager_output(" contents: ");
303 strncpy(lbuf, PTOV(fp->f_addr), fp->f_size);
304 if (pager_output(lbuf))
305 break;
309 if (hash == 1) {
310 void *ptr = PTOV(fp->f_addr);
312 pager_output(" hash: ");
313 sha1(ptr, fp->f_size, (uint8_t *)lbuf);
314 for (int i = 0; i < SHA1_DIGEST_LENGTH; i++)
315 printf("%02x", (int)(lbuf[i] & 0xff));
316 if (pager_output("\n"))
317 break;
320 if (fp->f_modules) {
321 pager_output(" modules: ");
322 for (mp = fp->f_modules; mp; mp = mp->m_next) {
323 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
324 pager_output(lbuf);
326 if (pager_output("\n"))
327 break;
329 if (verbose) {
330 /* XXX could add some formatting smarts here to display some better */
331 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
332 sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
333 if ((ret = pager_output(lbuf)))
334 break;
337 if (ret)
338 break;
340 pager_close();
341 return(CMD_OK);
345 * File level interface, functions file_*
348 file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
350 static int last_file_format = 0;
351 struct preloaded_file *fp;
352 int error;
353 int i;
355 if (preloaded_files == NULL)
356 last_file_format = 0;
358 if (archsw.arch_loadaddr != NULL)
359 dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
361 error = EFTYPE;
362 for (i = last_file_format, fp = NULL;
363 file_formats[i] && fp == NULL; i++) {
364 error = (file_formats[i]->l_load)(filename, dest, &fp);
365 if (error == 0) {
366 fp->f_loader = last_file_format = i; /* remember the loader */
367 *result = fp;
368 break;
369 } else if (last_file_format == i && i != 0) {
370 /* Restart from the beginning */
371 i = -1;
372 last_file_format = 0;
373 fp = NULL;
374 continue;
376 if (error == EFTYPE)
377 continue; /* Unknown to this handler? */
378 if (error) {
379 snprintf(command_errbuf, sizeof (command_errbuf),
380 "can't load file '%s': %s", filename, strerror(error));
381 break;
384 return (error);
387 static int
388 file_load_dependencies(struct preloaded_file *base_file)
390 struct file_metadata *md;
391 struct preloaded_file *fp;
392 struct mod_depend *verinfo;
393 struct kernel_module *mp;
394 char *dmodname;
395 int error;
397 md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
398 if (md == NULL)
399 return (0);
400 error = 0;
401 do {
402 verinfo = (struct mod_depend*)md->md_data;
403 dmodname = (char *)(verinfo + 1);
404 if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
405 printf("loading required module '%s'\n", dmodname);
406 error = mod_load(dmodname, verinfo, 0, NULL);
407 if (error)
408 break;
410 * If module loaded via kld name which isn't listed
411 * in the linker.hints file, we should check if it have
412 * required version.
414 mp = file_findmodule(NULL, dmodname, verinfo);
415 if (mp == NULL) {
416 snprintf(command_errbuf, sizeof (command_errbuf),
417 "module '%s' exists but with wrong version", dmodname);
418 error = ENOENT;
419 break;
422 md = metadata_next(md, MODINFOMD_DEPLIST);
423 } while (md);
424 if (!error)
425 return (0);
426 /* Load failed; discard everything */
427 while (base_file != NULL) {
428 fp = base_file;
429 base_file = base_file->f_next;
430 file_discard(fp);
432 return (error);
436 * Calculate the size of the environment module.
437 * The environment is list of name=value C strings, ending with a '\0' byte.
439 static size_t
440 env_get_size(void)
442 size_t size = 0;
443 struct env_var *ep;
445 /* Traverse the environment. */
446 for (ep = environ; ep != NULL; ep = ep->ev_next) {
447 size += strlen(ep->ev_name);
448 size++; /* "=" */
449 if (ep->ev_value != NULL)
450 size += strlen(ep->ev_value);
451 size++; /* nul byte */
453 size++; /* nul byte */
454 return (size);
457 static void
458 module_hash(struct preloaded_file *fp, void *addr, size_t size)
460 uint8_t hash[SHA1_DIGEST_LENGTH];
461 char ascii[2 * SHA1_DIGEST_LENGTH + 1];
462 int i;
464 sha1(addr, size, hash);
465 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
466 snprintf(ascii + 2 * i, sizeof (ascii) - 2 * i, "%02x",
467 hash[i] & 0xff);
469 /* Out of memory here is not fatal issue. */
470 asprintf(&fp->f_args, "hash=%s", ascii);
474 * Create virtual module for environment variables.
475 * This module should be created as late as possible before executing
476 * the OS kernel, or we may miss some environment variable updates.
478 void
479 build_environment_module(void)
481 struct preloaded_file *fp;
482 size_t size;
483 char *name = "environment";
484 vm_offset_t laddr;
486 /* We can't load first */
487 if ((file_findfile(NULL, NULL)) == NULL) {
488 printf("Can not load environment module: %s\n",
489 "the kernel is not loaded");
490 return;
493 tem_save_state(); /* Ask tem to save it's state in env. */
494 size = env_get_size();
496 fp = file_alloc();
497 if (fp != NULL) {
498 fp->f_name = strdup(name);
499 fp->f_type = strdup(name);
502 if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
503 printf("Can not load environment module: %s\n",
504 "out of memory");
505 if (fp != NULL)
506 file_discard(fp);
507 return;
511 if (archsw.arch_loadaddr != NULL)
512 loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
514 if (loadaddr == 0) {
515 printf("Can not load environment module: %s\n",
516 "out of memory");
517 file_discard(fp);
518 return;
521 laddr = bi_copyenv(loadaddr);
522 /* Looks OK so far; populate control structure */
523 module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
524 fp->f_loader = -1;
525 fp->f_addr = loadaddr;
526 fp->f_size = laddr - loadaddr;
528 /* recognise space consumption */
529 loadaddr = laddr;
531 file_insert_tail(fp);
534 void
535 build_font_module(void)
537 bitmap_data_t *bd;
538 struct font *fd;
539 struct preloaded_file *fp;
540 size_t size;
541 uint32_t checksum;
542 int i;
543 char *name = "console-font";
544 vm_offset_t laddr;
545 struct font_info fi;
546 struct fontlist *fl;
548 if (STAILQ_EMPTY(&fonts))
549 return;
551 /* We can't load first */
552 if ((file_findfile(NULL, NULL)) == NULL) {
553 printf("Can not load font module: %s\n",
554 "the kernel is not loaded");
555 return;
558 /* helper pointers */
559 bd = NULL;
560 STAILQ_FOREACH(fl, &fonts, font_next) {
561 if (fl->font_data->font != NULL) {
562 bd = fl->font_data;
563 break;
566 if (bd == NULL)
567 return;
568 fd = bd->font;
570 fi.fi_width = fd->vf_width;
571 checksum = fi.fi_width;
572 fi.fi_height = fd->vf_height;
573 checksum += fi.fi_height;
574 fi.fi_bitmap_size = bd->uncompressed_size;
575 checksum += fi.fi_bitmap_size;
577 size = roundup2(sizeof (struct font_info), 8);
578 for (i = 0; i < VFNT_MAPS; i++) {
579 fi.fi_map_count[i] = fd->vf_map_count[i];
580 checksum += fi.fi_map_count[i];
581 size += fd->vf_map_count[i] * sizeof (struct font_map);
582 size += roundup2(size, 8);
584 size += bd->uncompressed_size;
586 fi.fi_checksum = -checksum;
588 fp = file_alloc();
589 if (fp != NULL) {
590 fp->f_name = strdup(name);
591 fp->f_type = strdup(name);
594 if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
595 printf("Can not load font module: %s\n",
596 "out of memory");
597 if (fp != NULL)
598 file_discard(fp);
599 return;
602 if (archsw.arch_loadaddr != NULL)
603 loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
605 if (loadaddr == 0) {
606 printf("Can not load font module: %s\n",
607 "out of memory");
608 file_discard(fp);
609 return;
612 laddr = loadaddr;
613 laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info));
614 laddr = roundup2(laddr, 8);
616 /* Copy maps. */
617 for (i = 0; i < VFNT_MAPS; i++) {
618 if (fd->vf_map_count[i] != 0) {
619 laddr += archsw.arch_copyin(fd->vf_map[i], laddr,
620 fd->vf_map_count[i] * sizeof (struct font_map));
621 laddr = roundup2(laddr, 8);
625 /* Copy the bitmap. */
626 laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size);
628 /* Looks OK so far; populate control structure */
629 module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
630 fp->f_loader = -1;
631 fp->f_addr = loadaddr;
632 fp->f_size = laddr - loadaddr;
634 /* recognise space consumption */
635 loadaddr = laddr;
637 file_insert_tail(fp);
641 * We've been asked to load (fname) as (type), so just suck it in,
642 * no arguments or anything.
644 struct preloaded_file *
645 file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
647 struct preloaded_file *fp;
648 char *name;
649 int fd, got;
650 vm_offset_t laddr;
651 struct stat st;
653 /* We can't load first */
654 if ((file_findfile(NULL, NULL)) == NULL) {
655 command_errmsg = "can't load file before kernel";
656 return(NULL);
659 /* locate the file on the load path */
660 name = file_search(fname, NULL);
661 if (name == NULL) {
662 snprintf(command_errbuf, sizeof (command_errbuf),
663 "can't find '%s'", fname);
664 return(NULL);
667 if ((fd = open(name, O_RDONLY)) < 0) {
668 snprintf(command_errbuf, sizeof (command_errbuf),
669 "can't open '%s': %s", name, strerror(errno));
670 free(name);
671 return(NULL);
673 if (fstat(fd, &st) < 0) {
674 close(fd);
675 snprintf(command_errbuf, sizeof (command_errbuf),
676 "stat error '%s': %s", name, strerror(errno));
677 free(name);
678 return(NULL);
681 if (archsw.arch_loadaddr != NULL)
682 loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
683 if (loadaddr == 0) {
684 close(fd);
685 snprintf(command_errbuf, sizeof (command_errbuf),
686 "no memory to load %s", name);
687 free(name);
688 return(NULL);
691 laddr = loadaddr;
692 for (;;) {
693 /* read in 4k chunks; size is not really important */
694 got = archsw.arch_readin(fd, laddr, 4096);
695 if (got == 0) /* end of file */
696 break;
697 if (got < 0) { /* error */
698 snprintf(command_errbuf, sizeof (command_errbuf),
699 "error reading '%s': %s", name, strerror(errno));
700 free(name);
701 close(fd);
702 if (archsw.arch_free_loadaddr != NULL)
703 archsw.arch_free_loadaddr(loadaddr,
704 (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12));
705 return(NULL);
707 laddr += got;
710 /* Looks OK so far; create & populate control structure */
711 fp = file_alloc();
712 fp->f_name = strdup(name);
713 fp->f_args = unargv(argc, argv);
714 fp->f_type = strdup(type);
715 fp->f_metadata = NULL;
716 fp->f_loader = -1;
717 fp->f_addr = loadaddr;
718 fp->f_size = laddr - loadaddr;
720 /* recognise space consumption */
721 loadaddr = laddr;
723 /* Add to the list of loaded files */
724 if (insert != 0)
725 file_insert_tail(fp);
726 close(fd);
727 return(fp);
731 * Load the module (name), pass it (argc),(argv), add container file
732 * to the list of loaded files.
733 * If module is already loaded just assign new argc/argv.
736 mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
738 struct kernel_module *mp;
739 int err;
740 char *filename;
742 if (file_havepath(modname)) {
743 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
744 return (mod_loadkld(modname, argc, argv));
746 /* see if module is already loaded */
747 mp = file_findmodule(NULL, modname, verinfo);
748 if (mp) {
749 if (mp->m_args)
750 free(mp->m_args);
751 mp->m_args = unargv(argc, argv);
752 snprintf(command_errbuf, sizeof (command_errbuf),
753 "warning: module '%s' already loaded", mp->m_name);
754 return (0);
756 /* locate file with the module on the search path */
757 filename = mod_searchmodule(modname, verinfo);
758 if (filename == NULL) {
759 snprintf(command_errbuf, sizeof (command_errbuf),
760 "can't find '%s'", modname);
761 return (ENOENT);
763 err = mod_loadkld(filename, argc, argv);
764 return (err);
768 * Load specified KLD. If path is omitted, then try to locate it via
769 * search path.
772 mod_loadkld(const char *kldname, int argc, char *argv[])
774 struct preloaded_file *fp, *last_file;
775 int err;
776 char *filename;
779 * Get fully qualified KLD name
781 filename = file_search(kldname, kld_ext_list);
782 if (filename == NULL) {
783 snprintf(command_errbuf, sizeof (command_errbuf),
784 "can't find '%s'", kldname);
785 return (ENOENT);
788 * Check if KLD already loaded
790 fp = file_findfile(filename, NULL);
791 if (fp) {
792 snprintf(command_errbuf, sizeof (command_errbuf),
793 "warning: KLD '%s' already loaded", filename);
794 free(filename);
795 return (0);
797 for (last_file = preloaded_files;
798 last_file != NULL && last_file->f_next != NULL;
799 last_file = last_file->f_next)
802 do {
803 err = file_load(filename, loadaddr, &fp);
804 if (err)
805 break;
806 fp->f_args = unargv(argc, argv);
807 loadaddr = fp->f_addr + fp->f_size;
808 file_insert_tail(fp); /* Add to the list of loaded files */
809 if (file_load_dependencies(fp) != 0) {
810 err = ENOENT;
811 last_file->f_next = NULL;
812 loadaddr = last_file->f_addr + last_file->f_size;
813 fp = NULL;
814 break;
816 } while(0);
817 if (err == EFTYPE) {
818 snprintf(command_errbuf, sizeof (command_errbuf),
819 "don't know how to load module '%s'", filename);
821 if (err && fp)
822 file_discard(fp);
823 free(filename);
824 return (err);
828 * Find a file matching (name) and (type).
829 * NULL may be passed as a wildcard to either.
831 struct preloaded_file *
832 file_findfile(const char *name, const char *type)
834 struct preloaded_file *fp;
836 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
837 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
838 ((type == NULL) || !strcmp(type, fp->f_type)))
839 break;
841 return (fp);
845 * Find a module matching (name) inside of given file.
846 * NULL may be passed as a wildcard.
848 struct kernel_module *
849 file_findmodule(struct preloaded_file *fp, char *modname,
850 struct mod_depend *verinfo)
852 struct kernel_module *mp, *best;
853 int bestver, mver;
855 if (fp == NULL) {
856 for (fp = preloaded_files; fp; fp = fp->f_next) {
857 mp = file_findmodule(fp, modname, verinfo);
858 if (mp)
859 return (mp);
861 return (NULL);
863 best = NULL;
864 bestver = 0;
865 for (mp = fp->f_modules; mp; mp = mp->m_next) {
866 if (strcmp(modname, mp->m_name) == 0) {
867 if (verinfo == NULL)
868 return (mp);
869 mver = mp->m_version;
870 if (mver == verinfo->md_ver_preferred)
871 return (mp);
872 if (mver >= verinfo->md_ver_minimum &&
873 mver <= verinfo->md_ver_maximum &&
874 mver > bestver) {
875 best = mp;
876 bestver = mver;
880 return (best);
883 * Make a copy of (size) bytes of data from (p), and associate them as
884 * metadata of (type) to the module (mp).
886 void
887 file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
889 struct file_metadata *md;
891 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
892 md->md_size = size;
893 md->md_type = type;
894 bcopy(p, md->md_data, size);
895 md->md_next = fp->f_metadata;
896 fp->f_metadata = md;
900 * Find a metadata object of (type) associated with the file (fp)
902 struct file_metadata *
903 file_findmetadata(struct preloaded_file *fp, int type)
905 struct file_metadata *md;
907 for (md = fp->f_metadata; md != NULL; md = md->md_next)
908 if (md->md_type == type)
909 break;
910 return(md);
913 struct file_metadata *
914 metadata_next(struct file_metadata *md, int type)
916 if (md == NULL)
917 return (NULL);
918 while((md = md->md_next) != NULL)
919 if (md->md_type == type)
920 break;
921 return (md);
924 static const char *emptyextlist[] = { "", NULL };
927 * Check if the given file is in place and return full path to it.
929 static char *
930 file_lookup(const char *path, const char *name, int namelen, const char **extlist)
932 struct stat st;
933 char *result, *cp;
934 const char **cpp;
935 int pathlen, extlen, len;
937 pathlen = strlen(path);
938 extlen = 0;
939 if (extlist == NULL)
940 extlist = emptyextlist;
941 for (cpp = extlist; *cpp; cpp++) {
942 len = strlen(*cpp);
943 if (len > extlen)
944 extlen = len;
946 result = malloc(pathlen + namelen + extlen + 2);
947 if (result == NULL)
948 return (NULL);
949 bcopy(path, result, pathlen);
950 if (pathlen > 0 && result[pathlen - 1] != '/')
951 result[pathlen++] = '/';
952 cp = result + pathlen;
953 bcopy(name, cp, namelen);
954 cp += namelen;
955 for (cpp = extlist; *cpp; cpp++) {
956 strcpy(cp, *cpp);
957 if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
958 return result;
960 free(result);
961 return NULL;
965 * Check if file name have any qualifiers
967 static int
968 file_havepath(const char *name)
970 const char *cp;
972 archsw.arch_getdev(NULL, name, &cp);
973 return (cp != name || strchr(name, '/') != NULL);
977 * Attempt to find the file (name) on the module searchpath.
978 * If (name) is qualified in any way, we simply check it and
979 * return it or NULL. If it is not qualified, then we attempt
980 * to construct a path using entries in the environment variable
981 * module_path.
983 * The path we return a pointer to need never be freed, as we manage
984 * it internally.
986 static char *
987 file_search(const char *name, const char **extlist)
989 struct moduledir *mdp;
990 struct stat sb;
991 char *result;
992 int namelen;
994 /* Don't look for nothing */
995 if (name == NULL)
996 return(NULL);
998 if (*name == 0)
999 return(strdup(name));
1001 if (file_havepath(name)) {
1002 /* Qualified, so just see if it exists */
1003 if (stat(name, &sb) == 0)
1004 return(strdup(name));
1005 return(NULL);
1007 moduledir_rebuild();
1008 result = NULL;
1009 namelen = strlen(name);
1010 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1011 result = file_lookup(mdp->d_path, name, namelen, extlist);
1012 if (result)
1013 break;
1015 return(result);
1018 #define INT_ALIGN(base, ptr) ptr = \
1019 (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
1021 static char *
1022 mod_search_hints(struct moduledir *mdp, const char *modname,
1023 struct mod_depend *verinfo)
1025 u_char *cp, *recptr, *bufend, *best;
1026 char *result;
1027 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
1029 moduledir_readhints(mdp);
1030 modnamelen = strlen(modname);
1031 found = 0;
1032 result = NULL;
1033 bestver = 0;
1034 if (mdp->d_hints == NULL)
1035 goto bad;
1036 recptr = mdp->d_hints;
1037 bufend = recptr + mdp->d_hintsz;
1038 clen = blen = 0;
1039 best = cp = NULL;
1040 while (recptr < bufend && !found) {
1041 intp = (int*)recptr;
1042 reclen = *intp++;
1043 ival = *intp++;
1044 cp = (u_char*)intp;
1045 switch (ival) {
1046 case MDT_VERSION:
1047 clen = *cp++;
1048 if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
1049 break;
1050 cp += clen;
1051 INT_ALIGN(mdp->d_hints, cp);
1052 ival = *(int*)cp;
1053 cp += sizeof(int);
1054 clen = *cp++;
1055 if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
1056 found = 1;
1057 break;
1059 if (ival >= verinfo->md_ver_minimum &&
1060 ival <= verinfo->md_ver_maximum &&
1061 ival > bestver) {
1062 bestver = ival;
1063 best = cp;
1064 blen = clen;
1066 break;
1067 default:
1068 break;
1070 recptr += reclen + sizeof(int);
1073 * Finally check if KLD is in the place
1075 if (found)
1076 result = file_lookup(mdp->d_path, (char *)cp, clen, NULL);
1077 else if (best)
1078 result = file_lookup(mdp->d_path, (char *)best, blen, NULL);
1079 bad:
1081 * If nothing found or hints is absent - fallback to the old way
1082 * by using "kldname[.ko]" as module name.
1084 if (!found && !bestver && result == NULL)
1085 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
1086 return result;
1090 * Attempt to locate the file containing the module (name)
1092 static char *
1093 mod_searchmodule(char *name, struct mod_depend *verinfo)
1095 struct moduledir *mdp;
1096 char *result;
1098 moduledir_rebuild();
1100 * Now we ready to lookup module in the given directories
1102 result = NULL;
1103 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1104 result = mod_search_hints(mdp, name, verinfo);
1105 if (result)
1106 break;
1109 return(result);
1113 file_addmodule(struct preloaded_file *fp, char *modname, int version,
1114 struct kernel_module **newmp)
1116 struct kernel_module *mp;
1117 struct mod_depend mdepend;
1119 bzero(&mdepend, sizeof(mdepend));
1120 mdepend.md_ver_preferred = version;
1121 mp = file_findmodule(fp, modname, &mdepend);
1122 if (mp)
1123 return (EEXIST);
1124 mp = malloc(sizeof(struct kernel_module));
1125 if (mp == NULL)
1126 return (ENOMEM);
1127 bzero(mp, sizeof(struct kernel_module));
1128 mp->m_name = strdup(modname);
1129 mp->m_version = version;
1130 mp->m_fp = fp;
1131 mp->m_next = fp->f_modules;
1132 fp->f_modules = mp;
1133 if (newmp)
1134 *newmp = mp;
1135 return (0);
1139 * Throw a file away
1141 void
1142 file_discard(struct preloaded_file *fp)
1144 struct file_metadata *md, *md1;
1145 struct kernel_module *mp, *mp1;
1146 if (fp == NULL)
1147 return;
1149 if (archsw.arch_free_loadaddr != NULL && fp->f_addr)
1150 archsw.arch_free_loadaddr(fp->f_addr,
1151 (uint64_t)(roundup2(fp->f_size, PAGE_SIZE) >> 12));
1153 md = fp->f_metadata;
1154 while (md) {
1155 md1 = md;
1156 md = md->md_next;
1157 free(md1);
1159 mp = fp->f_modules;
1160 while (mp) {
1161 if (mp->m_name)
1162 free(mp->m_name);
1163 mp1 = mp;
1164 mp = mp->m_next;
1165 free(mp1);
1167 free(fp->f_name);
1168 free(fp->f_type);
1169 free(fp->f_args);
1170 free(fp);
1174 * Allocate a new file; must be used instead of malloc()
1175 * to ensure safe initialisation.
1177 struct preloaded_file *
1178 file_alloc(void)
1180 struct preloaded_file *fp;
1182 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
1183 bzero(fp, sizeof(struct preloaded_file));
1185 return (fp);
1189 * Add a module to the chain
1191 static void
1192 file_insert_tail(struct preloaded_file *fp)
1194 struct preloaded_file *cm;
1196 /* Append to list of loaded file */
1197 fp->f_next = NULL;
1198 if (preloaded_files == NULL) {
1199 preloaded_files = fp;
1200 } else {
1201 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
1203 cm->f_next = fp;
1207 static char *
1208 moduledir_fullpath(struct moduledir *mdp, const char *fname)
1210 char *cp;
1212 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
1213 if (cp == NULL)
1214 return NULL;
1215 strcpy(cp, mdp->d_path);
1216 strcat(cp, "/");
1217 strcat(cp, fname);
1218 return (cp);
1222 * Read linker.hints file into memory performing some sanity checks.
1224 static void
1225 moduledir_readhints(struct moduledir *mdp)
1227 struct stat st;
1228 char *path;
1229 int fd, size, version;
1231 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
1232 return;
1233 path = moduledir_fullpath(mdp, "linker.hints");
1234 if (stat(path, &st) != 0 ||
1235 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
1236 st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
1237 free(path);
1238 mdp->d_flags |= MDIR_NOHINTS;
1239 return;
1241 free(path);
1242 size = read(fd, &version, sizeof(version));
1243 if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
1244 goto bad;
1245 size = st.st_size - size;
1246 mdp->d_hints = malloc(size);
1247 if (mdp->d_hints == NULL)
1248 goto bad;
1249 if (read(fd, mdp->d_hints, size) != size)
1250 goto bad;
1251 mdp->d_hintsz = size;
1252 close(fd);
1253 return;
1254 bad:
1255 close(fd);
1256 if (mdp->d_hints) {
1257 free(mdp->d_hints);
1258 mdp->d_hints = NULL;
1260 mdp->d_flags |= MDIR_NOHINTS;
1261 return;
1265 * Extract directories from the ';' separated list, remove duplicates.
1267 static void
1268 moduledir_rebuild(void)
1270 struct moduledir *mdp, *mtmp;
1271 const char *path, *cp, *ep;
1272 size_t cplen;
1274 path = getenv("module_path");
1275 if (path == NULL)
1276 path = default_searchpath;
1278 * Rebuild list of module directories if it changed
1280 STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1281 mdp->d_flags |= MDIR_REMOVED;
1283 for (ep = path; *ep != 0; ep++) {
1284 cp = ep;
1285 for (; *ep != 0 && *ep != ';'; ep++)
1288 * Ignore trailing slashes
1290 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1292 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1293 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1294 continue;
1295 mdp->d_flags &= ~MDIR_REMOVED;
1296 break;
1298 if (mdp == NULL) {
1299 mdp = malloc(sizeof(*mdp) + cplen + 1);
1300 if (mdp == NULL)
1301 return;
1302 mdp->d_path = (char*)(mdp + 1);
1303 bcopy(cp, mdp->d_path, cplen);
1304 mdp->d_path[cplen] = 0;
1305 mdp->d_hints = NULL;
1306 mdp->d_flags = 0;
1307 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1309 if (*ep == 0)
1310 break;
1313 * Delete unused directories if any
1315 mdp = STAILQ_FIRST(&moduledir_list);
1316 while (mdp) {
1317 if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1318 mdp = STAILQ_NEXT(mdp, d_link);
1319 } else {
1320 if (mdp->d_hints)
1321 free(mdp->d_hints);
1322 mtmp = mdp;
1323 mdp = STAILQ_NEXT(mdp, d_link);
1324 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1325 free(mtmp);
1328 return;