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