Commit | Line | Data |
---|---|---|
984263bc MD |
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 | * $FreeBSD: src/sys/kern/kern_linker.c,v 1.41.2.3 2001/11/21 17:50:35 luigi Exp $ | |
27 | */ | |
28 | ||
29 | #include "opt_ddb.h" | |
30 | ||
31 | #include <sys/param.h> | |
32 | #include <sys/kernel.h> | |
33 | #include <sys/systm.h> | |
34 | #include <sys/malloc.h> | |
80d831e1 | 35 | #include <sys/sysmsg.h> |
984263bc MD |
36 | #include <sys/sysent.h> |
37 | #include <sys/proc.h> | |
2b3f93ea | 38 | #include <sys/caps.h> |
984263bc MD |
39 | #include <sys/lock.h> |
40 | #include <sys/module.h> | |
89e1aaa0 | 41 | #include <sys/queue.h> |
984263bc MD |
42 | #include <sys/linker.h> |
43 | #include <sys/fcntl.h> | |
44 | #include <sys/libkern.h> | |
fad57d0e | 45 | #include <sys/nlookup.h> |
984263bc MD |
46 | #include <sys/vnode.h> |
47 | #include <sys/sysctl.h> | |
48 | ||
49 | #include <vm/vm_zone.h> | |
50 | ||
6ef6faeb SS |
51 | #ifdef _KERNEL_VIRTUAL |
52 | #include <dlfcn.h> | |
53 | #endif | |
54 | ||
984263bc | 55 | #ifdef KLD_DEBUG |
1c0e3286 | 56 | int kld_debug = 1; |
984263bc MD |
57 | #endif |
58 | ||
6456e0ad MD |
59 | /* Metadata from the static kernel */ |
60 | SET_DECLARE(modmetadata_set, struct mod_metadata); | |
984263bc | 61 | MALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); |
6456e0ad | 62 | |
984263bc MD |
63 | linker_file_t linker_current_file; |
64 | linker_file_t linker_kernel_file; | |
65 | ||
5a4bb8ec MD |
66 | static struct lock llf_lock; /* lock for the file list */ |
67 | static struct lock kld_lock; | |
984263bc MD |
68 | static linker_class_list_t classes; |
69 | static linker_file_list_t linker_files; | |
70 | static int next_file_id = 1; | |
71 | ||
1c0e3286 SS |
72 | /* XXX wrong name; we're looking at version provision tags here, not modules */ |
73 | typedef TAILQ_HEAD(, modlist) modlisthead_t; | |
74 | struct modlist { | |
75 | TAILQ_ENTRY(modlist) link; /* chain together all modules */ | |
76 | linker_file_t container; | |
77 | const char *name; | |
78 | int version; | |
79 | }; | |
80 | typedef struct modlist *modlist_t; | |
81 | static modlisthead_t found_modules; | |
82 | ||
83 | ||
84 | static int linker_load_module(const char *kldname, const char *modname, | |
85 | struct linker_file *parent, struct mod_depend *verinfo, | |
86 | struct linker_file **lfpp); | |
87 | ||
88 | static char * | |
89 | linker_strdup(const char *str) | |
90 | { | |
91 | char *result; | |
92 | ||
93 | result = kmalloc(strlen(str) + 1, M_LINKER, M_WAITOK); | |
94 | strcpy(result, str); | |
95 | return(result); | |
96 | } | |
97 | ||
4f79e0ef AL |
98 | static const char * |
99 | linker_basename(const char *path) | |
100 | { | |
101 | const char *filename; | |
102 | ||
103 | filename = strrchr(path, '/'); | |
104 | if (filename == NULL) | |
105 | return path; | |
106 | if (filename[1]) | |
107 | filename++; | |
108 | return (filename); | |
109 | } | |
110 | ||
984263bc MD |
111 | static void |
112 | linker_init(void* arg) | |
113 | { | |
5a4bb8ec | 114 | lockinit(&llf_lock, "klink", 0, 0); |
47491315 | 115 | lockinit(&kld_lock, "kldlk", 0, LK_CANRECURSE); |
984263bc MD |
116 | TAILQ_INIT(&classes); |
117 | TAILQ_INIT(&linker_files); | |
118 | } | |
119 | ||
ba39e2e0 | 120 | SYSINIT(linker, SI_BOOT2_KLD, SI_ORDER_FIRST, linker_init, 0); |
984263bc MD |
121 | |
122 | int | |
123 | linker_add_class(const char* desc, void* priv, | |
124 | struct linker_class_ops* ops) | |
125 | { | |
126 | linker_class_t lc; | |
127 | ||
e7b4468c | 128 | lc = kmalloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT | M_ZERO); |
984263bc MD |
129 | if (!lc) |
130 | return ENOMEM; | |
984263bc MD |
131 | |
132 | lc->desc = desc; | |
133 | lc->priv = priv; | |
134 | lc->ops = ops; | |
135 | TAILQ_INSERT_HEAD(&classes, lc, link); | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
1c0e3286 | 140 | static void |
984263bc MD |
141 | linker_file_sysinit(linker_file_t lf) |
142 | { | |
dc62b251 | 143 | struct sysinit** start, ** stop; |
984263bc MD |
144 | struct sysinit** sipp; |
145 | struct sysinit** xipp; | |
146 | struct sysinit* save; | |
984263bc MD |
147 | |
148 | KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", | |
149 | lf->filename)); | |
150 | ||
dc62b251 | 151 | if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) |
1c0e3286 | 152 | return; |
984263bc | 153 | |
984263bc MD |
154 | /* |
155 | * Perform a bubble sort of the system initialization objects by | |
156 | * their subsystem (primary key) and order (secondary key). | |
157 | * | |
158 | * Since some things care about execution order, this is the | |
159 | * operation which ensures continued function. | |
160 | */ | |
dc62b251 MD |
161 | for (sipp = start; sipp < stop; sipp++) { |
162 | for (xipp = sipp + 1; xipp < stop; xipp++) { | |
984263bc MD |
163 | if ((*sipp)->subsystem < (*xipp)->subsystem || |
164 | ((*sipp)->subsystem == (*xipp)->subsystem && | |
165 | (*sipp)->order <= (*xipp)->order)) | |
166 | continue; /* skip*/ | |
167 | save = *sipp; | |
168 | *sipp = *xipp; | |
169 | *xipp = save; | |
170 | } | |
171 | } | |
172 | ||
173 | ||
174 | /* | |
175 | * Traverse the (now) ordered list of system initialization tasks. | |
176 | * Perform each task, and continue on to the next task. | |
177 | */ | |
dc62b251 | 178 | for (sipp = start; sipp < stop; sipp++) { |
ba39e2e0 | 179 | if ((*sipp)->subsystem == SI_SPECIAL_DUMMY) |
984263bc MD |
180 | continue; /* skip dummy task(s)*/ |
181 | ||
182 | /* Call function */ | |
183 | (*((*sipp)->func))((*sipp)->udata); | |
184 | } | |
984263bc MD |
185 | } |
186 | ||
187 | static void | |
188 | linker_file_sysuninit(linker_file_t lf) | |
189 | { | |
dc62b251 | 190 | struct sysinit** start, ** stop; |
984263bc MD |
191 | struct sysinit** sipp; |
192 | struct sysinit** xipp; | |
193 | struct sysinit* save; | |
194 | ||
195 | KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", | |
196 | lf->filename)); | |
197 | ||
dc62b251 | 198 | if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, NULL) != 0) |
984263bc MD |
199 | return; |
200 | ||
201 | /* | |
202 | * Perform a reverse bubble sort of the system initialization objects | |
203 | * by their subsystem (primary key) and order (secondary key). | |
204 | * | |
205 | * Since some things care about execution order, this is the | |
206 | * operation which ensures continued function. | |
207 | */ | |
dc62b251 MD |
208 | for (sipp = start; sipp < stop; sipp++) { |
209 | for (xipp = sipp + 1; xipp < stop; xipp++) { | |
984263bc MD |
210 | if ((*sipp)->subsystem > (*xipp)->subsystem || |
211 | ((*sipp)->subsystem == (*xipp)->subsystem && | |
212 | (*sipp)->order >= (*xipp)->order)) | |
213 | continue; /* skip*/ | |
214 | save = *sipp; | |
215 | *sipp = *xipp; | |
216 | *xipp = save; | |
217 | } | |
218 | } | |
219 | ||
220 | ||
221 | /* | |
222 | * Traverse the (now) ordered list of system initialization tasks. | |
223 | * Perform each task, and continue on to the next task. | |
224 | */ | |
dc62b251 | 225 | for (sipp = start; sipp < stop; sipp++) { |
ba39e2e0 | 226 | if ((*sipp)->subsystem == SI_SPECIAL_DUMMY) |
984263bc MD |
227 | continue; /* skip dummy task(s)*/ |
228 | ||
229 | /* Call function */ | |
230 | (*((*sipp)->func))((*sipp)->udata); | |
231 | } | |
232 | } | |
233 | ||
234 | static void | |
235 | linker_file_register_sysctls(linker_file_t lf) | |
236 | { | |
dc62b251 | 237 | struct sysctl_oid **start, **stop, **oidp; |
984263bc MD |
238 | |
239 | KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n", | |
240 | lf->filename)); | |
241 | ||
dc62b251 | 242 | if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) |
d1786c1b | 243 | return; |
dc62b251 MD |
244 | for (oidp = start; oidp < stop; oidp++) |
245 | sysctl_register_oid(*oidp); | |
984263bc MD |
246 | } |
247 | ||
248 | static void | |
249 | linker_file_unregister_sysctls(linker_file_t lf) | |
250 | { | |
dc62b251 | 251 | struct sysctl_oid **start, **stop, **oidp; |
984263bc MD |
252 | |
253 | KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n", | |
254 | lf->filename)); | |
255 | ||
dc62b251 | 256 | if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) |
984263bc | 257 | return; |
dc62b251 MD |
258 | for (oidp = start; oidp < stop; oidp++) |
259 | sysctl_unregister_oid(*oidp); | |
984263bc MD |
260 | } |
261 | ||
1c0e3286 SS |
262 | static int |
263 | linker_file_register_modules(linker_file_t lf) | |
264 | { | |
265 | struct mod_metadata **start, **stop, **mdp; | |
266 | const moduledata_t *moddata; | |
267 | int first_error, error; | |
268 | ||
269 | KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n", | |
270 | lf->filename)); | |
271 | ||
272 | if (linker_file_lookup_set(lf, "modmetadata_set", &start, &stop, NULL) != 0) { | |
273 | /* | |
274 | * This fallback should be unnecessary, but if we get booted | |
275 | * from boot2 instead of loader and we are missing our | |
276 | * metadata then we have to try the best we can. | |
277 | */ | |
278 | if (lf == linker_kernel_file) { | |
279 | start = SET_BEGIN(modmetadata_set); | |
280 | stop = SET_LIMIT(modmetadata_set); | |
281 | } else | |
282 | return (0); | |
283 | } | |
284 | first_error = 0; | |
285 | for (mdp = start; mdp < stop; mdp++) { | |
286 | if ((*mdp)->md_type != MDT_MODULE) | |
287 | continue; | |
288 | moddata = (*mdp)->md_data; | |
289 | KLD_DPF(FILE, ("Registering module %s in %s\n", moddata->name, lf->filename)); | |
290 | error = module_register(moddata, lf); | |
291 | if (error) { | |
292 | kprintf("Module %s failed to register: %d\n", moddata->name, error); | |
293 | if (first_error == 0) | |
294 | first_error = error; | |
295 | } | |
296 | } | |
297 | return (first_error); | |
298 | } | |
299 | ||
300 | static void | |
301 | linker_init_kernel_modules(void) | |
302 | { | |
303 | ||
304 | linker_file_register_modules(linker_kernel_file); | |
305 | } | |
306 | ||
307 | SYSINIT(linker_kernel, SI_BOOT2_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0); | |
308 | ||
984263bc | 309 | int |
1c0e3286 | 310 | linker_load_file(const char *filename, linker_file_t *result) |
984263bc MD |
311 | { |
312 | linker_class_t lc; | |
313 | linker_file_t lf; | |
314 | int foundfile, error = 0; | |
984263bc MD |
315 | |
316 | /* Refuse to load modules if securelevel raised */ | |
7e42c007 | 317 | if (securelevel > 0 || kernel_mem_readonly) |
8d1e479a | 318 | return EPERM; |
984263bc MD |
319 | |
320 | lf = linker_find_file_by_name(filename); | |
321 | if (lf) { | |
322 | KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); | |
323 | *result = lf; | |
324 | lf->refs++; | |
325 | goto out; | |
326 | } | |
327 | ||
984263bc MD |
328 | lf = NULL; |
329 | foundfile = 0; | |
89e1aaa0 | 330 | TAILQ_FOREACH(lc, &classes, link) { |
984263bc MD |
331 | KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", |
332 | filename, lc->desc)); | |
333 | ||
1c0e3286 | 334 | error = lc->ops->load_file(filename, &lf); |
984263bc MD |
335 | /* |
336 | * If we got something other than ENOENT, then it exists but we cannot | |
337 | * load it for some other reason. | |
338 | */ | |
339 | if (error != ENOENT) | |
340 | foundfile = 1; | |
341 | if (lf) { | |
1c0e3286 SS |
342 | error = linker_file_register_modules(lf); |
343 | if (error == EEXIST) { | |
344 | linker_file_unload(lf /* , LINKER_UNLOAD_FORCE */); | |
345 | return (error); | |
b8fb634a | 346 | } |
b8fb634a | 347 | linker_file_register_sysctls(lf); |
1c0e3286 SS |
348 | linker_file_sysinit(lf); |
349 | lf->flags |= LINKER_FILE_LINKED; | |
984263bc | 350 | *result = lf; |
1c0e3286 | 351 | return (0); |
984263bc MD |
352 | } |
353 | } | |
354 | /* | |
355 | * Less than ideal, but tells the user whether it failed to load or | |
356 | * the module was not found. | |
357 | */ | |
828a7fe6 | 358 | if (foundfile) { |
1c0e3286 SS |
359 | /* |
360 | * If the file type has not been recognized by the last try | |
361 | * printout a message before to fail. | |
362 | */ | |
363 | if (error == ENOSYS) | |
364 | kprintf("linker_load_file: Unsupported file type\n"); | |
365 | ||
828a7fe6 HP |
366 | /* |
367 | * Format not recognized or otherwise unloadable. | |
368 | * When loading a module that is statically built into | |
369 | * the kernel EEXIST percolates back up as the return | |
22628b14 SW |
370 | * value. Preserve this so that apps can recognize this |
371 | * special case. | |
828a7fe6 HP |
372 | */ |
373 | if (error != EEXIST) | |
374 | error = ENOEXEC; | |
32832096 | 375 | } else { |
984263bc | 376 | error = ENOENT; /* Nothing found */ |
32832096 | 377 | } |
984263bc MD |
378 | |
379 | out: | |
984263bc MD |
380 | return error; |
381 | } | |
382 | ||
32e913d7 | 383 | |
984263bc MD |
384 | linker_file_t |
385 | linker_find_file_by_name(const char* filename) | |
386 | { | |
d8061892 | 387 | linker_file_t lf = NULL; |
984263bc | 388 | char *koname; |
a3d55cbb MD |
389 | int i; |
390 | ||
391 | for (i = strlen(filename); i > 0 && filename[i-1] != '/'; --i) | |
392 | ; | |
393 | filename += i; | |
984263bc | 394 | |
efda3bd0 | 395 | koname = kmalloc(strlen(filename) + 4, M_LINKER, M_WAITOK); |
f8c7a42d | 396 | ksprintf(koname, "%s.ko", filename); |
984263bc | 397 | |
5a4bb8ec | 398 | lockmgr(&llf_lock, LK_SHARED); |
89e1aaa0 | 399 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
400 | if (!strcmp(lf->filename, koname)) |
401 | break; | |
402 | if (!strcmp(lf->filename, filename)) | |
403 | break; | |
404 | } | |
5a4bb8ec | 405 | lockmgr(&llf_lock, LK_RELEASE); |
984263bc | 406 | |
984263bc | 407 | if (koname) |
efda3bd0 | 408 | kfree(koname, M_LINKER); |
984263bc MD |
409 | return lf; |
410 | } | |
411 | ||
412 | linker_file_t | |
413 | linker_find_file_by_id(int fileid) | |
414 | { | |
d8061892 | 415 | linker_file_t lf = NULL; |
984263bc | 416 | |
5a4bb8ec | 417 | lockmgr(&llf_lock, LK_SHARED); |
47491315 | 418 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
419 | if (lf->id == fileid) |
420 | break; | |
47491315 | 421 | } |
5a4bb8ec | 422 | lockmgr(&llf_lock, LK_RELEASE); |
984263bc MD |
423 | |
424 | return lf; | |
425 | } | |
426 | ||
66021a66 SW |
427 | int |
428 | linker_file_foreach(linker_predicate_t *predicate, void *context) | |
429 | { | |
430 | linker_file_t lf; | |
431 | int retval = 0; | |
432 | ||
5a4bb8ec | 433 | lockmgr(&llf_lock, LK_SHARED); |
66021a66 SW |
434 | TAILQ_FOREACH(lf, &linker_files, link) { |
435 | retval = predicate(lf, context); | |
436 | if (retval != 0) | |
437 | break; | |
438 | } | |
5a4bb8ec MD |
439 | lockmgr(&llf_lock, LK_RELEASE); |
440 | ||
66021a66 SW |
441 | return (retval); |
442 | } | |
443 | ||
984263bc MD |
444 | linker_file_t |
445 | linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) | |
446 | { | |
d8061892 | 447 | linker_file_t lf = NULL; |
984263bc MD |
448 | const char *filename; |
449 | ||
4f79e0ef | 450 | filename = linker_basename(pathname); |
8d1e479a AL |
451 | KLD_DPF(FILE, ("linker_make_file: new file, filename=%s, pathname=%s\n", |
452 | filename, pathname)); | |
4f79e0ef | 453 | |
5a4bb8ec | 454 | lockmgr(&llf_lock, LK_EXCLUSIVE); |
648f3ded | 455 | lf = kmalloc(sizeof(struct linker_file), M_LINKER, M_WAITOK | M_ZERO); |
984263bc MD |
456 | lf->refs = 1; |
457 | lf->userrefs = 0; | |
458 | lf->flags = 0; | |
1c0e3286 | 459 | lf->filename = linker_strdup(filename); |
8d1e479a | 460 | lf->pathname = linker_strdup(pathname); |
984263bc MD |
461 | lf->id = next_file_id++; |
462 | lf->ndeps = 0; | |
463 | lf->deps = NULL; | |
464 | STAILQ_INIT(&lf->common); | |
465 | TAILQ_INIT(&lf->modules); | |
466 | ||
467 | lf->priv = priv; | |
468 | lf->ops = ops; | |
469 | TAILQ_INSERT_TAIL(&linker_files, lf, link); | |
470 | ||
5a4bb8ec MD |
471 | lockmgr(&llf_lock, LK_RELEASE); |
472 | ||
984263bc MD |
473 | return lf; |
474 | } | |
475 | ||
476 | int | |
477 | linker_file_unload(linker_file_t file) | |
478 | { | |
3598cc14 | 479 | module_t mod, next; |
1c0e3286 | 480 | modlist_t ml, nextml; |
984263bc MD |
481 | struct common_symbol* cp; |
482 | int error = 0; | |
483 | int i; | |
484 | ||
485 | /* Refuse to unload modules if securelevel raised */ | |
7e42c007 | 486 | if (securelevel > 0 || kernel_mem_readonly) |
8d1e479a | 487 | return EPERM; |
984263bc MD |
488 | |
489 | KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); | |
1c0e3286 | 490 | |
5a4bb8ec | 491 | lockmgr(&llf_lock, LK_EXCLUSIVE); |
984263bc | 492 | |
1c0e3286 SS |
493 | /* Easy case of just dropping a reference. */ |
494 | if (file->refs > 1) { | |
495 | file->refs--; | |
5a4bb8ec | 496 | lockmgr(&llf_lock, LK_RELEASE); |
1c0e3286 SS |
497 | return (0); |
498 | } | |
984263bc | 499 | |
1c0e3286 SS |
500 | KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); |
501 | ||
502 | /* | |
503 | * Inform any modules associated with this file. | |
504 | */ | |
505 | mod = TAILQ_FIRST(&file->modules); | |
506 | for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { | |
507 | next = module_getfnext(mod); | |
e7a2d403 MD |
508 | |
509 | /* | |
1c0e3286 SS |
510 | * Give the module a chance to veto the unload. Note that the |
511 | * act of unloading the module may cause other modules in the | |
512 | * same file list to be unloaded recursively. | |
e7a2d403 | 513 | */ |
1c0e3286 SS |
514 | if ((error = module_unload(mod)) != 0) { |
515 | KLD_DPF(FILE, ("linker_file_unload: module %p vetoes unload\n", | |
516 | mod)); | |
5a4bb8ec | 517 | lockmgr(&llf_lock, LK_RELEASE); |
1c0e3286 SS |
518 | file->refs--; |
519 | goto out; | |
984263bc | 520 | } |
1c0e3286 | 521 | module_release(mod); |
984263bc MD |
522 | } |
523 | ||
1c0e3286 SS |
524 | TAILQ_FOREACH_MUTABLE(ml, &found_modules, link, nextml) { |
525 | if (ml->container == file) { | |
526 | TAILQ_REMOVE(&found_modules, ml, link); | |
527 | kfree(ml, M_LINKER); | |
528 | } | |
984263bc MD |
529 | } |
530 | ||
531 | /* Don't try to run SYSUNINITs if we are unloaded due to a link error */ | |
532 | if (file->flags & LINKER_FILE_LINKED) { | |
1c0e3286 | 533 | file->flags &= ~LINKER_FILE_LINKED; |
5a4bb8ec | 534 | lockmgr(&llf_lock, LK_RELEASE); |
984263bc MD |
535 | linker_file_sysuninit(file); |
536 | linker_file_unregister_sysctls(file); | |
5a4bb8ec | 537 | lockmgr(&llf_lock, LK_EXCLUSIVE); |
984263bc MD |
538 | } |
539 | ||
540 | TAILQ_REMOVE(&linker_files, file, link); | |
984263bc | 541 | |
1c0e3286 | 542 | if (file->deps) { |
5a4bb8ec | 543 | lockmgr(&llf_lock, LK_RELEASE); |
1c0e3286 SS |
544 | for (i = 0; i < file->ndeps; i++) |
545 | linker_file_unload(file->deps[i]); | |
5a4bb8ec | 546 | lockmgr(&llf_lock, LK_EXCLUSIVE); |
1c0e3286 SS |
547 | kfree(file->deps, M_LINKER); |
548 | file->deps = NULL; | |
549 | } | |
984263bc | 550 | |
1c0e3286 SS |
551 | while ((cp = STAILQ_FIRST(&file->common)) != NULL) { |
552 | STAILQ_REMOVE_HEAD(&file->common, link); | |
efda3bd0 | 553 | kfree(cp, M_LINKER); |
984263bc MD |
554 | } |
555 | ||
556 | file->ops->unload(file); | |
1c0e3286 SS |
557 | |
558 | if (file->filename) { | |
559 | kfree(file->filename, M_LINKER); | |
560 | file->filename = NULL; | |
561 | } | |
8d1e479a AL |
562 | if (file->pathname) { |
563 | kfree(file->pathname, M_LINKER); | |
564 | file->pathname = NULL; | |
565 | } | |
1c0e3286 | 566 | |
efda3bd0 | 567 | kfree(file, M_LINKER); |
984263bc | 568 | |
5a4bb8ec | 569 | lockmgr(&llf_lock, LK_RELEASE); |
1c0e3286 | 570 | |
984263bc MD |
571 | out: |
572 | return error; | |
573 | } | |
574 | ||
addd2777 | 575 | void |
984263bc MD |
576 | linker_file_add_dependancy(linker_file_t file, linker_file_t dep) |
577 | { | |
578 | linker_file_t* newdeps; | |
579 | ||
77652cad | 580 | newdeps = kmalloc((file->ndeps + 1) * sizeof(linker_file_t*), |
e7b4468c | 581 | M_LINKER, M_WAITOK | M_ZERO); |
984263bc MD |
582 | |
583 | if (file->deps) { | |
584 | bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); | |
efda3bd0 | 585 | kfree(file->deps, M_LINKER); |
984263bc MD |
586 | } |
587 | file->deps = newdeps; | |
588 | file->deps[file->ndeps] = dep; | |
589 | file->ndeps++; | |
984263bc MD |
590 | } |
591 | ||
dc62b251 MD |
592 | /* |
593 | * Locate a linker set and its contents. | |
594 | * This is a helper function to avoid linker_if.h exposure elsewhere. | |
595 | * Note: firstp and lastp are really void *** | |
596 | */ | |
597 | int | |
598 | linker_file_lookup_set(linker_file_t file, const char *name, | |
599 | void *firstp, void *lastp, int *countp) | |
600 | { | |
601 | return file->ops->lookup_set(file, name, firstp, lastp, countp); | |
602 | } | |
603 | ||
d1786c1b MD |
604 | int |
605 | linker_file_lookup_symbol(linker_file_t file, const char* name, int deps, caddr_t *raddr) | |
984263bc MD |
606 | { |
607 | c_linker_sym_t sym; | |
608 | linker_symval_t symval; | |
609 | linker_file_t lf; | |
984263bc MD |
610 | size_t common_size = 0; |
611 | int i; | |
612 | ||
1c0e3286 | 613 | KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", |
984263bc MD |
614 | file, name, deps)); |
615 | ||
616 | if (file->ops->lookup_symbol(file, name, &sym) == 0) { | |
617 | file->ops->symbol_values(file, sym, &symval); | |
d1786c1b MD |
618 | |
619 | /* | |
620 | * XXX Assume a common symbol if its value is 0 and it has a non-zero | |
621 | * size, otherwise it could be an absolute symbol with a value of 0. | |
622 | */ | |
d8061892 | 623 | if (symval.value == NULL && symval.size != 0) { |
984263bc MD |
624 | /* |
625 | * For commons, first look them up in the dependancies and | |
626 | * only allocate space if not found there. | |
627 | */ | |
628 | common_size = symval.size; | |
d1786c1b | 629 | } else { |
1c0e3286 | 630 | KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%p\n", symval.value)); |
d1786c1b MD |
631 | *raddr = symval.value; |
632 | return 0; | |
984263bc MD |
633 | } |
634 | } | |
984263bc MD |
635 | if (deps) { |
636 | for (i = 0; i < file->ndeps; i++) { | |
d1786c1b | 637 | if (linker_file_lookup_symbol(file->deps[i], name, 0, raddr) == 0) { |
1c0e3286 | 638 | KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%p\n", *raddr)); |
d1786c1b | 639 | return 0; |
984263bc MD |
640 | } |
641 | } | |
642 | ||
643 | /* If we have not found it in the dependencies, search globally */ | |
89e1aaa0 | 644 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
645 | /* But skip the current file if it's on the list */ |
646 | if (lf == file) | |
647 | continue; | |
648 | /* And skip the files we searched above */ | |
649 | for (i = 0; i < file->ndeps; i++) | |
650 | if (lf == file->deps[i]) | |
651 | break; | |
652 | if (i < file->ndeps) | |
653 | continue; | |
d1786c1b | 654 | if (linker_file_lookup_symbol(lf, name, 0, raddr) == 0) { |
1c0e3286 | 655 | KLD_DPF(SYM, ("linker_file_lookup_symbol: global value=%p\n", *raddr)); |
d1786c1b | 656 | return 0; |
984263bc MD |
657 | } |
658 | } | |
659 | } | |
660 | ||
661 | if (common_size > 0) { | |
662 | /* | |
663 | * This is a common symbol which was not found in the | |
664 | * dependancies. We maintain a simple common symbol table in | |
665 | * the file object. | |
666 | */ | |
667 | struct common_symbol* cp; | |
668 | ||
89e1aaa0 | 669 | STAILQ_FOREACH(cp, &file->common, link) |
984263bc | 670 | if (!strcmp(cp->name, name)) { |
1c0e3286 | 671 | KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%p\n", cp->address)); |
d1786c1b MD |
672 | *raddr = cp->address; |
673 | return 0; | |
984263bc MD |
674 | } |
675 | ||
676 | /* | |
677 | * Round the symbol size up to align. | |
678 | */ | |
679 | common_size = (common_size + sizeof(int) - 1) & -sizeof(int); | |
77652cad | 680 | cp = kmalloc(sizeof(struct common_symbol) |
984263bc MD |
681 | + common_size |
682 | + strlen(name) + 1, | |
e7b4468c | 683 | M_LINKER, M_WAITOK | M_ZERO); |
984263bc MD |
684 | |
685 | cp->address = (caddr_t) (cp + 1); | |
686 | cp->name = cp->address + common_size; | |
687 | strcpy(cp->name, name); | |
688 | bzero(cp->address, common_size); | |
689 | STAILQ_INSERT_TAIL(&file->common, cp, link); | |
690 | ||
1c0e3286 | 691 | KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%p\n", cp->address)); |
d1786c1b MD |
692 | *raddr = cp->address; |
693 | return 0; | |
984263bc MD |
694 | } |
695 | ||
6ef6faeb SS |
696 | #ifdef _KERNEL_VIRTUAL |
697 | *raddr = dlsym(RTLD_NEXT, name); | |
698 | if (*raddr != NULL) { | |
f130e9af | 699 | KLD_DPF(SYM, ("linker_file_lookup_symbol: found dlsym=%p\n", *raddr)); |
6ef6faeb SS |
700 | return 0; |
701 | } | |
702 | #endif | |
703 | ||
984263bc | 704 | KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); |
d1786c1b | 705 | return ENOENT; |
984263bc MD |
706 | } |
707 | ||
708 | #ifdef DDB | |
709 | /* | |
710 | * DDB Helpers. DDB has to look across multiple files with their own | |
711 | * symbol tables and string tables. | |
712 | * | |
713 | * Note that we do not obey list locking protocols here. We really don't | |
714 | * need DDB to hang because somebody's got the lock held. We'll take the | |
715 | * chance that the files list is inconsistant instead. | |
716 | */ | |
717 | ||
718 | int | |
719 | linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) | |
720 | { | |
721 | linker_file_t lf; | |
722 | ||
89e1aaa0 | 723 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
724 | if (lf->ops->lookup_symbol(lf, symstr, sym) == 0) |
725 | return 0; | |
726 | } | |
727 | return ENOENT; | |
728 | } | |
729 | ||
730 | int | |
731 | linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) | |
732 | { | |
733 | linker_file_t lf; | |
734 | u_long off = (uintptr_t)value; | |
735 | u_long diff, bestdiff; | |
736 | c_linker_sym_t best; | |
737 | c_linker_sym_t es; | |
738 | ||
d8061892 | 739 | best = NULL; |
984263bc | 740 | bestdiff = off; |
89e1aaa0 | 741 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
742 | if (lf->ops->search_symbol(lf, value, &es, &diff) != 0) |
743 | continue; | |
d8061892 | 744 | if (es != NULL && diff < bestdiff) { |
984263bc MD |
745 | best = es; |
746 | bestdiff = diff; | |
747 | } | |
748 | if (bestdiff == 0) | |
749 | break; | |
750 | } | |
751 | if (best) { | |
752 | *sym = best; | |
753 | *diffp = bestdiff; | |
754 | return 0; | |
755 | } else { | |
d8061892 | 756 | *sym = NULL; |
984263bc MD |
757 | *diffp = off; |
758 | return ENOENT; | |
759 | } | |
760 | } | |
761 | ||
762 | int | |
763 | linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) | |
764 | { | |
765 | linker_file_t lf; | |
766 | ||
89e1aaa0 | 767 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
768 | if (lf->ops->symbol_values(lf, sym, symval) == 0) |
769 | return 0; | |
770 | } | |
771 | return ENOENT; | |
772 | } | |
773 | ||
774 | #endif | |
775 | ||
776 | /* | |
777 | * Syscalls. | |
3919ced0 MD |
778 | * |
779 | * MPALMOSTSAFE | |
984263bc | 780 | */ |
984263bc | 781 | int |
80d831e1 | 782 | sys_kldload(struct sysmsg *sysmsg, const struct kldload_args *uap) |
984263bc | 783 | { |
1c0e3286 SS |
784 | char *file; |
785 | char *kldname, *modname; | |
984263bc MD |
786 | linker_file_t lf; |
787 | int error = 0; | |
788 | ||
80d831e1 | 789 | sysmsg->sysmsg_result = -1; |
984263bc | 790 | |
7e42c007 | 791 | if (securelevel > 0 || kernel_mem_readonly) /* redundant, but that's OK */ |
984263bc MD |
792 | return EPERM; |
793 | ||
2b3f93ea | 794 | if ((error = caps_priv_check_self(SYSCAP_NOKLD)) != 0) |
984263bc MD |
795 | return error; |
796 | ||
1c0e3286 SS |
797 | file = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
798 | if ((error = copyinstr(uap->file, file, MAXPATHLEN, NULL)) != 0) | |
984263bc MD |
799 | goto out; |
800 | ||
1c0e3286 SS |
801 | /* |
802 | * If file does not contain a qualified name or any dot in it | |
803 | * (kldname.ko, or kldname.ver.ko) treat it as an interface | |
804 | * name. | |
805 | */ | |
4f79e0ef | 806 | if (strchr(file, '/') || strchr(file, '.')) { |
1c0e3286 SS |
807 | kldname = file; |
808 | modname = NULL; | |
809 | } else { | |
810 | kldname = NULL; | |
811 | modname = file; | |
984263bc MD |
812 | } |
813 | ||
5a4bb8ec | 814 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
3919ced0 | 815 | error = linker_load_module(kldname, modname, NULL, NULL, &lf); |
5a4bb8ec | 816 | lockmgr(&kld_lock, LK_RELEASE); |
3919ced0 | 817 | if (error) |
984263bc MD |
818 | goto out; |
819 | ||
820 | lf->userrefs++; | |
80d831e1 | 821 | sysmsg->sysmsg_result = lf->id; |
984263bc MD |
822 | |
823 | out: | |
1c0e3286 SS |
824 | if (file) |
825 | kfree(file, M_TEMP); | |
984263bc MD |
826 | return error; |
827 | } | |
828 | ||
3919ced0 MD |
829 | /* |
830 | * MPALMOSTSAFE | |
831 | */ | |
984263bc | 832 | int |
80d831e1 | 833 | sys_kldunload(struct sysmsg *sysmsg, const struct kldunload_args *uap) |
984263bc MD |
834 | { |
835 | linker_file_t lf; | |
836 | int error = 0; | |
837 | ||
7e42c007 | 838 | if (securelevel > 0 || kernel_mem_readonly) /* redundant, but that's OK */ |
984263bc MD |
839 | return EPERM; |
840 | ||
2b3f93ea | 841 | if ((error = caps_priv_check_self(SYSCAP_NOKLD)) != 0) |
984263bc MD |
842 | return error; |
843 | ||
5a4bb8ec | 844 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
ab2eb4eb | 845 | lf = linker_find_file_by_id(uap->fileid); |
984263bc MD |
846 | if (lf) { |
847 | KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); | |
848 | if (lf->userrefs == 0) { | |
6ea70f76 | 849 | kprintf("linkerunload: attempt to unload file that was loaded by the kernel\n"); |
984263bc MD |
850 | error = EBUSY; |
851 | goto out; | |
852 | } | |
853 | lf->userrefs--; | |
854 | error = linker_file_unload(lf); | |
855 | if (error) | |
856 | lf->userrefs++; | |
3919ced0 | 857 | } else { |
984263bc | 858 | error = ENOENT; |
3919ced0 | 859 | } |
984263bc | 860 | out: |
5a4bb8ec MD |
861 | lockmgr(&kld_lock, LK_RELEASE); |
862 | ||
984263bc MD |
863 | return error; |
864 | } | |
865 | ||
3919ced0 MD |
866 | /* |
867 | * MPALMOSTSAFE | |
868 | */ | |
984263bc | 869 | int |
80d831e1 | 870 | sys_kldfind(struct sysmsg *sysmsg, const struct kldfind_args *uap) |
984263bc | 871 | { |
4f79e0ef AL |
872 | char *pathname; |
873 | const char *filename; | |
984263bc | 874 | linker_file_t lf; |
3919ced0 | 875 | int error; |
984263bc | 876 | |
80d831e1 | 877 | sysmsg->sysmsg_result = -1; |
984263bc | 878 | |
4f79e0ef AL |
879 | pathname = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
880 | if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) | |
984263bc MD |
881 | goto out; |
882 | ||
4f79e0ef | 883 | filename = linker_basename(pathname); |
984263bc | 884 | |
5a4bb8ec | 885 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
4f79e0ef | 886 | lf = linker_find_file_by_name(filename); |
984263bc | 887 | if (lf) |
80d831e1 | 888 | sysmsg->sysmsg_result = lf->id; |
984263bc MD |
889 | else |
890 | error = ENOENT; | |
5a4bb8ec | 891 | lockmgr(&kld_lock, LK_RELEASE); |
984263bc MD |
892 | |
893 | out: | |
4f79e0ef AL |
894 | if (pathname) |
895 | kfree(pathname, M_TEMP); | |
984263bc MD |
896 | return error; |
897 | } | |
898 | ||
3919ced0 MD |
899 | /* |
900 | * MPALMOSTSAFE | |
901 | */ | |
984263bc | 902 | int |
80d831e1 | 903 | sys_kldnext(struct sysmsg *sysmsg, const struct kldnext_args *uap) |
984263bc MD |
904 | { |
905 | linker_file_t lf; | |
906 | int error = 0; | |
907 | ||
5a4bb8ec | 908 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
3919ced0 | 909 | if (uap->fileid == 0) { |
8d1e479a | 910 | lf = TAILQ_FIRST(&linker_files); |
3919ced0 | 911 | } else { |
8d1e479a AL |
912 | lf = linker_find_file_by_id(uap->fileid); |
913 | if (lf == NULL) { | |
914 | error = ENOENT; | |
915 | goto out; | |
916 | } | |
917 | lf = TAILQ_NEXT(lf, link); | |
984263bc MD |
918 | } |
919 | ||
1c0e3286 SS |
920 | /* Skip partially loaded files. */ |
921 | while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) { | |
8d1e479a | 922 | lf = TAILQ_NEXT(lf, link); |
1c0e3286 SS |
923 | } |
924 | ||
925 | if (lf) | |
80d831e1 | 926 | sysmsg->sysmsg_result = lf->id; |
1c0e3286 | 927 | else |
80d831e1 | 928 | sysmsg->sysmsg_result = 0; |
984263bc | 929 | |
1c0e3286 | 930 | out: |
5a4bb8ec MD |
931 | lockmgr(&kld_lock, LK_RELEASE); |
932 | ||
984263bc MD |
933 | return error; |
934 | } | |
935 | ||
3919ced0 MD |
936 | /* |
937 | * MPALMOSTSAFE | |
938 | */ | |
984263bc | 939 | int |
80d831e1 | 940 | sys_kldstat(struct sysmsg *sysmsg, const struct kldstat_args *uap) |
984263bc MD |
941 | { |
942 | linker_file_t lf; | |
943 | int error = 0; | |
944 | int version; | |
945 | struct kld_file_stat* stat; | |
946 | int namelen; | |
947 | ||
5a4bb8ec | 948 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
ab2eb4eb | 949 | lf = linker_find_file_by_id(uap->fileid); |
984263bc MD |
950 | if (!lf) { |
951 | error = ENOENT; | |
952 | goto out; | |
953 | } | |
954 | ||
ab2eb4eb | 955 | stat = uap->stat; |
984263bc MD |
956 | |
957 | /* | |
958 | * Check the version of the user's structure. | |
959 | */ | |
960 | if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) | |
961 | goto out; | |
962 | if (version != sizeof(struct kld_file_stat)) { | |
963 | error = EINVAL; | |
964 | goto out; | |
965 | } | |
966 | ||
967 | namelen = strlen(lf->filename) + 1; | |
968 | if (namelen > MAXPATHLEN) | |
969 | namelen = MAXPATHLEN; | |
8d1e479a | 970 | if ((error = copyout(lf->filename, stat->name, namelen)) != 0) |
984263bc | 971 | goto out; |
8d1e479a AL |
972 | |
973 | namelen = strlen(lf->pathname) + 1; | |
974 | if (namelen > MAXPATHLEN) | |
975 | namelen = MAXPATHLEN; | |
976 | if ((error = copyout(lf->pathname, stat->pathname, namelen)) != 0) | |
977 | goto out; | |
978 | ||
984263bc MD |
979 | if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) |
980 | goto out; | |
981 | if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) | |
982 | goto out; | |
983 | if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0) | |
984 | goto out; | |
985 | if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) | |
986 | goto out; | |
987 | ||
80d831e1 | 988 | sysmsg->sysmsg_result = 0; |
984263bc MD |
989 | |
990 | out: | |
5a4bb8ec MD |
991 | lockmgr(&kld_lock, LK_RELEASE); |
992 | ||
984263bc MD |
993 | return error; |
994 | } | |
995 | ||
3919ced0 MD |
996 | /* |
997 | * MPALMOSTSAFE | |
998 | */ | |
984263bc | 999 | int |
80d831e1 | 1000 | sys_kldfirstmod(struct sysmsg *sysmsg, const struct kldfirstmod_args *uap) |
984263bc MD |
1001 | { |
1002 | linker_file_t lf; | |
1003 | int error = 0; | |
1004 | ||
5a4bb8ec | 1005 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
ab2eb4eb | 1006 | lf = linker_find_file_by_id(uap->fileid); |
984263bc MD |
1007 | if (lf) { |
1008 | if (TAILQ_FIRST(&lf->modules)) | |
80d831e1 | 1009 | sysmsg->sysmsg_result = module_getid(TAILQ_FIRST(&lf->modules)); |
984263bc | 1010 | else |
80d831e1 | 1011 | sysmsg->sysmsg_result = 0; |
3919ced0 | 1012 | } else { |
984263bc | 1013 | error = ENOENT; |
3919ced0 | 1014 | } |
5a4bb8ec | 1015 | lockmgr(&kld_lock, LK_RELEASE); |
984263bc MD |
1016 | |
1017 | return error; | |
1018 | } | |
1019 | ||
3919ced0 MD |
1020 | /* |
1021 | * MPALMOSTSAFE | |
1022 | */ | |
984263bc | 1023 | int |
80d831e1 | 1024 | sys_kldsym(struct sysmsg *sysmsg, const struct kldsym_args *uap) |
984263bc MD |
1025 | { |
1026 | char *symstr = NULL; | |
1027 | c_linker_sym_t sym; | |
1028 | linker_symval_t symval; | |
1029 | linker_file_t lf; | |
1030 | struct kld_sym_lookup lookup; | |
1031 | int error = 0; | |
1032 | ||
5a4bb8ec | 1033 | lockmgr(&kld_lock, LK_EXCLUSIVE); |
ab2eb4eb | 1034 | if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) |
984263bc | 1035 | goto out; |
ab2eb4eb | 1036 | if (lookup.version != sizeof(lookup) || uap->cmd != KLDSYM_LOOKUP) { |
984263bc MD |
1037 | error = EINVAL; |
1038 | goto out; | |
1039 | } | |
1040 | ||
efda3bd0 | 1041 | symstr = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
984263bc MD |
1042 | if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) |
1043 | goto out; | |
1044 | ||
ab2eb4eb DR |
1045 | if (uap->fileid != 0) { |
1046 | lf = linker_find_file_by_id(uap->fileid); | |
984263bc MD |
1047 | if (lf == NULL) { |
1048 | error = ENOENT; | |
1049 | goto out; | |
1050 | } | |
1051 | if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && | |
1052 | lf->ops->symbol_values(lf, sym, &symval) == 0) { | |
1053 | lookup.symvalue = (uintptr_t)symval.value; | |
1054 | lookup.symsize = symval.size; | |
ab2eb4eb | 1055 | error = copyout(&lookup, uap->data, sizeof(lookup)); |
984263bc MD |
1056 | } else |
1057 | error = ENOENT; | |
1058 | } else { | |
89e1aaa0 | 1059 | TAILQ_FOREACH(lf, &linker_files, link) { |
984263bc MD |
1060 | if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && |
1061 | lf->ops->symbol_values(lf, sym, &symval) == 0) { | |
1062 | lookup.symvalue = (uintptr_t)symval.value; | |
1063 | lookup.symsize = symval.size; | |
ab2eb4eb | 1064 | error = copyout(&lookup, uap->data, sizeof(lookup)); |
984263bc MD |
1065 | break; |
1066 | } | |
1067 | } | |
1068 | if (!lf) | |
1069 | error = ENOENT; | |
1070 | } | |
1071 | out: | |
5a4bb8ec | 1072 | lockmgr(&kld_lock, LK_RELEASE); |
984263bc | 1073 | if (symstr) |
efda3bd0 | 1074 | kfree(symstr, M_TEMP); |
5a4bb8ec | 1075 | |
984263bc MD |
1076 | return error; |
1077 | } | |
1078 | ||
32832096 | 1079 | /* |
1c0e3286 | 1080 | * Preloaded module support |
32832096 | 1081 | */ |
1c0e3286 SS |
1082 | |
1083 | static modlist_t | |
1084 | modlist_lookup(const char *name, int ver) | |
6456e0ad | 1085 | { |
1c0e3286 | 1086 | modlist_t mod; |
6456e0ad | 1087 | |
1c0e3286 SS |
1088 | TAILQ_FOREACH(mod, &found_modules, link) { |
1089 | if (strcmp(mod->name, name) == 0 && (ver == 0 || mod->version == ver)) | |
1090 | return (mod); | |
6456e0ad | 1091 | } |
1c0e3286 SS |
1092 | return (NULL); |
1093 | } | |
6456e0ad | 1094 | |
1c0e3286 SS |
1095 | static modlist_t |
1096 | modlist_lookup2(const char *name, struct mod_depend *verinfo) | |
1097 | { | |
1098 | modlist_t mod, bestmod; | |
1099 | int ver; | |
1100 | ||
1101 | if (verinfo == NULL) | |
1102 | return (modlist_lookup(name, 0)); | |
1103 | bestmod = NULL; | |
1104 | TAILQ_FOREACH(mod, &found_modules, link) { | |
1105 | if (strcmp(mod->name, name) != 0) | |
1106 | continue; | |
1107 | ver = mod->version; | |
1108 | if (ver == verinfo->md_ver_preferred) | |
1109 | return (mod); | |
1110 | if (ver >= verinfo->md_ver_minimum && | |
1111 | ver <= verinfo->md_ver_maximum && | |
1112 | (bestmod == NULL || ver > bestmod->version)) | |
1113 | bestmod = mod; | |
1114 | } | |
1115 | return (bestmod); | |
1116 | } | |
1117 | ||
32e913d7 JT |
1118 | int |
1119 | linker_reference_module(const char *modname, struct mod_depend *verinfo, | |
1120 | linker_file_t *result) | |
1121 | { | |
1122 | modlist_t mod; | |
1123 | int error; | |
1124 | ||
5a4bb8ec | 1125 | lockmgr(&llf_lock, LK_SHARED); |
32e913d7 JT |
1126 | if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { |
1127 | *result = mod->container; | |
1128 | (*result)->refs++; | |
5a4bb8ec | 1129 | lockmgr(&llf_lock, LK_RELEASE); |
32e913d7 JT |
1130 | return (0); |
1131 | } | |
1132 | ||
5a4bb8ec | 1133 | lockmgr(&llf_lock, LK_RELEASE); |
47491315 | 1134 | /*lockmgr(&kld_lock, LK_EXCLUSIVE);*/ |
240c3f5a | 1135 | error = linker_load_module(NULL, modname, NULL, verinfo, result); |
47491315 | 1136 | /*lockmgr(&kld_lock, LK_RELEASE);*/ |
5a4bb8ec | 1137 | |
32e913d7 JT |
1138 | return (error); |
1139 | } | |
1140 | ||
1141 | int | |
1142 | linker_release_module(const char *modname, struct mod_depend *verinfo, | |
1143 | linker_file_t lf) | |
1144 | { | |
1145 | modlist_t mod; | |
1146 | int error; | |
1147 | ||
5a4bb8ec | 1148 | lockmgr(&llf_lock, LK_SHARED); |
32e913d7 JT |
1149 | if (lf == NULL) { |
1150 | KASSERT(modname != NULL, | |
1151 | ("linker_release_module: no file or name")); | |
1152 | mod = modlist_lookup2(modname, verinfo); | |
1153 | if (mod == NULL) { | |
5a4bb8ec | 1154 | lockmgr(&llf_lock, LK_RELEASE); |
32e913d7 JT |
1155 | return (ESRCH); |
1156 | } | |
1157 | lf = mod->container; | |
1158 | } else | |
1159 | KASSERT(modname == NULL && verinfo == NULL, | |
1160 | ("linker_release_module: both file and name")); | |
5a4bb8ec | 1161 | lockmgr(&llf_lock, LK_RELEASE); |
47491315 | 1162 | /*lockmgr(&kld_lock, LK_EXCLUSIVE);*/ |
240c3f5a | 1163 | error = linker_file_unload(lf); |
47491315 | 1164 | /*lockmgr(&kld_lock, LK_RELEASE);*/ |
5a4bb8ec | 1165 | |
32e913d7 JT |
1166 | return (error); |
1167 | } | |
1168 | ||
1c0e3286 SS |
1169 | static modlist_t |
1170 | modlist_newmodule(const char *modname, int version, linker_file_t container) | |
1171 | { | |
1172 | modlist_t mod; | |
1173 | ||
1174 | mod = kmalloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); | |
1175 | if (mod == NULL) | |
1176 | panic("no memory for module list"); | |
1177 | mod->container = container; | |
1178 | mod->name = modname; | |
1179 | mod->version = version; | |
1180 | TAILQ_INSERT_TAIL(&found_modules, mod, link); | |
1181 | return (mod); | |
1182 | } | |
1183 | ||
1184 | static void | |
1185 | linker_addmodules(linker_file_t lf, struct mod_metadata **start, | |
1186 | struct mod_metadata **stop, int preload) | |
1187 | { | |
1188 | struct mod_metadata *mp, **mdp; | |
1189 | const char *modname; | |
1190 | int ver; | |
1191 | ||
1192 | for (mdp = start; mdp < stop; mdp++) { | |
1193 | mp = *mdp; | |
1194 | if (mp->md_type != MDT_VERSION) | |
1195 | continue; | |
1196 | modname = mp->md_cval; | |
1197 | ver = ((struct mod_version *)mp->md_data)->mv_version; | |
1198 | if (modlist_lookup(modname, ver) != NULL) { | |
1199 | kprintf("module %s already present!\n", modname); | |
1200 | /* XXX what can we do? this is a build error. :-( */ | |
6456e0ad | 1201 | continue; |
6456e0ad | 1202 | } |
1c0e3286 | 1203 | modlist_newmodule(modname, ver, lf); |
6456e0ad | 1204 | } |
6456e0ad MD |
1205 | } |
1206 | ||
984263bc MD |
1207 | static void |
1208 | linker_preload(void* arg) | |
1209 | { | |
1210 | caddr_t modptr; | |
1c0e3286 | 1211 | const char *modname, *nmodname; |
984263bc | 1212 | char *modtype; |
1c0e3286 | 1213 | linker_file_t lf, nlf; |
984263bc MD |
1214 | linker_class_t lc; |
1215 | int error; | |
1c0e3286 SS |
1216 | linker_file_list_t loaded_files; |
1217 | linker_file_list_t depended_files; | |
1218 | struct mod_metadata *mp, *nmp; | |
1219 | struct mod_metadata **start, **stop, **mdp, **nmdp; | |
1220 | struct mod_depend *verinfo; | |
1221 | int nver; | |
1222 | int resolves; | |
1223 | modlist_t mod; | |
dc62b251 | 1224 | struct sysinit **si_start, **si_stop; |
984263bc | 1225 | |
1c0e3286 SS |
1226 | TAILQ_INIT(&loaded_files); |
1227 | TAILQ_INIT(&depended_files); | |
1228 | TAILQ_INIT(&found_modules); | |
1229 | ||
984263bc MD |
1230 | modptr = NULL; |
1231 | while ((modptr = preload_search_next_name(modptr)) != NULL) { | |
1232 | modname = (char *)preload_search_info(modptr, MODINFO_NAME); | |
1233 | modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); | |
1234 | if (modname == NULL) { | |
6ea70f76 | 1235 | kprintf("Preloaded module at %p does not have a name!\n", modptr); |
984263bc MD |
1236 | continue; |
1237 | } | |
1238 | if (modtype == NULL) { | |
6ea70f76 | 1239 | kprintf("Preloaded module at %p does not have a type!\n", modptr); |
984263bc MD |
1240 | continue; |
1241 | } | |
6456e0ad | 1242 | |
1c0e3286 | 1243 | if (bootverbose) |
135d05a5 | 1244 | kprintf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr); |
984263bc | 1245 | lf = NULL; |
89e1aaa0 | 1246 | TAILQ_FOREACH(lc, &classes, link) { |
1c0e3286 SS |
1247 | error = lc->ops->preload_file(modname, &lf); |
1248 | if (!error) | |
984263bc | 1249 | break; |
1c0e3286 | 1250 | lf = NULL; |
984263bc | 1251 | } |
1c0e3286 SS |
1252 | if (lf) |
1253 | TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); | |
1254 | } | |
984263bc | 1255 | |
1c0e3286 SS |
1256 | /* |
1257 | * First get a list of stuff in the kernel. | |
1258 | */ | |
1259 | if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, | |
1260 | &stop, NULL) == 0) | |
1261 | linker_addmodules(linker_kernel_file, start, stop, 1); | |
1262 | ||
1263 | /* | |
1264 | * This is a once-off kinky bubble sort to resolve relocation | |
1265 | * dependency requirements. | |
1266 | */ | |
1267 | restart: | |
1268 | TAILQ_FOREACH(lf, &loaded_files, loaded) { | |
1269 | error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); | |
1270 | /* | |
1271 | * First, look to see if we would successfully link with this | |
1272 | * stuff. | |
1273 | */ | |
1274 | resolves = 1; /* unless we know otherwise */ | |
1275 | if (!error) { | |
1276 | for (mdp = start; mdp < stop; mdp++) { | |
1277 | mp = *mdp; | |
1278 | if (mp->md_type != MDT_DEPEND) | |
1279 | continue; | |
1280 | modname = mp->md_cval; | |
1281 | verinfo = mp->md_data; | |
1282 | for (nmdp = start; nmdp < stop; nmdp++) { | |
1283 | nmp = *nmdp; | |
1284 | if (nmp->md_type != MDT_VERSION) | |
1285 | continue; | |
1286 | nmodname = nmp->md_cval; | |
1287 | if (strcmp(modname, nmodname) == 0) | |
1288 | break; | |
1289 | } | |
1290 | if (nmdp < stop)/* it's a self reference */ | |
1291 | continue; | |
1292 | ||
1293 | /* | |
1294 | * ok, the module isn't here yet, we | |
1295 | * are not finished | |
984263bc | 1296 | */ |
1c0e3286 SS |
1297 | if (modlist_lookup2(modname, verinfo) == NULL) |
1298 | resolves = 0; | |
1299 | } | |
1300 | } | |
1301 | /* | |
1302 | * OK, if we found our modules, we can link. So, "provide" | |
1303 | * the modules inside and add it to the end of the link order | |
1304 | * list. | |
1305 | */ | |
1306 | if (resolves) { | |
1307 | if (!error) { | |
1308 | for (mdp = start; mdp < stop; mdp++) { | |
1309 | mp = *mdp; | |
1310 | if (mp->md_type != MDT_VERSION) | |
1311 | continue; | |
1312 | modname = mp->md_cval; | |
1313 | nver = ((struct mod_version *)mp->md_data)->mv_version; | |
1314 | if (modlist_lookup(modname, nver) != NULL) { | |
1315 | kprintf("module %s already present!\n", modname); | |
1316 | TAILQ_REMOVE(&loaded_files, lf, loaded); | |
1317 | linker_file_unload(lf /* , LINKER_UNLOAD_FORCE */ ); | |
1318 | /* we changed tailq next ptr */ | |
1319 | goto restart; | |
984263bc | 1320 | } |
1c0e3286 | 1321 | modlist_newmodule(modname, nver, lf); |
984263bc | 1322 | } |
984263bc | 1323 | } |
1c0e3286 SS |
1324 | TAILQ_REMOVE(&loaded_files, lf, loaded); |
1325 | TAILQ_INSERT_TAIL(&depended_files, lf, loaded); | |
1326 | /* | |
1327 | * Since we provided modules, we need to restart the | |
1328 | * sort so that the previous files that depend on us | |
1329 | * have a chance. Also, we've busted the tailq next | |
1330 | * pointer with the REMOVE. | |
1331 | */ | |
1332 | goto restart; | |
1333 | } | |
1334 | } | |
1335 | ||
1336 | /* | |
1337 | * At this point, we check to see what could not be resolved.. | |
1338 | */ | |
1339 | while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { | |
1340 | TAILQ_REMOVE(&loaded_files, lf, loaded); | |
1341 | kprintf("KLD file %s is missing dependencies\n", lf->filename); | |
1342 | linker_file_unload(lf /* , LINKER_UNLOAD_FORCE */ ); | |
1343 | } | |
1344 | ||
1345 | /* | |
1346 | * We made it. Finish off the linking in the order we determined. | |
1347 | */ | |
1348 | TAILQ_FOREACH_MUTABLE(lf, &depended_files, loaded, nlf) { | |
1349 | if (linker_kernel_file) { | |
1350 | linker_kernel_file->refs++; | |
1351 | linker_file_add_dependancy(lf, linker_kernel_file); | |
1352 | } | |
1353 | lf->userrefs++; | |
1354 | ||
1355 | error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); | |
1356 | if (!error) { | |
1357 | for (mdp = start; mdp < stop; mdp++) { | |
1358 | mp = *mdp; | |
1359 | if (mp->md_type != MDT_DEPEND) | |
1360 | continue; | |
1361 | modname = mp->md_cval; | |
1362 | verinfo = mp->md_data; | |
1363 | mod = modlist_lookup2(modname, verinfo); | |
1364 | /* Don't count self-dependencies */ | |
1365 | if (lf == mod->container) | |
1366 | continue; | |
1367 | mod->container->refs++; | |
1368 | linker_file_add_dependancy(lf, mod->container); | |
1369 | } | |
1370 | } | |
1371 | /* | |
1372 | * Now do relocation etc using the symbol search paths | |
1373 | * established by the dependencies | |
1374 | */ | |
1375 | error = lf->ops->preload_finish(lf); | |
1376 | if (error) { | |
1377 | TAILQ_REMOVE(&depended_files, lf, loaded); | |
1378 | kprintf("KLD file %s - could not finalize loading\n", | |
1379 | lf->filename); | |
1380 | linker_file_unload(lf /* , LINKER_UNLOAD_FORCE */); | |
1381 | continue; | |
984263bc | 1382 | } |
1c0e3286 SS |
1383 | linker_file_register_modules(lf); |
1384 | if (linker_file_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0) | |
1385 | sysinit_add(si_start, si_stop); | |
1386 | linker_file_register_sysctls(lf); | |
1387 | lf->flags |= LINKER_FILE_LINKED; | |
984263bc | 1388 | } |
1c0e3286 | 1389 | /* woohoo! we made it! */ |
984263bc MD |
1390 | } |
1391 | ||
ba39e2e0 | 1392 | SYSINIT(preload, SI_BOOT2_KLD, SI_ORDER_MIDDLE, linker_preload, 0); |
984263bc MD |
1393 | |
1394 | /* | |
1395 | * Search for a not-loaded module by name. | |
1396 | * | |
1397 | * Modules may be found in the following locations: | |
1398 | * | |
1399 | * - preloaded (result is just the module name) | |
1400 | * - on disk (result is full path to module) | |
1401 | * | |
984263bc MD |
1402 | * The search path can be manipulated via sysctl. Note that we use the ';' |
1403 | * character as a separator to be consistent with the bootloader. | |
1404 | */ | |
1405 | ||
d4b28782 | 1406 | static char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules.local"; |
984263bc MD |
1407 | |
1408 | SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, | |
1409 | sizeof(linker_path), "module load search path"); | |
446d0710 | 1410 | TUNABLE_STR("module_path", linker_path, sizeof(linker_path)); |
984263bc | 1411 | |
984263bc MD |
1412 | char * |
1413 | linker_search_path(const char *name) | |
1414 | { | |
fad57d0e | 1415 | struct nlookupdata nd; |
984263bc | 1416 | char *cp, *ep, *result; |
b6d2621b | 1417 | char *buf, *retbuf, *freebuf; |
555d1043 | 1418 | size_t name_len, prefix_len; |
1c0e3286 | 1419 | size_t result_len; |
555d1043 | 1420 | int sep; |
984263bc MD |
1421 | int error; |
1422 | enum vtype type; | |
1c0e3286 SS |
1423 | const char *exts[] = { "", ".ko", NULL }; |
1424 | const char **ext; | |
984263bc | 1425 | |
b6d2621b AL |
1426 | /* already full path */ |
1427 | if (name[0] == '/') | |
1428 | return linker_strdup(name); | |
1429 | ||
1430 | /* resolve to full path */ | |
1431 | if (strchr(name, '/') != NULL) { | |
1432 | result = NULL; | |
1433 | ||
1434 | /* adapted from sys___realpath() */ | |
1435 | error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_FOLLOW); | |
1436 | if (error == 0) { | |
1437 | nd.nl_flags |= NLC_SHAREDLOCK; | |
1438 | error = nlookup(&nd); | |
1439 | } | |
1440 | if (error == 0) { | |
1441 | if (nd.nl_flags & NLC_NCPISLOCKED) { | |
1442 | nd.nl_flags &= ~NLC_NCPISLOCKED; | |
1443 | cache_unlock(&nd.nl_nch); | |
1444 | } | |
1445 | error = cache_fullpath(curproc, &nd.nl_nch, NULL, | |
1446 | &retbuf, &freebuf, 0); | |
1447 | if (error == 0) { | |
1448 | result = linker_strdup(retbuf); | |
1449 | kfree(freebuf, M_TEMP); | |
1450 | } | |
1451 | } | |
1452 | nlookup_done(&nd); | |
1453 | ||
1454 | return (result); | |
1455 | } | |
984263bc MD |
1456 | |
1457 | /* traverse the linker path */ | |
b6d2621b | 1458 | buf = kmalloc(MAXPATHLEN, M_LINKER, M_WAITOK); |
984263bc | 1459 | cp = linker_path; |
555d1043 | 1460 | name_len = strlen(name); |
984263bc | 1461 | for (;;) { |
984263bc MD |
1462 | /* find the end of this component */ |
1463 | for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) | |
1464 | ; | |
555d1043 YT |
1465 | prefix_len = ep - cp; |
1466 | /* if this component doesn't end with a slash, add one */ | |
1467 | if (ep == cp || *(ep - 1) != '/') | |
1468 | sep = 1; | |
1469 | else | |
1470 | sep = 0; | |
1471 | ||
b6d2621b | 1472 | result = buf; |
555d1043 YT |
1473 | strncpy(result, cp, prefix_len); |
1474 | if (sep) | |
1475 | result[prefix_len++] = '/'; | |
1476 | strcpy(result + prefix_len, name); | |
984263bc | 1477 | |
1c0e3286 SS |
1478 | result_len = strlen(result); |
1479 | for (ext = exts; *ext != NULL; ext++) { | |
1480 | strcpy(result + result_len, *ext); | |
1481 | ||
1482 | /* | |
1483 | * Attempt to open the file, and return the path if we succeed and it's | |
1484 | * a regular file. | |
1485 | */ | |
1486 | error = nlookup_init(&nd, result, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); | |
1487 | if (error == 0) | |
1488 | error = vn_open(&nd, NULL, FREAD, 0); | |
1489 | if (error == 0) { | |
1490 | type = nd.nl_open_vp->v_type; | |
1491 | if (type == VREG) { | |
1492 | nlookup_done(&nd); | |
1493 | return (result); | |
1494 | } | |
fad57d0e | 1495 | } |
1c0e3286 | 1496 | nlookup_done(&nd); |
984263bc | 1497 | } |
1c0e3286 | 1498 | |
984263bc MD |
1499 | if (*ep == 0) |
1500 | break; | |
1501 | cp = ep + 1; | |
1502 | } | |
b6d2621b AL |
1503 | |
1504 | kfree(buf, M_LINKER); | |
984263bc MD |
1505 | return(NULL); |
1506 | } | |
1c0e3286 SS |
1507 | |
1508 | /* | |
1509 | * Find a file which contains given module and load it, if "parent" is not | |
1510 | * NULL, register a reference to it. | |
1511 | */ | |
1512 | static int | |
1513 | linker_load_module(const char *kldname, const char *modname, | |
1514 | struct linker_file *parent, struct mod_depend *verinfo, | |
1515 | struct linker_file **lfpp) | |
1516 | { | |
1517 | linker_file_t lfdep; | |
1518 | const char *filename; | |
1519 | char *pathname; | |
1520 | int error; | |
1521 | ||
1522 | if (modname == NULL) { | |
1523 | /* | |
1524 | * We have to load KLD | |
1525 | */ | |
1526 | KASSERT(verinfo == NULL, ("linker_load_module: verinfo is not NULL")); | |
1527 | pathname = linker_search_path(kldname); | |
1528 | } else { | |
1529 | if (modlist_lookup2(modname, verinfo) != NULL) | |
1530 | return (EEXIST); | |
135d05a5 | 1531 | if (kldname != NULL) { |
1c0e3286 | 1532 | pathname = linker_strdup(kldname); |
135d05a5 | 1533 | } else if (rootvnode == NULL) { |
1c0e3286 | 1534 | pathname = NULL; |
135d05a5 | 1535 | } else { |
1c0e3286 | 1536 | pathname = linker_search_path(modname); |
240c3f5a | 1537 | } |
1c0e3286 SS |
1538 | #if 0 |
1539 | /* | |
1540 | * Need to find a KLD with required module | |
1541 | */ | |
1542 | pathname = linker_search_module(modname, | |
1543 | strlen(modname), verinfo); | |
1544 | #endif | |
1545 | } | |
1546 | if (pathname == NULL) | |
1547 | return (ENOENT); | |
1548 | ||
1549 | /* | |
1550 | * Can't load more than one file with the same basename XXX: | |
1551 | * Actually it should be possible to have multiple KLDs with | |
1552 | * the same basename but different path because they can | |
1553 | * provide different versions of the same modules. | |
1554 | */ | |
4f79e0ef | 1555 | filename = linker_basename(pathname); |
1c0e3286 SS |
1556 | if (linker_find_file_by_name(filename)) |
1557 | error = EEXIST; | |
1558 | else | |
1559 | do { | |
1560 | error = linker_load_file(pathname, &lfdep); | |
1561 | if (error) | |
1562 | break; | |
1563 | if (modname && verinfo && modlist_lookup2(modname, verinfo) == NULL) { | |
1564 | linker_file_unload(lfdep /* , LINKER_UNLOAD_FORCE */ ); | |
1565 | error = ENOENT; | |
1566 | break; | |
1567 | } | |
1568 | if (parent) { | |
1569 | linker_file_add_dependancy(parent, lfdep); | |
1570 | } | |
1571 | if (lfpp) | |
1572 | *lfpp = lfdep; | |
1573 | } while (0); | |
1574 | kfree(pathname, M_LINKER); | |
1575 | return (error); | |
1576 | } | |
1577 | ||
1578 | /* | |
1579 | * This routine is responsible for finding dependencies of userland initiated | |
1580 | * kldload(2)'s of files. | |
1581 | */ | |
1582 | int | |
1583 | linker_load_dependencies(linker_file_t lf) | |
1584 | { | |
1585 | linker_file_t lfdep; | |
1586 | struct mod_metadata **start, **stop, **mdp, **nmdp; | |
1587 | struct mod_metadata *mp, *nmp; | |
1588 | struct mod_depend *verinfo; | |
1589 | modlist_t mod; | |
1590 | const char *modname, *nmodname; | |
1591 | int ver, error = 0, count; | |
1592 | ||
1593 | /* | |
1594 | * All files are dependant on /kernel. | |
1595 | */ | |
1596 | if (linker_kernel_file) { | |
1597 | linker_kernel_file->refs++; | |
1598 | linker_file_add_dependancy(lf, linker_kernel_file); | |
1599 | } | |
1600 | if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, &count) != 0) | |
1601 | return (0); | |
1602 | for (mdp = start; mdp < stop; mdp++) { | |
1603 | mp = *mdp; | |
1604 | if (mp->md_type != MDT_VERSION) | |
1605 | continue; | |
1606 | modname = mp->md_cval; | |
1607 | ver = ((struct mod_version *)mp->md_data)->mv_version; | |
1608 | mod = modlist_lookup(modname, ver); | |
1609 | if (mod != NULL) { | |
1610 | kprintf("interface %s.%d already present in the KLD '%s'!\n", | |
1611 | modname, ver, mod->container->filename); | |
1612 | return (EEXIST); | |
1613 | } | |
1614 | } | |
1615 | ||
1616 | for (mdp = start; mdp < stop; mdp++) { | |
1617 | mp = *mdp; | |
1618 | if (mp->md_type != MDT_DEPEND) | |
1619 | continue; | |
1620 | modname = mp->md_cval; | |
1621 | verinfo = mp->md_data; | |
1622 | nmodname = NULL; | |
1623 | for (nmdp = start; nmdp < stop; nmdp++) { | |
1624 | nmp = *nmdp; | |
1625 | if (nmp->md_type != MDT_VERSION) | |
1626 | continue; | |
1627 | nmodname = nmp->md_cval; | |
1628 | if (strcmp(modname, nmodname) == 0) | |
1629 | break; | |
1630 | } | |
1631 | if (nmdp < stop) /* early exit, it's a self reference */ | |
1632 | continue; | |
1633 | mod = modlist_lookup2(modname, verinfo); | |
1634 | if (mod) { /* woohoo, it's loaded already */ | |
1635 | lfdep = mod->container; | |
1636 | lfdep->refs++; | |
1637 | linker_file_add_dependancy(lf, lfdep); | |
1638 | continue; | |
1639 | } | |
1640 | error = linker_load_module(NULL, modname, lf, verinfo, NULL); | |
1641 | if (error) { | |
1642 | kprintf("KLD %s: depends on %s - not available or version mismatch\n", | |
1643 | lf->filename, modname); | |
1644 | break; | |
1645 | } | |
1646 | } | |
1647 | ||
1648 | if (error) | |
1649 | return (error); | |
1650 | linker_addmodules(lf, start, stop, 0); | |
777b8d88 | 1651 | return (0); |
1c0e3286 | 1652 | } |