module.c revision 57468
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: head/sys/boot/common/module.c 57468 2000-02-25 05:10:44Z bp $ 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 40static int mod_loadmodule(char *name, int argc, char *argv[], struct loaded_module **mpp); 41static int file_load_dependancies(struct loaded_module *base_file); 42static char *mod_searchfile(char *name); 43static char *mod_searchmodule(char *name); 44static void mod_append(struct loaded_module *mp); 45static struct module_metadata *metadata_next(struct module_metadata *md, int type); 46 47/* load address should be tweaked by first module loaded (kernel) */ 48static vm_offset_t loadaddr = 0; 49 50static char *default_searchpath ="/;/boot;/modules"; 51 52struct 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 66COMMAND_SET(load, "load", "load a kernel or module", command_load); 67 68static int 69command_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 ((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 117COMMAND_SET(unload, "unload", "unload all modules", command_unload); 118 119static int 120command_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 133COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); 134 135static int 136command_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 */ 188int 189mod_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 */ 227int 228mod_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 */ 293static int 294mod_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 356static int 357file_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 && error != EEXIST) 373 break; 374 } 375 md = metadata_next(md, MODINFOMD_DEPLIST); 376 } while (md); 377 return (error); 378} 379 380/* 381 * Find a module matching (name) and (type). 382 * NULL may be passed as a wildcard to either. 383 */ 384struct loaded_module * 385mod_findmodule(char *name, char *type) 386{ 387 struct loaded_module *mp; 388 389 for (mp = loaded_modules; mp != NULL; mp = mp->m_next) { 390 if (((name == NULL) || !strcmp(name, mp->m_name)) && 391 ((type == NULL) || !strcmp(type, mp->m_type))) 392 break; 393 } 394 return(mp); 395} 396 397/* 398 * Make a copy of (size) bytes of data from (p), and associate them as 399 * metadata of (type) to the module (mp). 400 */ 401void 402mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p) 403{ 404 struct module_metadata *md; 405 406 md = malloc(sizeof(struct module_metadata) + size); 407 md->md_size = size; 408 md->md_type = type; 409 bcopy(p, md->md_data, size); 410 md->md_next = mp->m_metadata; 411 mp->m_metadata = md; 412} 413 414/* 415 * Find a metadata object of (type) associated with the module 416 * (mp) 417 */ 418struct module_metadata * 419mod_findmetadata(struct loaded_module *mp, int type) 420{ 421 struct module_metadata *md; 422 423 for (md = mp->m_metadata; md != NULL; md = md->md_next) 424 if (md->md_type == type) 425 break; 426 return(md); 427} 428 429struct module_metadata * 430metadata_next(struct module_metadata *md, int type) 431{ 432 if (md == NULL) 433 return (NULL); 434 while((md = md->md_next) != NULL) 435 if (md->md_type == type) 436 break; 437 return (md); 438} 439 440/* 441 * Attempt to find the file (name) on the module searchpath. 442 * If (name) is qualified in any way, we simply check it and 443 * return it or NULL. If it is not qualified, then we attempt 444 * to construct a path using entries in the environment variable 445 * module_path. 446 * 447 * The path we return a pointer to need never be freed, as we manage 448 * it internally. 449 */ 450static char * 451mod_searchfile(char *name) 452{ 453 char *result; 454 char *path, *sp; 455 const char *cp; 456 struct stat sb; 457 458 /* Don't look for nothing */ 459 if (name == NULL) 460 return(name); 461 462 if (*name == 0) 463 return(strdup(name)); 464 465 /* 466 * See if there's a device on the front, or a directory name. 467 */ 468 archsw.arch_getdev(NULL, name, &cp); 469 if ((cp != name) || (strchr(name, '/') != NULL)) { 470 /* Qualified, so just see if it exists */ 471 if (stat(name, &sb) == 0) 472 return(strdup(name)); 473 return(NULL); 474 } 475 476 /* 477 * Get the module path 478 */ 479 if ((cp = getenv("module_path")) == NULL) 480 cp = default_searchpath; 481 sp = path = strdup(cp); 482 483 /* 484 * Traverse the path, splitting off ';'-delimited components. 485 */ 486 result = NULL; 487 while((cp = strsep(&path, ";")) != NULL) { 488 result = malloc(strlen(cp) + strlen(name) + 5); 489 strcpy(result, cp); 490 if (cp[strlen(cp) - 1] != '/') 491 strcat(result, "/"); 492 strcat(result, name); 493/* printf("search '%s'\n", result); */ 494 if ((stat(result, &sb) == 0) && 495 S_ISREG(sb.st_mode)) 496 break; 497 free(result); 498 result = NULL; 499 } 500 free(sp); 501 return(result); 502} 503 504/* 505 * Attempt to locate the file containing the module (name) 506 */ 507static char * 508mod_searchmodule(char *name) 509{ 510 char *tn, *result; 511 512 /* Look for (name).ko */ 513 tn = malloc(strlen(name) + 3 + 1); 514 strcpy(tn, name); 515 strcat(tn, ".ko"); 516 result = mod_searchfile(tn); 517 free(tn); 518 /* Look for just (name) (useful for finding kernels) */ 519 if (result == NULL) 520 result = mod_searchfile(name); 521 522 return(result); 523} 524 525 526/* 527 * Throw a module away 528 */ 529void 530mod_discard(struct loaded_module *mp) 531{ 532 struct module_metadata *md; 533 534 if (mp != NULL) { 535 while (mp->m_metadata != NULL) { 536 md = mp->m_metadata; 537 mp->m_metadata = mp->m_metadata->md_next; 538 free(md); 539 } 540 if (mp->m_name != NULL) 541 free(mp->m_name); 542 if (mp->m_type != NULL) 543 free(mp->m_type); 544 if (mp->m_args != NULL) 545 free(mp->m_args); 546 free(mp); 547 } 548} 549 550/* 551 * Allocate a new module; must be used instead of malloc() 552 * to ensure safe initialisation. 553 */ 554struct loaded_module * 555mod_allocmodule(void) 556{ 557 struct loaded_module *mp; 558 559 if ((mp = malloc(sizeof(struct loaded_module))) != NULL) { 560 bzero(mp, sizeof(struct loaded_module)); 561 } 562 return(mp); 563} 564 565 566/* 567 * Add a module to the chain 568 */ 569static void 570mod_append(struct loaded_module *mp) 571{ 572 struct loaded_module *cm; 573 574 /* Append to list of loaded modules */ 575 mp->m_next = NULL; 576 if (loaded_modules == NULL) { 577 loaded_modules = mp; 578 } else { 579 for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next) 580 ; 581 cm->m_next = mp; 582 } 583} 584