Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / boot / common / module.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
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/boot/common/module.c,v 1.13.2.4 2002/12/19 12:41:10 thomas Exp $
27  */
28
29 /*
30  * module function dispatcher, support, etc.
31  */
32
33 #include <stand.h>
34 #include <string.h>
35 #include <sys/param.h>
36 #include <sys/linker.h>
37
38 #include "bootstrap.h"
39
40 static int                      mod_loadmodule(char *name, int argc, char *argv[], struct loaded_module **mpp);
41 static int                      file_load_dependancies(struct loaded_module *base_file);
42 static char                     *mod_searchfile(char *name);
43 static char                     *mod_searchmodule(char *name);
44 static void                     mod_append(struct loaded_module *mp);
45 static struct module_metadata   *metadata_next(struct module_metadata *md, int type);
46
47 /* load address should be tweaked by first module loaded (kernel) */
48 static vm_offset_t      loadaddr = 0;
49
50 static const char       *default_searchpath ="/;/boot;/modules";
51
52 struct loaded_module *loaded_modules = NULL;
53
54 /*
55  * load an object, either a disk file or code module.
56  *
57  * To load a file, the syntax is:
58  *
59  * load -t <type> <path>
60  *
61  * code modules are loaded as:
62  *
63  * load <path> <options>
64  */
65
66 COMMAND_SET(load, "load", "load a kernel or module", command_load);
67
68 static int
69 command_load(int argc, char *argv[])
70 {
71     char        *typestr;
72     int         dofile, ch, error;
73     
74     dofile = 0;
75     optind = 1;
76     optreset = 1;
77     typestr = NULL;
78     if (argc == 1) {
79         command_errmsg = "no filename specified";
80         return(CMD_ERROR);
81     }
82     while ((ch = getopt(argc, argv, "t:")) != -1) {
83         switch(ch) {
84         case 't':
85             typestr = optarg;
86             dofile = 1;
87             break;
88         case '?':
89         default:
90             /* getopt has already reported an error */
91             return(CMD_OK);
92         }
93     }
94     argv += (optind - 1);
95     argc -= (optind - 1);
96
97     /*
98      * Request to load a raw file?
99      */
100     if (dofile) {
101         if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
102             command_errmsg = "invalid load type";
103             return(CMD_ERROR);
104         }
105         return(mod_loadobj(typestr, argv[1]));
106     }
107     
108     /*
109      * Looks like a request for a module.
110      */
111     error = mod_load(argv[1], argc - 2, argv + 2);
112     if (error == EEXIST)
113         sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
114     return (error == 0 ? CMD_OK : CMD_ERROR);
115 }
116
117 COMMAND_SET(unload, "unload", "unload all modules", command_unload);
118
119 static int
120 command_unload(int argc, char *argv[])
121 {
122     struct loaded_module        *mp;
123     
124     while (loaded_modules != NULL) {
125         mp = loaded_modules;
126         loaded_modules = loaded_modules->m_next;
127         mod_discard(mp);
128     }
129     loadaddr = 0;
130     return(CMD_OK);
131 }
132
133 COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
134
135 static int
136 command_lsmod(int argc, char *argv[])
137 {
138     struct loaded_module        *am;
139     struct module_metadata      *md;
140     char                        lbuf[80];
141     int                         ch, verbose;
142
143     verbose = 0;
144     optind = 1;
145     optreset = 1;
146     while ((ch = getopt(argc, argv, "v")) != -1) {
147         switch(ch) {
148         case 'v':
149             verbose = 1;
150             break;
151         case '?':
152         default:
153             /* getopt has already reported an error */
154             return(CMD_OK);
155         }
156     }
157
158     pager_open();
159     for (am = loaded_modules; (am != NULL); am = am->m_next) {
160         sprintf(lbuf, " %p: %s (%s, 0x%lx)\n", 
161                 (void *) am->m_addr, am->m_name, am->m_type, (long) am->m_size);
162         pager_output(lbuf);
163         if (am->m_args != NULL) {
164             pager_output("    args: ");
165             pager_output(am->m_args);
166             pager_output("\n");
167         }
168         if (verbose)
169             /* XXX could add some formatting smarts here to display some better */
170             for (md = am->m_metadata; md != NULL; md = md->md_next) {
171                 sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
172                 pager_output(lbuf);
173             }
174     }
175     pager_close();
176     return(CMD_OK);
177 }
178
179 /*
180  * We've been asked to load (name) and give it (argc),(argv).
181  * Start by trying to load it, and then attempt to load all of its 
182  * dependancies.  If we fail at any point, throw them all away and
183  * fail the entire load.
184  *
185  * XXX if a depended-on module requires arguments, it must be loaded
186  *     explicitly first.
187  */
188 int
189 mod_load(char *name, int argc, char *argv[])
190 {
191     struct loaded_module        *last_mod, *base_mod, *mp;
192     int                         error;
193
194     /* remember previous last module on chain */
195     for (last_mod = loaded_modules; 
196          (last_mod != NULL) && (last_mod->m_next != NULL);
197          last_mod = last_mod->m_next)
198         ;
199     
200     /* 
201      * Load the first module; note that it's the only one that gets
202      * arguments explicitly.
203      */
204     error = mod_loadmodule(name, argc, argv, &base_mod);
205     if (error)
206         return (error);
207
208     error = file_load_dependancies(base_mod);
209     if (!error)
210         return (0);
211
212     /* Load failed; discard everything */
213     last_mod->m_next = NULL;
214     loadaddr = last_mod->m_addr + last_mod->m_size;
215     while (base_mod != NULL) {
216         mp = base_mod;
217         base_mod = base_mod->m_next;
218         mod_discard(mp);
219     }
220     return (error);
221 }
222
223 /*
224  * We've been asked to load (name) as (type), so just suck it in,
225  * no arguments or anything.
226  */
227 int
228 mod_loadobj(char *type, char *name)
229 {
230     struct loaded_module        *mp;
231     char                        *cp;
232     int                         fd, got;
233     vm_offset_t                 laddr;
234
235     /* We can't load first */
236     if ((mod_findmodule(NULL, NULL)) == NULL) {
237         command_errmsg = "can't load file before kernel";
238         return(CMD_ERROR);
239     }
240
241     /* locate the file on the load path */
242     cp = mod_searchfile(name);
243     if (cp == NULL) {
244         sprintf(command_errbuf, "can't find '%s'", name);
245         return(CMD_ERROR);
246     }
247     name = cp;
248     
249     if ((fd = open(name, O_RDONLY)) < 0) {
250         sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
251         free(name);
252         return(CMD_ERROR);
253     }
254
255     laddr = loadaddr;
256     for (;;) {
257         /* read in 4k chunks; size is not really important */
258         got = archsw.arch_readin(fd, laddr, 4096);
259         if (got == 0)                           /* end of file */
260             break;
261         if (got < 0) {                          /* error */
262             sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
263             free(name);
264             close(fd);
265             return(CMD_ERROR);
266         }
267         laddr += got;
268     }
269     
270     /* Looks OK so far; create & populate control structure */
271     mp = malloc(sizeof(struct loaded_module));
272     mp->m_name = name;
273     mp->m_type = strdup(type);
274     mp->m_args = NULL;
275     mp->m_metadata = NULL;
276     mp->m_loader = -1;
277     mp->m_addr = loadaddr;
278     mp->m_size = laddr - loadaddr;
279
280     /* recognise space consumption */
281     loadaddr = laddr;
282
283     /* Add to the list of loaded modules */
284     mod_append(mp);
285     close(fd);
286     return(CMD_OK);
287 }
288
289 /*
290  * Load the module (name), pass it (argc),(argv).
291  * Don't do any dependancy checking.
292  */
293 static int
294 mod_loadmodule(char *name, int argc, char *argv[], struct loaded_module **mpp)
295 {
296     struct loaded_module        *mp;
297     int                         i, err;
298     char                        *cp;
299
300     /* locate the module on the search path */
301     cp = mod_searchmodule(name);
302     if (cp == NULL) {
303         sprintf(command_errbuf, "can't find '%s'", name);
304         return (ENOENT);
305     }
306     name = cp;
307
308     cp = strrchr(name, '/');
309     if (cp)
310         cp++;
311     else
312         cp = name;
313     /* see if module is already loaded */
314     mp = mod_findmodule(cp, NULL);
315     if (mp) {
316         *mpp = mp;
317         return (EEXIST);
318     }
319
320     err = 0;
321     for (i = 0, mp = NULL; (module_formats[i] != NULL) && (mp == NULL); i++) {
322         if ((err = (module_formats[i]->l_load)(name, loadaddr, &mp)) != 0) {
323
324             /* Unknown to this handler? */
325             if (err == EFTYPE)
326                 continue;
327                 
328             /* Fatal error */
329             sprintf(command_errbuf, "can't load module '%s': %s", name, strerror(err));
330             free(name);
331             return (err);
332         } else {
333
334             /* Load was OK, set args */
335             mp->m_args = unargv(argc, argv);
336
337             /* where can we put the next one? */
338             loadaddr = mp->m_addr + mp->m_size;
339         
340             /* remember the loader */
341             mp->m_loader = i;
342
343             /* Add to the list of loaded modules */
344             mod_append(mp);
345             *mpp = mp;
346
347             break;
348         }
349     }
350     if (err == EFTYPE)
351         sprintf(command_errbuf, "don't know how to load module '%s'", name);
352     free(name);
353     return (err);
354 }
355
356 static int
357 file_load_dependancies(struct loaded_module *base_file)
358 {
359     struct module_metadata      *md;
360     char                        *dmodname;
361     int                         error;
362
363     md = mod_findmetadata(base_file, MODINFOMD_DEPLIST);
364     if (md == NULL)
365         return (0);
366     error = 0;
367     do {
368         dmodname = (char *)md->md_data;
369         if (mod_findmodule(NULL, dmodname) == NULL) {
370             printf("loading required module '%s'\n", dmodname);
371             error = mod_load(dmodname, 0, NULL);
372             if (error == EEXIST)
373                 error = 0;
374             if (error != 0)
375                 break;
376         }
377         md = metadata_next(md, MODINFOMD_DEPLIST);
378     } while (md);
379     return (error);
380 }
381
382 /*
383  * Find a module matching (name) and (type).
384  * NULL may be passed as a wildcard to either.
385  */
386 struct loaded_module *
387 mod_findmodule(char *name, char *type)
388 {
389     struct loaded_module        *mp;
390     
391     for (mp = loaded_modules; mp != NULL; mp = mp->m_next) {
392         if (((name == NULL) || !strcmp(name, mp->m_name)) &&
393             ((type == NULL) || !strcmp(type, mp->m_type)))
394             break;
395     }
396     return(mp);
397 }
398
399 /*
400  * Make a copy of (size) bytes of data from (p), and associate them as
401  * metadata of (type) to the module (mp).
402  */
403 void
404 mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p)
405 {
406     struct module_metadata      *md;
407
408     md = malloc(sizeof(struct module_metadata) + size);
409     md->md_size = size;
410     md->md_type = type;
411     bcopy(p, md->md_data, size);
412     md->md_next = mp->m_metadata;
413     mp->m_metadata = md;
414 }
415
416 /*
417  * Find a metadata object of (type) associated with the module
418  * (mp)
419  */
420 struct module_metadata *
421 mod_findmetadata(struct loaded_module *mp, int type)
422 {
423     struct module_metadata      *md;
424
425     for (md = mp->m_metadata; md != NULL; md = md->md_next)
426         if (md->md_type == type)
427             break;
428     return(md);
429 }
430
431 struct module_metadata *
432 metadata_next(struct module_metadata *md, int type)
433 {
434     if (md == NULL)
435         return (NULL);
436     while((md = md->md_next) != NULL)
437         if (md->md_type == type)
438             break;
439     return (md);
440 }
441
442 /*
443  * Attempt to find the file (name) on the module searchpath.
444  * If (name) is qualified in any way, we simply check it and
445  * return it or NULL.  If it is not qualified, then we attempt
446  * to construct a path using entries in the environment variable
447  * module_path.
448  *
449  * The path we return a pointer to need never be freed, as we manage
450  * it internally.
451  */
452 static char *
453 mod_searchfile(char *name)
454 {
455     char                *result;
456     char                *path, *sp;
457     const char          *cp;
458     struct stat         sb;
459
460     /* Don't look for nothing */
461     if (name == NULL)
462         return(name);
463
464     if (*name == 0)
465         return(strdup(name));
466
467     /*
468      * See if there's a device on the front, or a directory name.
469      */
470     archsw.arch_getdev(NULL, name, &cp);
471     if ((cp != name) || (strchr(name, '/') != NULL)) {
472         /* Qualified, so just see if it exists */
473         if (stat(name, &sb) == 0)
474             return(strdup(name));
475         return(NULL);
476     }
477     
478     /*
479      * Get the module path
480      */
481     if ((cp = getenv("module_path")) == NULL)
482         cp = default_searchpath;
483     sp = path = strdup(cp);
484     
485     /*
486      * Traverse the path, splitting off ';'-delimited components.
487      */
488     result = NULL;
489     while((cp = strsep(&path, ";")) != NULL) {
490         result = malloc(strlen(cp) + strlen(name) + 5);
491         strcpy(result, cp);
492         if (cp[strlen(cp) - 1] != '/')
493             strcat(result, "/");
494         strcat(result, name);
495 /*      printf("search '%s'\n", result); */
496         if ((stat(result, &sb) == 0) && 
497             S_ISREG(sb.st_mode))
498             break;
499         free(result);
500         result = NULL;
501     }
502     free(sp);
503     return(result);
504 }
505
506 /*
507  * Attempt to locate the file containing the module (name)
508  */
509 static char *
510 mod_searchmodule(char *name)
511 {
512     char        *tn, *result;
513     
514     /* Look for (name).ko */
515     tn = malloc(strlen(name) + 3 + 1);
516     strcpy(tn, name);
517     strcat(tn, ".ko");
518     result = mod_searchfile(tn);
519     free(tn);
520     /* Look for just (name) (useful for finding kernels) */
521     if (result == NULL)
522         result = mod_searchfile(name);
523
524     return(result);
525 }
526
527
528 /*
529  * Throw a module away
530  */
531 void
532 mod_discard(struct loaded_module *mp)
533 {
534     struct module_metadata      *md;
535
536     if (mp != NULL) {
537         while (mp->m_metadata != NULL) {
538             md = mp->m_metadata;
539             mp->m_metadata = mp->m_metadata->md_next;
540             free(md);
541         }       
542         if (mp->m_name != NULL)
543             free(mp->m_name);
544         if (mp->m_type != NULL)
545             free(mp->m_type);
546         if (mp->m_args != NULL)
547             free(mp->m_args);
548         free(mp);
549     }
550 }
551
552 /*
553  * Allocate a new module; must be used instead of malloc()
554  * to ensure safe initialisation.
555  */
556 struct loaded_module *
557 mod_allocmodule(void)
558 {
559     struct loaded_module        *mp;
560     
561     if ((mp = malloc(sizeof(struct loaded_module))) != NULL) {
562         bzero(mp, sizeof(struct loaded_module));
563     }
564     return(mp);
565 }
566
567
568 /*
569  * Add a module to the chain
570  */
571 static void
572 mod_append(struct loaded_module *mp)
573 {
574     struct loaded_module        *cm;
575     
576     /* Append to list of loaded modules */
577     mp->m_next = NULL;
578     if (loaded_modules == NULL) {
579         loaded_modules = mp;
580     } else {
581         for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next)
582             ;
583         cm->m_next = mp;
584     }
585 }