1 /*- 2 * Copyright (c) 1997 Doug Rabson 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 * $Id: kern_linker.c,v 1.6 1998/01/01 08:56:24 bde Exp $ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/systm.h> 32 #include <sys/malloc.h> 33 #include <sys/sysproto.h> 34 #include <sys/sysent.h> 35 #include <sys/proc.h> 36 #include <sys/lock.h> 37 #include <machine/cpu.h> 38 #include <sys/module.h> 39 #include <sys/linker.h> 40 #include <sys/unistd.h> 41 42 MALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); 43 linker_file_t linker_current_file; 44 45 static struct lock lock; /* lock for the file list */ 46 static linker_class_list_t classes; 47 static linker_file_list_t files; 48 static int next_file_id = 1; 49 50 static void 51 linker_init(void* arg) 52 { 53 lockinit(&lock, PVM, "klink", 0, 0); 54 TAILQ_INIT(&classes); 55 TAILQ_INIT(&files); 56 } 57 58 SYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0); 59 60 int 61 linker_add_class(const char* desc, void* priv, 62 struct linker_class_ops* ops) 63 { 64 linker_class_t lc; 65 66 lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); 67 if (!lc) 68 return ENOMEM; 69 70 lc->desc = desc; 71 lc->priv = priv; 72 lc->ops = ops; 73 TAILQ_INSERT_HEAD(&classes, lc, link); 74 75 return 0; 76 } 77 78 static void 79 linker_file_sysinit(linker_file_t lf) 80 { 81 struct linker_set* sysinits; 82 struct sysinit** sipp; 83 struct sysinit** xipp; 84 struct sysinit* save; 85 86 linker_current_file = lf; 87 88 KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 89 lf->filename)); 90 91 sysinits = (struct linker_set*) 92 linker_file_lookup_symbol(lf, "sysinit_set", 0); 93 if (!sysinits) 94 return; 95 96 /* 97 * Perform a bubble sort of the system initialization objects by 98 * their subsystem (primary key) and order (secondary key). 99 * 100 * Since some things care about execution order, this is the 101 * operation which ensures continued function. 102 */ 103 for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 104 for( xipp = sipp + 1; *xipp; xipp++) { 105 if( (*sipp)->subsystem < (*xipp)->subsystem || 106 ( (*sipp)->subsystem == (*xipp)->subsystem && 107 (*sipp)->order < (*xipp)->order)) 108 continue; /* skip*/ 109 save = *sipp; 110 *sipp = *xipp; 111 *xipp = save; 112 } 113 } 114 115 116 /* 117 * Traverse the (now) ordered list of system initialization tasks. 118 * Perform each task, and continue on to the next task. 119 * 120 * The last item on the list is expected to be the scheduler, 121 * which will not return. 122 */ 123 for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 124 if( (*sipp)->subsystem == SI_SUB_DUMMY) 125 continue; /* skip dummy task(s)*/ 126 127 switch( (*sipp)->type) { 128 case SI_TYPE_DEFAULT: 129 /* no special processing*/ 130 (*((*sipp)->func))( (*sipp)->udata); 131 break; 132 133 case SI_TYPE_KTHREAD: 134 #if !defined(SMP) 135 /* kernel thread*/ 136 if (fork1(&proc0, RFFDG|RFPROC|RFMEM)) 137 panic("fork kernel thread"); 138 cpu_set_fork_handler(pfind(proc0.p_retval[0]), 139 (*sipp)->func, (*sipp)->udata); 140 break; 141 #endif 142 143 case SI_TYPE_KPROCESS: 144 /* kernel thread*/ 145 if (fork1(&proc0, RFFDG|RFPROC)) 146 panic("fork kernel process"); 147 cpu_set_fork_handler(pfind(proc0.p_retval[0]), 148 (*sipp)->func, (*sipp)->udata); 149 break; 150 151 default: 152 panic( "linker_file_sysinit: unrecognized init type"); 153 } 154 } 155 } 156 157 int 158 linker_load_file(const char* filename, linker_file_t* result) 159 { 160 linker_class_t lc; 161 linker_file_t lf; 162 int error = 0; 163 164 lf = linker_find_file_by_name(filename); 165 if (lf) { 166 KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); 167 *result = lf; 168 lf->refs++; 169 goto out; 170 } 171 172 lf = NULL; 173 for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 174 KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", 175 filename, lc->desc)); 176 if (error = lc->ops->load_file(filename, &lf)) 177 goto out; 178 if (lf) { 179 linker_file_sysinit(lf); 180 181 *result = lf; 182 goto out; 183 } 184 } 185 186 error = ENOEXEC; /* format not recognised */ 187 188 out: 189 return error; 190 } 191 192 linker_file_t 193 linker_find_file_by_name(const char* filename) 194 { 195 linker_file_t lf = 0; 196 197 lockmgr(&lock, LK_SHARED, 0, curproc); 198 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 199 if (!strcmp(lf->filename, filename)) 200 break; 201 lockmgr(&lock, LK_RELEASE, 0, curproc); 202 203 return lf; 204 } 205 206 linker_file_t 207 linker_find_file_by_id(int fileid) 208 { 209 linker_file_t lf = 0; 210 211 lockmgr(&lock, LK_SHARED, 0, curproc); 212 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 213 if (lf->id == fileid) 214 break; 215 lockmgr(&lock, LK_RELEASE, 0, curproc); 216 217 return lf; 218 } 219 220 linker_file_t 221 linker_make_file(const char* filename, void* priv, struct linker_file_ops* ops) 222 { 223 linker_file_t lf = 0; 224 int namelen; 225 226 KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 227 lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 228 namelen = strlen(filename) + 1; 229 lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); 230 if (!lf) 231 goto out; 232 233 lf->refs = 1; 234 lf->userrefs = 0; 235 lf->filename = (char*) (lf + 1); 236 strcpy(lf->filename, filename); 237 lf->id = next_file_id++; 238 lf->ndeps = 0; 239 lf->deps = NULL; 240 STAILQ_INIT(&lf->common); 241 TAILQ_INIT(&lf->modules); 242 243 lf->priv = priv; 244 lf->ops = ops; 245 TAILQ_INSERT_TAIL(&files, lf, link); 246 247 out: 248 lockmgr(&lock, LK_RELEASE, 0, curproc); 249 return lf; 250 } 251 252 int 253 linker_file_unload(linker_file_t file) 254 { 255 module_t mod, next; 256 struct common_symbol* cp; 257 int error = 0; 258 int i; 259 260 KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs)); 261 lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 262 if (file->refs == 1) { 263 KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); 264 /* 265 * Inform any modules associated with this file. 266 */ 267 for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 268 next = module_getfnext(mod); 269 270 /* 271 * Give the module a chance to veto the unload. 272 */ 273 if (error = module_unload(mod)) { 274 KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", 275 mod)); 276 lockmgr(&lock, LK_RELEASE, 0, curproc); 277 goto out; 278 } 279 280 module_release(mod); 281 } 282 } 283 284 file->refs--; 285 if (file->refs > 0) { 286 lockmgr(&lock, LK_RELEASE, 0, curproc); 287 goto out; 288 } 289 290 TAILQ_REMOVE(&files, file, link); 291 lockmgr(&lock, LK_RELEASE, 0, curproc); 292 293 for (i = 0; i < file->ndeps; i++) 294 linker_file_unload(file->deps[i]); 295 free(file->deps, M_LINKER); 296 297 for (cp = STAILQ_FIRST(&file->common); cp; 298 cp = STAILQ_FIRST(&file->common)) { 299 STAILQ_REMOVE(&file->common, cp, common_symbol, link); 300 free(cp, M_LINKER); 301 } 302 303 file->ops->unload(file); 304 free(file, M_LINKER); 305 306 out: 307 return error; 308 } 309 310 int 311 linker_file_add_dependancy(linker_file_t file, linker_file_t dep) 312 { 313 linker_file_t* newdeps; 314 315 newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), 316 M_LINKER, M_WAITOK); 317 if (newdeps == NULL) 318 return ENOMEM; 319 320 if (file->deps) { 321 bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); 322 free(file->deps, M_LINKER); 323 } 324 file->deps = newdeps; 325 file->deps[file->ndeps] = dep; 326 file->ndeps++; 327 328 return 0; 329 } 330 331 caddr_t 332 linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) 333 { 334 linker_sym_t sym; 335 linker_symval_t symval; 336 caddr_t address; 337 size_t common_size = 0; 338 int i; 339 340 KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d", 341 file, name, deps)); 342 343 if (file->ops->lookup_symbol(file, name, &sym) == 0) { 344 file->ops->symbol_values(file, sym, &symval); 345 if (symval.value == 0) 346 /* 347 * For commons, first look them up in the dependancies and 348 * only allocate space if not found there. 349 */ 350 common_size = symval.size; 351 else 352 return symval.value; 353 } 354 355 if (deps) 356 for (i = 0; i < file->ndeps; i++) { 357 address = linker_file_lookup_symbol(file->deps[i], name, 0); 358 if (address) 359 return address; 360 } 361 362 if (common_size > 0) { 363 /* 364 * This is a common symbol which was not found in the 365 * dependancies. We maintain a simple common symbol table in 366 * the file object. 367 */ 368 struct common_symbol* cp; 369 370 for (cp = STAILQ_FIRST(&file->common); cp; 371 cp = STAILQ_NEXT(cp, link)) 372 if (!strcmp(cp->name, name)) 373 return cp->address; 374 375 /* 376 * Round the symbol size up to align. 377 */ 378 common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 379 cp = malloc(sizeof(struct common_symbol) 380 + common_size 381 + strlen(name) + 1, 382 M_LINKER, M_WAITOK); 383 if (!cp) 384 return 0; 385 386 cp->address = (caddr_t) (cp + 1); 387 cp->name = cp->address + common_size; 388 strcpy(cp->name, name); 389 bzero(cp->address, common_size); 390 STAILQ_INSERT_TAIL(&file->common, cp, link); 391 392 return cp->address; 393 } 394 395 return 0; 396 } 397 398 /* 399 * Syscalls. 400 */ 401 402 int 403 kldload(struct proc* p, struct kldload_args* uap) 404 { 405 char* filename = NULL; 406 linker_file_t lf; 407 int error = 0; 408 409 p->p_retval[0] = -1; 410 411 if (securelevel > 0) 412 return EPERM; 413 414 if (error = suser(p->p_ucred, &p->p_acflag)) 415 return error; 416 417 filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 418 if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 419 goto out; 420 421 if (error = linker_load_file(uap->file, &lf)) 422 goto out; 423 424 lf->userrefs++; 425 p->p_retval[0] = lf->id; 426 427 out: 428 if (filename) 429 free(filename, M_TEMP); 430 return error; 431 } 432 433 int 434 kldunload(struct proc* p, struct kldunload_args* uap) 435 { 436 linker_file_t lf; 437 int error = 0; 438 439 if (securelevel > 0) 440 return EPERM; 441 442 if (error = suser(p->p_ucred, &p->p_acflag)) 443 return error; 444 445 lf = linker_find_file_by_id(SCARG(uap, fileid)); 446 if (lf) { 447 KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 448 if (lf->userrefs == 0) { 449 printf("linkerunload: attempt to unload file which was not loaded by user\n"); 450 error = EBUSY; 451 goto out; 452 } 453 lf->userrefs--; 454 error = linker_file_unload(lf); 455 } else 456 error = ENOENT; 457 458 out: 459 return error; 460 } 461 462 int 463 kldfind(struct proc* p, struct kldfind_args* uap) 464 { 465 char* filename = NULL; 466 linker_file_t lf; 467 int error = 0; 468 469 p->p_retval[0] = -1; 470 471 filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 472 if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 473 goto out; 474 475 lf = linker_find_file_by_name(filename); 476 if (lf) 477 p->p_retval[0] = lf->id; 478 else 479 error = ENOENT; 480 481 out: 482 if (filename) 483 free(filename, M_TEMP); 484 return error; 485 } 486 487 int 488 kldnext(struct proc* p, struct kldnext_args* uap) 489 { 490 linker_file_t lf; 491 int error = 0; 492 493 if (SCARG(uap, fileid) == 0) { 494 if (TAILQ_FIRST(&files)) 495 p->p_retval[0] = TAILQ_FIRST(&files)->id; 496 else 497 p->p_retval[0] = 0; 498 return 0; 499 } 500 501 lf = linker_find_file_by_id(SCARG(uap, fileid)); 502 if (lf) { 503 if (TAILQ_NEXT(lf, link)) 504 p->p_retval[0] = TAILQ_NEXT(lf, link)->id; 505 else 506 p->p_retval[0] = 0; 507 } else 508 error = ENOENT; 509 510 return error; 511 } 512 513 int 514 kldstat(struct proc* p, struct kldstat_args* uap) 515 { 516 linker_file_t lf; 517 int error = 0; 518 int version; 519 struct kld_file_stat* stat; 520 int namelen; 521 522 lf = linker_find_file_by_id(SCARG(uap, fileid)); 523 if (!lf) { 524 error = ENOENT; 525 goto out; 526 } 527 528 stat = SCARG(uap, stat); 529 530 /* 531 * Check the version of the user's structure. 532 */ 533 if (error = copyin(&stat->version, &version, sizeof(version))) 534 goto out; 535 if (version != sizeof(struct kld_file_stat)) { 536 error = EINVAL; 537 goto out; 538 } 539 540 namelen = strlen(lf->filename) + 1; 541 if (namelen > MAXPATHLEN) 542 namelen = MAXPATHLEN; 543 if (error = copyout(lf->filename, &stat->name[0], namelen)) 544 goto out; 545 if (error = copyout(&lf->refs, &stat->refs, sizeof(int))) 546 goto out; 547 if (error = copyout(&lf->id, &stat->id, sizeof(int))) 548 goto out; 549 if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) 550 goto out; 551 if (error = copyout(&lf->size, &stat->size, sizeof(size_t))) 552 goto out; 553 554 p->p_retval[0] = 0; 555 556 out: 557 return error; 558 } 559 560 int 561 kldfirstmod(struct proc* p, struct kldfirstmod_args* uap) 562 { 563 linker_file_t lf; 564 int error = 0; 565 566 lf = linker_find_file_by_id(SCARG(uap, fileid)); 567 if (lf) { 568 if (TAILQ_FIRST(&lf->modules)) 569 p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules)); 570 else 571 p->p_retval[0] = 0; 572 } else 573 error = ENOENT; 574 575 return error; 576 } 577