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