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