Move all namei flags handling into kobj_load_file(). When I originally wrote this, I was going for maximum flexibility. However, after a private discussion with dholland@, I see how this will cause problems with the future world order of namei whenever that might be. At the moment, I don't need the extra flexibility, but if something comes up this may have to be revisited.diff -r1.44 -r1.45 src/sys/kern/kern_module.c
(jnemeth)
--- src/sys/kern/kern_module.c 2009/05/25 22:33:00 1.44
+++ src/sys/kern/kern_module.c 2009/05/26 08:34:23 1.45
@@ -1,1081 +1,1083 @@ | @@ -1,1081 +1,1083 @@ | |||
1 | /* $NetBSD: kern_module.c,v 1.44 2009/05/25 22:33:00 jnemeth Exp $ */ | 1 | /* $NetBSD: kern_module.c,v 1.45 2009/05/26 08:34:23 jnemeth Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software developed for The NetBSD Foundation | 7 | * This code is derived from software developed for The NetBSD Foundation | |
8 | * by Andrew Doran. | 8 | * by Andrew Doran. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Kernel module support. | 33 | * Kernel module support. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | #include <sys/cdefs.h> | 36 | #include <sys/cdefs.h> | |
37 | __KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.44 2009/05/25 22:33:00 jnemeth Exp $"); | 37 | __KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.45 2009/05/26 08:34:23 jnemeth Exp $"); | |
38 | 38 | |||
39 | #ifdef _KERNEL_OPT | 39 | #ifdef _KERNEL_OPT | |
40 | #include "opt_ddb.h" | 40 | #include "opt_ddb.h" | |
41 | #include "opt_modular.h" | 41 | #include "opt_modular.h" | |
42 | #endif | 42 | #endif | |
43 | 43 | |||
44 | #include <sys/param.h> | 44 | #include <sys/param.h> | |
45 | #include <sys/systm.h> | 45 | #include <sys/systm.h> | |
46 | #include <sys/kernel.h> | 46 | #include <sys/kernel.h> | |
47 | #include <sys/fcntl.h> | 47 | #include <sys/fcntl.h> | |
48 | #include <sys/proc.h> | 48 | #include <sys/proc.h> | |
49 | #include <sys/kauth.h> | 49 | #include <sys/kauth.h> | |
50 | #include <sys/kobj.h> | 50 | #include <sys/kobj.h> | |
51 | #include <sys/kmem.h> | 51 | #include <sys/kmem.h> | |
52 | #include <sys/module.h> | 52 | #include <sys/module.h> | |
53 | #include <sys/kauth.h> | 53 | #include <sys/kauth.h> | |
54 | #include <sys/kthread.h> | 54 | #include <sys/kthread.h> | |
55 | #include <sys/sysctl.h> | 55 | #include <sys/sysctl.h> | |
56 | #include <sys/namei.h> | 56 | #include <sys/namei.h> | |
57 | 57 | |||
58 | #include <uvm/uvm_extern.h> | 58 | #include <uvm/uvm_extern.h> | |
59 | 59 | |||
60 | #include <machine/stdarg.h> | 60 | #include <machine/stdarg.h> | |
61 | 61 | |||
62 | struct vm_map *module_map; | 62 | struct vm_map *module_map; | |
63 | 63 | |||
64 | struct modlist module_list = TAILQ_HEAD_INITIALIZER(module_list); | 64 | struct modlist module_list = TAILQ_HEAD_INITIALIZER(module_list); | |
65 | struct modlist module_bootlist = TAILQ_HEAD_INITIALIZER(module_bootlist); | 65 | struct modlist module_bootlist = TAILQ_HEAD_INITIALIZER(module_bootlist); | |
66 | static module_t *module_active; | 66 | static module_t *module_active; | |
67 | static char module_base[64]; | 67 | static char module_base[64]; | |
68 | static int module_verbose_on; | 68 | static int module_verbose_on; | |
69 | static int module_autoload_on = 1; | 69 | static int module_autoload_on = 1; | |
70 | u_int module_count; | 70 | u_int module_count; | |
71 | kmutex_t module_lock; | 71 | kmutex_t module_lock; | |
72 | u_int module_autotime = 10; | 72 | u_int module_autotime = 10; | |
73 | u_int module_gen = 1; | 73 | u_int module_gen = 1; | |
74 | static kcondvar_t module_thread_cv; | 74 | static kcondvar_t module_thread_cv; | |
75 | static kmutex_t module_thread_lock; | 75 | static kmutex_t module_thread_lock; | |
76 | static int module_thread_ticks; | 76 | static int module_thread_ticks; | |
77 | 77 | |||
78 | /* Ensure that the kernel's link set isn't empty. */ | 78 | /* Ensure that the kernel's link set isn't empty. */ | |
79 | static modinfo_t module_dummy; | 79 | static modinfo_t module_dummy; | |
80 | __link_set_add_rodata(modules, module_dummy); | 80 | __link_set_add_rodata(modules, module_dummy); | |
81 | 81 | |||
82 | static module_t *module_lookup(const char *); | 82 | static module_t *module_lookup(const char *); | |
83 | static int module_do_load(const char *, bool, int, prop_dictionary_t, | 83 | static int module_do_load(const char *, bool, int, prop_dictionary_t, | |
84 | module_t **, modclass_t class, bool); | 84 | module_t **, modclass_t class, bool); | |
85 | static int module_do_unload(const char *); | 85 | static int module_do_unload(const char *); | |
86 | static void module_error(const char *, ...) | 86 | static void module_error(const char *, ...) | |
87 | __attribute__((__format__(__printf__,1,2))); | 87 | __attribute__((__format__(__printf__,1,2))); | |
88 | static void module_print(const char *, ...) | 88 | static void module_print(const char *, ...) | |
89 | __attribute__((__format__(__printf__,1,2))); | 89 | __attribute__((__format__(__printf__,1,2))); | |
90 | static int module_do_builtin(const char *, module_t **); | 90 | static int module_do_builtin(const char *, module_t **); | |
91 | static int module_fetch_info(module_t *); | 91 | static int module_fetch_info(module_t *); | |
92 | static void module_thread(void *); | 92 | static void module_thread(void *); | |
93 | 93 | |||
94 | /* | 94 | /* | |
95 | * module_error: | 95 | * module_error: | |
96 | * | 96 | * | |
97 | * Utility function: log an error. | 97 | * Utility function: log an error. | |
98 | */ | 98 | */ | |
99 | static void | 99 | static void | |
100 | module_error(const char *fmt, ...) | 100 | module_error(const char *fmt, ...) | |
101 | { | 101 | { | |
102 | va_list ap; | 102 | va_list ap; | |
103 | 103 | |||
104 | va_start(ap, fmt); | 104 | va_start(ap, fmt); | |
105 | printf("WARNING: module error: "); | 105 | printf("WARNING: module error: "); | |
106 | vprintf(fmt, ap); | 106 | vprintf(fmt, ap); | |
107 | printf("\n"); | 107 | printf("\n"); | |
108 | va_end(ap); | 108 | va_end(ap); | |
109 | } | 109 | } | |
110 | 110 | |||
111 | /* | 111 | /* | |
112 | * module_print: | 112 | * module_print: | |
113 | * | 113 | * | |
114 | * Utility function: log verbose output. | 114 | * Utility function: log verbose output. | |
115 | */ | 115 | */ | |
116 | static void | 116 | static void | |
117 | module_print(const char *fmt, ...) | 117 | module_print(const char *fmt, ...) | |
118 | { | 118 | { | |
119 | va_list ap; | 119 | va_list ap; | |
120 | 120 | |||
121 | if (module_verbose_on) { | 121 | if (module_verbose_on) { | |
122 | va_start(ap, fmt); | 122 | va_start(ap, fmt); | |
123 | printf("DEBUG: module: "); | 123 | printf("DEBUG: module: "); | |
124 | vprintf(fmt, ap); | 124 | vprintf(fmt, ap); | |
125 | printf("\n"); | 125 | printf("\n"); | |
126 | va_end(ap); | 126 | va_end(ap); | |
127 | } | 127 | } | |
128 | } | 128 | } | |
129 | 129 | |||
130 | /* | 130 | /* | |
131 | * module_init: | 131 | * module_init: | |
132 | * | 132 | * | |
133 | * Initialize the module subsystem. | 133 | * Initialize the module subsystem. | |
134 | */ | 134 | */ | |
135 | void | 135 | void | |
136 | module_init(void) | 136 | module_init(void) | |
137 | { | 137 | { | |
138 | extern struct vm_map *module_map; | 138 | extern struct vm_map *module_map; | |
139 | int error; | 139 | int error; | |
140 | 140 | |||
141 | if (module_map == NULL) { | 141 | if (module_map == NULL) { | |
142 | module_map = kernel_map; | 142 | module_map = kernel_map; | |
143 | } | 143 | } | |
144 | mutex_init(&module_lock, MUTEX_DEFAULT, IPL_NONE); | 144 | mutex_init(&module_lock, MUTEX_DEFAULT, IPL_NONE); | |
145 | cv_init(&module_thread_cv, "modunload"); | 145 | cv_init(&module_thread_cv, "modunload"); | |
146 | mutex_init(&module_thread_lock, MUTEX_DEFAULT, IPL_NONE); | 146 | mutex_init(&module_thread_lock, MUTEX_DEFAULT, IPL_NONE); | |
147 | #ifdef MODULAR /* XXX */ | 147 | #ifdef MODULAR /* XXX */ | |
148 | module_init_md(); | 148 | module_init_md(); | |
149 | #endif | 149 | #endif | |
150 | 150 | |||
151 | #if __NetBSD_Version__ / 1000000 % 100 == 99 /* -current */ | 151 | #if __NetBSD_Version__ / 1000000 % 100 == 99 /* -current */ | |
152 | snprintf(module_base, sizeof(module_base), "/stand/%s/%s/modules", | 152 | snprintf(module_base, sizeof(module_base), "/stand/%s/%s/modules", | |
153 | machine, osrelease); | 153 | machine, osrelease); | |
154 | #else /* release */ | 154 | #else /* release */ | |
155 | snprintf(module_base, sizeof(module_base), "/stand/%s/%d.%d/modules", | 155 | snprintf(module_base, sizeof(module_base), "/stand/%s/%d.%d/modules", | |
156 | machine, __NetBSD_Version__ / 100000000, | 156 | machine, __NetBSD_Version__ / 100000000, | |
157 | __NetBSD_Version__ / 1000000 % 100); | 157 | __NetBSD_Version__ / 1000000 % 100); | |
158 | #endif | 158 | #endif | |
159 | 159 | |||
160 | error = kthread_create(PRI_VM, KTHREAD_MPSAFE, NULL, module_thread, | 160 | error = kthread_create(PRI_VM, KTHREAD_MPSAFE, NULL, module_thread, | |
161 | NULL, NULL, "modunload"); | 161 | NULL, NULL, "modunload"); | |
162 | if (error != 0) | 162 | if (error != 0) | |
163 | panic("module_init: %d", error); | 163 | panic("module_init: %d", error); | |
164 | } | 164 | } | |
165 | 165 | |||
166 | SYSCTL_SETUP(sysctl_module_setup, "sysctl module setup") | 166 | SYSCTL_SETUP(sysctl_module_setup, "sysctl module setup") | |
167 | { | 167 | { | |
168 | const struct sysctlnode *node = NULL; | 168 | const struct sysctlnode *node = NULL; | |
169 | 169 | |||
170 | sysctl_createv(clog, 0, NULL, NULL, | 170 | sysctl_createv(clog, 0, NULL, NULL, | |
171 | CTLFLAG_PERMANENT, | 171 | CTLFLAG_PERMANENT, | |
172 | CTLTYPE_NODE, "kern", NULL, | 172 | CTLTYPE_NODE, "kern", NULL, | |
173 | NULL, 0, NULL, 0, | 173 | NULL, 0, NULL, 0, | |
174 | CTL_KERN, CTL_EOL); | 174 | CTL_KERN, CTL_EOL); | |
175 | sysctl_createv(clog, 0, NULL, &node, | 175 | sysctl_createv(clog, 0, NULL, &node, | |
176 | CTLFLAG_PERMANENT, | 176 | CTLFLAG_PERMANENT, | |
177 | CTLTYPE_NODE, "module", | 177 | CTLTYPE_NODE, "module", | |
178 | SYSCTL_DESCR("Module options"), | 178 | SYSCTL_DESCR("Module options"), | |
179 | NULL, 0, NULL, 0, | 179 | NULL, 0, NULL, 0, | |
180 | CTL_KERN, CTL_CREATE, CTL_EOL); | 180 | CTL_KERN, CTL_CREATE, CTL_EOL); | |
181 | 181 | |||
182 | if (node == NULL) | 182 | if (node == NULL) | |
183 | return; | 183 | return; | |
184 | 184 | |||
185 | sysctl_createv(clog, 0, &node, NULL, | 185 | sysctl_createv(clog, 0, &node, NULL, | |
186 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, | 186 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, | |
187 | CTLTYPE_INT, "autoload", | 187 | CTLTYPE_INT, "autoload", | |
188 | SYSCTL_DESCR("Enable automatic load of modules"), | 188 | SYSCTL_DESCR("Enable automatic load of modules"), | |
189 | NULL, 0, &module_autoload_on, 0, | 189 | NULL, 0, &module_autoload_on, 0, | |
190 | CTL_CREATE, CTL_EOL); | 190 | CTL_CREATE, CTL_EOL); | |
191 | sysctl_createv(clog, 0, &node, NULL, | 191 | sysctl_createv(clog, 0, &node, NULL, | |
192 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, | 192 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, | |
193 | CTLTYPE_INT, "verbose", | 193 | CTLTYPE_INT, "verbose", | |
194 | SYSCTL_DESCR("Enable verbose output"), | 194 | SYSCTL_DESCR("Enable verbose output"), | |
195 | NULL, 0, &module_verbose_on, 0, | 195 | NULL, 0, &module_verbose_on, 0, | |
196 | CTL_CREATE, CTL_EOL); | 196 | CTL_CREATE, CTL_EOL); | |
197 | } | 197 | } | |
198 | 198 | |||
199 | /* | 199 | /* | |
200 | * module_init_class: | 200 | * module_init_class: | |
201 | * | 201 | * | |
202 | * Initialize all built-in and pre-loaded modules of the | 202 | * Initialize all built-in and pre-loaded modules of the | |
203 | * specified class. | 203 | * specified class. | |
204 | */ | 204 | */ | |
205 | void | 205 | void | |
206 | module_init_class(modclass_t class) | 206 | module_init_class(modclass_t class) | |
207 | { | 207 | { | |
208 | __link_set_decl(modules, modinfo_t); | 208 | __link_set_decl(modules, modinfo_t); | |
209 | modinfo_t *const *mip, *mi; | 209 | modinfo_t *const *mip, *mi; | |
210 | module_t *mod; | 210 | module_t *mod; | |
211 | 211 | |||
212 | mutex_enter(&module_lock); | 212 | mutex_enter(&module_lock); | |
213 | /* | 213 | /* | |
214 | * Builtins first. These can't depend on pre-loaded modules. | 214 | * Builtins first. These can't depend on pre-loaded modules. | |
215 | */ | 215 | */ | |
216 | __link_set_foreach(mip, modules) { | 216 | __link_set_foreach(mip, modules) { | |
217 | mi = *mip; | 217 | mi = *mip; | |
218 | if (mi == &module_dummy) { | 218 | if (mi == &module_dummy) { | |
219 | continue; | 219 | continue; | |
220 | } | 220 | } | |
221 | if (class != MODULE_CLASS_ANY && class != mi->mi_class) { | 221 | if (class != MODULE_CLASS_ANY && class != mi->mi_class) { | |
222 | continue; | 222 | continue; | |
223 | } | 223 | } | |
224 | (void)module_do_builtin(mi->mi_name, NULL); | 224 | (void)module_do_builtin(mi->mi_name, NULL); | |
225 | } | 225 | } | |
226 | /* | 226 | /* | |
227 | * Now preloaded modules. These will be pulled off the | 227 | * Now preloaded modules. These will be pulled off the | |
228 | * list as we call module_do_load(); | 228 | * list as we call module_do_load(); | |
229 | */ | 229 | */ | |
230 | do { | 230 | do { | |
231 | TAILQ_FOREACH(mod, &module_bootlist, mod_chain) { | 231 | TAILQ_FOREACH(mod, &module_bootlist, mod_chain) { | |
232 | mi = mod->mod_info; | 232 | mi = mod->mod_info; | |
233 | if (class != MODULE_CLASS_ANY && | 233 | if (class != MODULE_CLASS_ANY && | |
234 | class != mi->mi_class) | 234 | class != mi->mi_class) | |
235 | continue; | 235 | continue; | |
236 | module_do_load(mi->mi_name, false, 0, NULL, NULL, | 236 | module_do_load(mi->mi_name, false, 0, NULL, NULL, | |
237 | class, false); | 237 | class, false); | |
238 | break; | 238 | break; | |
239 | } | 239 | } | |
240 | } while (mod != NULL); | 240 | } while (mod != NULL); | |
241 | mutex_exit(&module_lock); | 241 | mutex_exit(&module_lock); | |
242 | } | 242 | } | |
243 | 243 | |||
244 | /* | 244 | /* | |
245 | * module_compatible: | 245 | * module_compatible: | |
246 | * | 246 | * | |
247 | * Return true if the two supplied kernel versions are said to | 247 | * Return true if the two supplied kernel versions are said to | |
248 | * have the same binary interface for kernel code. The entire | 248 | * have the same binary interface for kernel code. The entire | |
249 | * version is signficant for the development tree (-current), | 249 | * version is signficant for the development tree (-current), | |
250 | * major and minor versions are significant for official | 250 | * major and minor versions are significant for official | |
251 | * releases of the system. | 251 | * releases of the system. | |
252 | */ | 252 | */ | |
253 | bool | 253 | bool | |
254 | module_compatible(int v1, int v2) | 254 | module_compatible(int v1, int v2) | |
255 | { | 255 | { | |
256 | 256 | |||
257 | #if __NetBSD_Version__ / 1000000 % 100 == 99 /* -current */ | 257 | #if __NetBSD_Version__ / 1000000 % 100 == 99 /* -current */ | |
258 | return v1 == v2; | 258 | return v1 == v2; | |
259 | #else /* release */ | 259 | #else /* release */ | |
260 | return abs(v1 - v2) < 10000; | 260 | return abs(v1 - v2) < 10000; | |
261 | #endif | 261 | #endif | |
262 | } | 262 | } | |
263 | 263 | |||
264 | /* | 264 | /* | |
265 | * module_load: | 265 | * module_load: | |
266 | * | 266 | * | |
267 | * Load a single module from the file system. | 267 | * Load a single module from the file system. | |
268 | */ | 268 | */ | |
269 | int | 269 | int | |
270 | module_load(const char *filename, int flags, prop_dictionary_t props, | 270 | module_load(const char *filename, int flags, prop_dictionary_t props, | |
271 | modclass_t class) | 271 | modclass_t class) | |
272 | { | 272 | { | |
273 | int error; | 273 | int error; | |
274 | 274 | |||
275 | /* Authorize. */ | 275 | /* Authorize. */ | |
276 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | 276 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | |
277 | 0, (void *)(uintptr_t)MODCTL_LOAD, NULL, NULL); | 277 | 0, (void *)(uintptr_t)MODCTL_LOAD, NULL, NULL); | |
278 | if (error != 0) { | 278 | if (error != 0) { | |
279 | return error; | 279 | return error; | |
280 | } | 280 | } | |
281 | 281 | |||
282 | mutex_enter(&module_lock); | 282 | mutex_enter(&module_lock); | |
283 | error = module_do_load(filename, false, flags, props, NULL, class, | 283 | error = module_do_load(filename, false, flags, props, NULL, class, | |
284 | false); | 284 | false); | |
285 | mutex_exit(&module_lock); | 285 | mutex_exit(&module_lock); | |
286 | 286 | |||
287 | return error; | 287 | return error; | |
288 | } | 288 | } | |
289 | 289 | |||
290 | /* | 290 | /* | |
291 | * module_autoload: | 291 | * module_autoload: | |
292 | * | 292 | * | |
293 | * Load a single module from the file system, system initiated. | 293 | * Load a single module from the file system, system initiated. | |
294 | */ | 294 | */ | |
295 | int | 295 | int | |
296 | module_autoload(const char *filename, modclass_t class) | 296 | module_autoload(const char *filename, modclass_t class) | |
297 | { | 297 | { | |
298 | int error; | 298 | int error; | |
299 | 299 | |||
300 | KASSERT(mutex_owned(&module_lock)); | 300 | KASSERT(mutex_owned(&module_lock)); | |
301 | 301 | |||
302 | /* Nothing if the user has disabled it. */ | 302 | /* Nothing if the user has disabled it. */ | |
303 | if (!module_autoload_on) { | 303 | if (!module_autoload_on) { | |
304 | return EPERM; | 304 | return EPERM; | |
305 | } | 305 | } | |
306 | 306 | |||
307 | /* Disallow path seperators and magic symlinks. */ | 307 | /* Disallow path seperators and magic symlinks. */ | |
308 | if (strchr(filename, '/') != NULL || strchr(filename, '@') != NULL || | 308 | if (strchr(filename, '/') != NULL || strchr(filename, '@') != NULL || | |
309 | strchr(filename, '.') != NULL) { | 309 | strchr(filename, '.') != NULL) { | |
310 | return EPERM; | 310 | return EPERM; | |
311 | } | 311 | } | |
312 | 312 | |||
313 | /* Authorize. */ | 313 | /* Authorize. */ | |
314 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | 314 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | |
315 | 0, (void *)(uintptr_t)MODCTL_LOAD, (void *)(uintptr_t)1, NULL); | 315 | 0, (void *)(uintptr_t)MODCTL_LOAD, (void *)(uintptr_t)1, NULL); | |
316 | if (error != 0) { | 316 | if (error != 0) { | |
317 | return error; | 317 | return error; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | return module_do_load(filename, false, 0, NULL, NULL, class, true); | 320 | return module_do_load(filename, false, 0, NULL, NULL, class, true); | |
321 | } | 321 | } | |
322 | 322 | |||
323 | /* | 323 | /* | |
324 | * module_unload: | 324 | * module_unload: | |
325 | * | 325 | * | |
326 | * Find and unload a module by name. | 326 | * Find and unload a module by name. | |
327 | */ | 327 | */ | |
328 | int | 328 | int | |
329 | module_unload(const char *name) | 329 | module_unload(const char *name) | |
330 | { | 330 | { | |
331 | int error; | 331 | int error; | |
332 | 332 | |||
333 | /* Authorize. */ | 333 | /* Authorize. */ | |
334 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | 334 | error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, | |
335 | 0, (void *)(uintptr_t)MODCTL_UNLOAD, NULL, NULL); | 335 | 0, (void *)(uintptr_t)MODCTL_UNLOAD, NULL, NULL); | |
336 | if (error != 0) { | 336 | if (error != 0) { | |
337 | return error; | 337 | return error; | |
338 | } | 338 | } | |
339 | 339 | |||
340 | mutex_enter(&module_lock); | 340 | mutex_enter(&module_lock); | |
341 | error = module_do_unload(name); | 341 | error = module_do_unload(name); | |
342 | mutex_exit(&module_lock); | 342 | mutex_exit(&module_lock); | |
343 | 343 | |||
344 | return error; | 344 | return error; | |
345 | } | 345 | } | |
346 | 346 | |||
347 | /* | 347 | /* | |
348 | * module_lookup: | 348 | * module_lookup: | |
349 | * | 349 | * | |
350 | * Look up a module by name. | 350 | * Look up a module by name. | |
351 | */ | 351 | */ | |
352 | module_t * | 352 | module_t * | |
353 | module_lookup(const char *name) | 353 | module_lookup(const char *name) | |
354 | { | 354 | { | |
355 | module_t *mod; | 355 | module_t *mod; | |
356 | 356 | |||
357 | KASSERT(mutex_owned(&module_lock)); | 357 | KASSERT(mutex_owned(&module_lock)); | |
358 | 358 | |||
359 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | 359 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | |
360 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | 360 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | |
361 | break; | 361 | break; | |
362 | } | 362 | } | |
363 | } | 363 | } | |
364 | 364 | |||
365 | return mod; | 365 | return mod; | |
366 | } | 366 | } | |
367 | 367 | |||
368 | /* | 368 | /* | |
369 | * module_hold: | 369 | * module_hold: | |
370 | * | 370 | * | |
371 | * Add a single reference to a module. It's the caller's | 371 | * Add a single reference to a module. It's the caller's | |
372 | * responsibility to ensure that the reference is dropped | 372 | * responsibility to ensure that the reference is dropped | |
373 | * later. | 373 | * later. | |
374 | */ | 374 | */ | |
375 | int | 375 | int | |
376 | module_hold(const char *name) | 376 | module_hold(const char *name) | |
377 | { | 377 | { | |
378 | module_t *mod; | 378 | module_t *mod; | |
379 | 379 | |||
380 | mutex_enter(&module_lock); | 380 | mutex_enter(&module_lock); | |
381 | mod = module_lookup(name); | 381 | mod = module_lookup(name); | |
382 | if (mod == NULL) { | 382 | if (mod == NULL) { | |
383 | mutex_exit(&module_lock); | 383 | mutex_exit(&module_lock); | |
384 | return ENOENT; | 384 | return ENOENT; | |
385 | } | 385 | } | |
386 | mod->mod_refcnt++; | 386 | mod->mod_refcnt++; | |
387 | mutex_exit(&module_lock); | 387 | mutex_exit(&module_lock); | |
388 | 388 | |||
389 | return 0; | 389 | return 0; | |
390 | } | 390 | } | |
391 | 391 | |||
392 | /* | 392 | /* | |
393 | * module_rele: | 393 | * module_rele: | |
394 | * | 394 | * | |
395 | * Release a reference acquired with module_hold(). | 395 | * Release a reference acquired with module_hold(). | |
396 | */ | 396 | */ | |
397 | void | 397 | void | |
398 | module_rele(const char *name) | 398 | module_rele(const char *name) | |
399 | { | 399 | { | |
400 | module_t *mod; | 400 | module_t *mod; | |
401 | 401 | |||
402 | mutex_enter(&module_lock); | 402 | mutex_enter(&module_lock); | |
403 | mod = module_lookup(name); | 403 | mod = module_lookup(name); | |
404 | if (mod == NULL) { | 404 | if (mod == NULL) { | |
405 | mutex_exit(&module_lock); | 405 | mutex_exit(&module_lock); | |
406 | panic("module_rele: gone"); | 406 | panic("module_rele: gone"); | |
407 | } | 407 | } | |
408 | mod->mod_refcnt--; | 408 | mod->mod_refcnt--; | |
409 | mutex_exit(&module_lock); | 409 | mutex_exit(&module_lock); | |
410 | } | 410 | } | |
411 | 411 | |||
412 | /* | 412 | /* | |
413 | * module_enqueue: | 413 | * module_enqueue: | |
414 | * | 414 | * | |
415 | * Put a module onto the global list and update counters. | 415 | * Put a module onto the global list and update counters. | |
416 | */ | 416 | */ | |
417 | static void | 417 | static void | |
418 | module_enqueue(module_t *mod) | 418 | module_enqueue(module_t *mod) | |
419 | { | 419 | { | |
420 | int i; | 420 | int i; | |
421 | 421 | |||
422 | /* | 422 | /* | |
423 | * If there are requisite modules, put at the head of the queue. | 423 | * If there are requisite modules, put at the head of the queue. | |
424 | * This is so that autounload can unload requisite modules with | 424 | * This is so that autounload can unload requisite modules with | |
425 | * only one pass through the queue. | 425 | * only one pass through the queue. | |
426 | */ | 426 | */ | |
427 | if (mod->mod_nrequired) { | 427 | if (mod->mod_nrequired) { | |
428 | TAILQ_INSERT_HEAD(&module_list, mod, mod_chain); | 428 | TAILQ_INSERT_HEAD(&module_list, mod, mod_chain); | |
429 | 429 | |||
430 | /* Add references to the requisite modules. */ | 430 | /* Add references to the requisite modules. */ | |
431 | for (i = 0; i < mod->mod_nrequired; i++) { | 431 | for (i = 0; i < mod->mod_nrequired; i++) { | |
432 | KASSERT(mod->mod_required[i] != NULL); | 432 | KASSERT(mod->mod_required[i] != NULL); | |
433 | mod->mod_required[i]->mod_refcnt++; | 433 | mod->mod_required[i]->mod_refcnt++; | |
434 | } | 434 | } | |
435 | } else { | 435 | } else { | |
436 | TAILQ_INSERT_TAIL(&module_list, mod, mod_chain); | 436 | TAILQ_INSERT_TAIL(&module_list, mod, mod_chain); | |
437 | } | 437 | } | |
438 | module_count++; | 438 | module_count++; | |
439 | module_gen++; | 439 | module_gen++; | |
440 | } | 440 | } | |
441 | 441 | |||
442 | /* | 442 | /* | |
443 | * module_do_builtin: | 443 | * module_do_builtin: | |
444 | * | 444 | * | |
445 | * Initialize a single module from the list of modules that are | 445 | * Initialize a single module from the list of modules that are | |
446 | * built into the kernel (linked into the kernel image). | 446 | * built into the kernel (linked into the kernel image). | |
447 | */ | 447 | */ | |
448 | static int | 448 | static int | |
449 | module_do_builtin(const char *name, module_t **modp) | 449 | module_do_builtin(const char *name, module_t **modp) | |
450 | { | 450 | { | |
451 | __link_set_decl(modules, modinfo_t); | 451 | __link_set_decl(modules, modinfo_t); | |
452 | modinfo_t *const *mip; | 452 | modinfo_t *const *mip; | |
453 | const char *p, *s; | 453 | const char *p, *s; | |
454 | char buf[MAXMODNAME]; | 454 | char buf[MAXMODNAME]; | |
455 | modinfo_t *mi; | 455 | modinfo_t *mi; | |
456 | module_t *mod, *mod2; | 456 | module_t *mod, *mod2; | |
457 | size_t len; | 457 | size_t len; | |
458 | int error; | 458 | int error; | |
459 | 459 | |||
460 | KASSERT(mutex_owned(&module_lock)); | 460 | KASSERT(mutex_owned(&module_lock)); | |
461 | 461 | |||
462 | /* | 462 | /* | |
463 | * Check to see if already loaded. | 463 | * Check to see if already loaded. | |
464 | */ | 464 | */ | |
465 | if ((mod = module_lookup(name)) != NULL) { | 465 | if ((mod = module_lookup(name)) != NULL) { | |
466 | if (modp != NULL) { | 466 | if (modp != NULL) { | |
467 | *modp = mod; | 467 | *modp = mod; | |
468 | } | 468 | } | |
469 | return 0; | 469 | return 0; | |
470 | } | 470 | } | |
471 | 471 | |||
472 | /* | 472 | /* | |
473 | * Search the list to see if we have a module by this name. | 473 | * Search the list to see if we have a module by this name. | |
474 | */ | 474 | */ | |
475 | error = ENOENT; | 475 | error = ENOENT; | |
476 | __link_set_foreach(mip, modules) { | 476 | __link_set_foreach(mip, modules) { | |
477 | mi = *mip; | 477 | mi = *mip; | |
478 | if (mi == &module_dummy) { | 478 | if (mi == &module_dummy) { | |
479 | continue; | 479 | continue; | |
480 | } | 480 | } | |
481 | if (strcmp(mi->mi_name, name) == 0) { | 481 | if (strcmp(mi->mi_name, name) == 0) { | |
482 | error = 0; | 482 | error = 0; | |
483 | break; | 483 | break; | |
484 | } | 484 | } | |
485 | } | 485 | } | |
486 | if (error != 0) { | 486 | if (error != 0) { | |
487 | module_error("can't find `%s'", name); | 487 | module_error("can't find `%s'", name); | |
488 | return error; | 488 | return error; | |
489 | } | 489 | } | |
490 | 490 | |||
491 | /* | 491 | /* | |
492 | * Initialize pre-requisites. | 492 | * Initialize pre-requisites. | |
493 | */ | 493 | */ | |
494 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | 494 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | |
495 | if (mod == NULL) { | 495 | if (mod == NULL) { | |
496 | module_error("out of memory for `%s'", name); | 496 | module_error("out of memory for `%s'", name); | |
497 | return ENOMEM; | 497 | return ENOMEM; | |
498 | } | 498 | } | |
499 | if (modp != NULL) { | 499 | if (modp != NULL) { | |
500 | *modp = mod; | 500 | *modp = mod; | |
501 | } | 501 | } | |
502 | if (mi->mi_required != NULL) { | 502 | if (mi->mi_required != NULL) { | |
503 | for (s = mi->mi_required; *s != '\0'; s = p) { | 503 | for (s = mi->mi_required; *s != '\0'; s = p) { | |
504 | if (*s == ',') | 504 | if (*s == ',') | |
505 | s++; | 505 | s++; | |
506 | p = s; | 506 | p = s; | |
507 | while (*p != '\0' && *p != ',') | 507 | while (*p != '\0' && *p != ',') | |
508 | p++; | 508 | p++; | |
509 | len = min(p - s + 1, sizeof(buf)); | 509 | len = min(p - s + 1, sizeof(buf)); | |
510 | strlcpy(buf, s, len); | 510 | strlcpy(buf, s, len); | |
511 | if (buf[0] == '\0') | 511 | if (buf[0] == '\0') | |
512 | break; | 512 | break; | |
513 | if (mod->mod_nrequired == MAXMODDEPS - 1) { | 513 | if (mod->mod_nrequired == MAXMODDEPS - 1) { | |
514 | module_error("too many required modules"); | 514 | module_error("too many required modules"); | |
515 | kmem_free(mod, sizeof(*mod)); | 515 | kmem_free(mod, sizeof(*mod)); | |
516 | return EINVAL; | 516 | return EINVAL; | |
517 | } | 517 | } | |
518 | error = module_do_builtin(buf, &mod2); | 518 | error = module_do_builtin(buf, &mod2); | |
519 | if (error != 0) { | 519 | if (error != 0) { | |
520 | kmem_free(mod, sizeof(*mod)); | 520 | kmem_free(mod, sizeof(*mod)); | |
521 | return error; | 521 | return error; | |
522 | } | 522 | } | |
523 | mod->mod_required[mod->mod_nrequired++] = mod2; | 523 | mod->mod_required[mod->mod_nrequired++] = mod2; | |
524 | } | 524 | } | |
525 | } | 525 | } | |
526 | 526 | |||
527 | /* | 527 | /* | |
528 | * Try to initialize the module. | 528 | * Try to initialize the module. | |
529 | */ | 529 | */ | |
530 | KASSERT(module_active == NULL); | 530 | KASSERT(module_active == NULL); | |
531 | module_active = mod; | 531 | module_active = mod; | |
532 | error = (*mi->mi_modcmd)(MODULE_CMD_INIT, NULL); | 532 | error = (*mi->mi_modcmd)(MODULE_CMD_INIT, NULL); | |
533 | module_active = NULL; | 533 | module_active = NULL; | |
534 | if (error != 0) { | 534 | if (error != 0) { | |
535 | module_error("builtin module `%s' " | 535 | module_error("builtin module `%s' " | |
536 | "failed to init", mi->mi_name); | 536 | "failed to init", mi->mi_name); | |
537 | kmem_free(mod, sizeof(*mod)); | 537 | kmem_free(mod, sizeof(*mod)); | |
538 | return error; | 538 | return error; | |
539 | } | 539 | } | |
540 | mod->mod_info = mi; | 540 | mod->mod_info = mi; | |
541 | mod->mod_source = MODULE_SOURCE_KERNEL; | 541 | mod->mod_source = MODULE_SOURCE_KERNEL; | |
542 | module_enqueue(mod); | 542 | module_enqueue(mod); | |
543 | return 0; | 543 | return 0; | |
544 | } | 544 | } | |
545 | 545 | |||
546 | /* | 546 | /* | |
547 | * module_do_load: | 547 | * module_do_load: | |
548 | * | 548 | * | |
549 | * Helper routine: load a module from the file system, or one | 549 | * Helper routine: load a module from the file system, or one | |
550 | * pushed by the boot loader. | 550 | * pushed by the boot loader. | |
551 | */ | 551 | */ | |
552 | static int | 552 | static int | |
553 | module_do_load(const char *name, bool isdep, int flags, | 553 | module_do_load(const char *name, bool isdep, int flags, | |
554 | prop_dictionary_t props, module_t **modp, modclass_t class, | 554 | prop_dictionary_t props, module_t **modp, modclass_t class, | |
555 | bool autoload) | 555 | bool autoload) | |
556 | { | 556 | { | |
557 | static TAILQ_HEAD(,module) pending = TAILQ_HEAD_INITIALIZER(pending); | 557 | static TAILQ_HEAD(,module) pending = TAILQ_HEAD_INITIALIZER(pending); | |
558 | static int depth; | 558 | static int depth; | |
559 | const int maxdepth = 6; | 559 | const int maxdepth = 6; | |
560 | modinfo_t *mi; | 560 | modinfo_t *mi; | |
561 | module_t *mod, *mod2; | 561 | module_t *mod, *mod2; | |
562 | char buf[MAXMODNAME], *path; | 562 | char buf[MAXMODNAME], *path; | |
563 | const char *s, *p; | 563 | const char *s, *p; | |
564 | int error; | 564 | int error; | |
565 | size_t len; | 565 | size_t len; | |
566 | bool nochroot; | |||
566 | 567 | |||
567 | KASSERT(mutex_owned(&module_lock)); | 568 | KASSERT(mutex_owned(&module_lock)); | |
568 | 569 | |||
569 | error = 0; | 570 | error = 0; | |
570 | path=NULL; | 571 | path=NULL; | |
571 | 572 | |||
572 | /* | 573 | /* | |
573 | * Avoid recursing too far. | 574 | * Avoid recursing too far. | |
574 | */ | 575 | */ | |
575 | if (++depth > maxdepth) { | 576 | if (++depth > maxdepth) { | |
576 | module_error("too many required modules"); | 577 | module_error("too many required modules"); | |
577 | depth--; | 578 | depth--; | |
578 | return EMLINK; | 579 | return EMLINK; | |
579 | } | 580 | } | |
580 | 581 | |||
581 | /* | 582 | /* | |
582 | * Load the module and link. Before going to the file system, | 583 | * Load the module and link. Before going to the file system, | |
583 | * scan the list of modules loaded by the boot loader. Just | 584 | * scan the list of modules loaded by the boot loader. Just | |
584 | * before init is started the list of modules loaded at boot | 585 | * before init is started the list of modules loaded at boot | |
585 | * will be purged. Before init is started we can assume that | 586 | * will be purged. Before init is started we can assume that | |
586 | * `name' is a module name and not a path name. | 587 | * `name' is a module name and not a path name. | |
587 | */ | 588 | */ | |
588 | TAILQ_FOREACH(mod, &module_bootlist, mod_chain) { | 589 | TAILQ_FOREACH(mod, &module_bootlist, mod_chain) { | |
589 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | 590 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | |
590 | TAILQ_REMOVE(&module_bootlist, mod, mod_chain); | 591 | TAILQ_REMOVE(&module_bootlist, mod, mod_chain); | |
591 | break; | 592 | break; | |
592 | } | 593 | } | |
593 | } | 594 | } | |
594 | if (mod != NULL) { | 595 | if (mod != NULL) { | |
595 | TAILQ_INSERT_TAIL(&pending, mod, mod_chain); | 596 | TAILQ_INSERT_TAIL(&pending, mod, mod_chain); | |
596 | } else { | 597 | } else { | |
597 | /* | 598 | /* | |
598 | * If a requisite module, check to see if it is | 599 | * If a requisite module, check to see if it is | |
599 | * already present. | 600 | * already present. | |
600 | */ | 601 | */ | |
601 | if (isdep) { | 602 | if (isdep) { | |
602 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | 603 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | |
603 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | 604 | if (strcmp(mod->mod_info->mi_name, name) == 0) { | |
604 | break; | 605 | break; | |
605 | } | 606 | } | |
606 | } | 607 | } | |
607 | if (mod != NULL) { | 608 | if (mod != NULL) { | |
608 | if (modp != NULL) { | 609 | if (modp != NULL) { | |
609 | *modp = mod; | 610 | *modp = mod; | |
610 | } | 611 | } | |
611 | depth--; | 612 | depth--; | |
612 | return 0; | 613 | return 0; | |
613 | } | 614 | } | |
614 | } | 615 | } | |
615 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | 616 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | |
616 | if (mod == NULL) { | 617 | if (mod == NULL) { | |
617 | module_error("out of memory for `%s'", name); | 618 | module_error("out of memory for `%s'", name); | |
618 | depth--; | 619 | depth--; | |
619 | return ENOMEM; | 620 | return ENOMEM; | |
620 | } | 621 | } | |
621 | path = PNBUF_GET(); | 622 | path = PNBUF_GET(); | |
622 | if (!autoload) { | 623 | if (!autoload) { | |
624 | nochroot = false; | |||
623 | snprintf(path, MAXPATHLEN, "%s", name); | 625 | snprintf(path, MAXPATHLEN, "%s", name); | |
624 | error = kobj_load_file(&mod->mod_kobj, path, FOLLOW); | 626 | error = kobj_load_file(&mod->mod_kobj, path, nochroot); | |
625 | } | 627 | } | |
626 | if (autoload || (error == ENOENT)) { | 628 | if (autoload || (error == ENOENT)) { | |
629 | nochroot = true; | |||
627 | snprintf(path, MAXPATHLEN, "%s/%s/%s.kmod", | 630 | snprintf(path, MAXPATHLEN, "%s/%s/%s.kmod", | |
628 | module_base, name, name); | 631 | module_base, name, name); | |
629 | error = kobj_load_file(&mod->mod_kobj, path, | 632 | error = kobj_load_file(&mod->mod_kobj, path, nochroot); | |
630 | FOLLOW | NOCHROOT); | |||
631 | } | 633 | } | |
632 | if (error != 0) { | 634 | if (error != 0) { | |
633 | kmem_free(mod, sizeof(*mod)); | 635 | kmem_free(mod, sizeof(*mod)); | |
634 | depth--; | 636 | depth--; | |
635 | PNBUF_PUT(path); | 637 | PNBUF_PUT(path); | |
636 | if (autoload) { | 638 | if (autoload) { | |
637 | module_print("Cannot load kernel object `%s'" | 639 | module_print("Cannot load kernel object `%s'" | |
638 | " error=%d", name, error); | 640 | " error=%d", name, error); | |
639 | } else { | 641 | } else { | |
640 | module_error("Cannot load kernel object `%s'" | 642 | module_error("Cannot load kernel object `%s'" | |
641 | " error=%d", name, error); | 643 | " error=%d", name, error); | |
642 | } | 644 | } | |
643 | return error; | 645 | return error; | |
644 | } | 646 | } | |
645 | TAILQ_INSERT_TAIL(&pending, mod, mod_chain); | 647 | TAILQ_INSERT_TAIL(&pending, mod, mod_chain); | |
646 | mod->mod_source = MODULE_SOURCE_FILESYS; | 648 | mod->mod_source = MODULE_SOURCE_FILESYS; | |
647 | error = module_fetch_info(mod); | 649 | error = module_fetch_info(mod); | |
648 | if (error != 0) { | 650 | if (error != 0) { | |
649 | module_error("cannot fetch module info for `%s'", | 651 | module_error("cannot fetch module info for `%s'", | |
650 | name); | 652 | name); | |
651 | goto fail; | 653 | goto fail; | |
652 | } | 654 | } | |
653 | } | 655 | } | |
654 | 656 | |||
655 | /* | 657 | /* | |
656 | * Check compatibility. | 658 | * Check compatibility. | |
657 | */ | 659 | */ | |
658 | mi = mod->mod_info; | 660 | mi = mod->mod_info; | |
659 | if (strlen(mi->mi_name) >= MAXMODNAME) { | 661 | if (strlen(mi->mi_name) >= MAXMODNAME) { | |
660 | error = EINVAL; | 662 | error = EINVAL; | |
661 | module_error("module name `%s' too long", mi->mi_name); | 663 | module_error("module name `%s' too long", mi->mi_name); | |
662 | goto fail; | 664 | goto fail; | |
663 | } | 665 | } | |
664 | if (!module_compatible(mi->mi_version, __NetBSD_Version__)) { | 666 | if (!module_compatible(mi->mi_version, __NetBSD_Version__)) { | |
665 | module_error("module built for `%d', system `%d'", | 667 | module_error("module built for `%d', system `%d'", | |
666 | mi->mi_version, __NetBSD_Version__); | 668 | mi->mi_version, __NetBSD_Version__); | |
667 | if ((flags & MODCTL_LOAD_FORCE) != 0) { | 669 | if ((flags & MODCTL_LOAD_FORCE) != 0) { | |
668 | module_error("forced load, system may be unstable"); | 670 | module_error("forced load, system may be unstable"); | |
669 | } else { | 671 | } else { | |
670 | error = EPROGMISMATCH; | 672 | error = EPROGMISMATCH; | |
671 | goto fail; | 673 | goto fail; | |
672 | } | 674 | } | |
673 | } | 675 | } | |
674 | 676 | |||
675 | /* | 677 | /* | |
676 | * If a specific kind of module was requested, ensure that we have | 678 | * If a specific kind of module was requested, ensure that we have | |
677 | * a match. | 679 | * a match. | |
678 | */ | 680 | */ | |
679 | if (class != MODULE_CLASS_ANY && class != mi->mi_class) { | 681 | if (class != MODULE_CLASS_ANY && class != mi->mi_class) { | |
680 | module_print("incompatible module class for `%s' (%d != %d)", | 682 | module_print("incompatible module class for `%s' (%d != %d)", | |
681 | name, class, mi->mi_class); | 683 | name, class, mi->mi_class); | |
682 | error = ENOENT; | 684 | error = ENOENT; | |
683 | goto fail; | 685 | goto fail; | |
684 | } | 686 | } | |
685 | 687 | |||
686 | /* | 688 | /* | |
687 | * If loading a dependency, `name' is a plain module name. | 689 | * If loading a dependency, `name' is a plain module name. | |
688 | * The name must match. | 690 | * The name must match. | |
689 | */ | 691 | */ | |
690 | if (isdep && strcmp(mi->mi_name, name) != 0) { | 692 | if (isdep && strcmp(mi->mi_name, name) != 0) { | |
691 | module_error("dependency name mismatch (`%s' != `%s')", | 693 | module_error("dependency name mismatch (`%s' != `%s')", | |
692 | name, mi->mi_name); | 694 | name, mi->mi_name); | |
693 | error = ENOENT; | 695 | error = ENOENT; | |
694 | goto fail; | 696 | goto fail; | |
695 | } | 697 | } | |
696 | 698 | |||
697 | /* | 699 | /* | |
698 | * Check to see if the module is already loaded. If so, we may | 700 | * Check to see if the module is already loaded. If so, we may | |
699 | * have been recursively called to handle a dependency, so be sure | 701 | * have been recursively called to handle a dependency, so be sure | |
700 | * to set modp. | 702 | * to set modp. | |
701 | */ | 703 | */ | |
702 | if ((mod2 = module_lookup(mi->mi_name)) != NULL) { | 704 | if ((mod2 = module_lookup(mi->mi_name)) != NULL) { | |
703 | if (modp != NULL) | 705 | if (modp != NULL) | |
704 | *modp = mod2; | 706 | *modp = mod2; | |
705 | module_print("module `%s' already loaded", mi->mi_name); | 707 | module_print("module `%s' already loaded", mi->mi_name); | |
706 | error = EEXIST; | 708 | error = EEXIST; | |
707 | goto fail; | 709 | goto fail; | |
708 | } | 710 | } | |
709 | 711 | |||
710 | /* | 712 | /* | |
711 | * Block circular dependencies. | 713 | * Block circular dependencies. | |
712 | */ | 714 | */ | |
713 | TAILQ_FOREACH(mod2, &pending, mod_chain) { | 715 | TAILQ_FOREACH(mod2, &pending, mod_chain) { | |
714 | if (mod == mod2) { | 716 | if (mod == mod2) { | |
715 | continue; | 717 | continue; | |
716 | } | 718 | } | |
717 | if (strcmp(mod2->mod_info->mi_name, mi->mi_name) == 0) { | 719 | if (strcmp(mod2->mod_info->mi_name, mi->mi_name) == 0) { | |
718 | error = EDEADLK; | 720 | error = EDEADLK; | |
719 | module_error("circular dependency detected for `%s'", | 721 | module_error("circular dependency detected for `%s'", | |
720 | mi->mi_name); | 722 | mi->mi_name); | |
721 | goto fail; | 723 | goto fail; | |
722 | } | 724 | } | |
723 | } | 725 | } | |
724 | 726 | |||
725 | /* | 727 | /* | |
726 | * Now try to load any requisite modules. | 728 | * Now try to load any requisite modules. | |
727 | */ | 729 | */ | |
728 | if (mi->mi_required != NULL) { | 730 | if (mi->mi_required != NULL) { | |
729 | for (s = mi->mi_required; *s != '\0'; s = p) { | 731 | for (s = mi->mi_required; *s != '\0'; s = p) { | |
730 | if (*s == ',') | 732 | if (*s == ',') | |
731 | s++; | 733 | s++; | |
732 | p = s; | 734 | p = s; | |
733 | while (*p != '\0' && *p != ',') | 735 | while (*p != '\0' && *p != ',') | |
734 | p++; | 736 | p++; | |
735 | len = p - s + 1; | 737 | len = p - s + 1; | |
736 | if (len >= MAXMODNAME) { | 738 | if (len >= MAXMODNAME) { | |
737 | error = EINVAL; | 739 | error = EINVAL; | |
738 | module_error("required module name `%s'" | 740 | module_error("required module name `%s'" | |
739 | " too long", mi->mi_required); | 741 | " too long", mi->mi_required); | |
740 | goto fail; | 742 | goto fail; | |
741 | } | 743 | } | |
742 | strlcpy(buf, s, len); | 744 | strlcpy(buf, s, len); | |
743 | if (buf[0] == '\0') | 745 | if (buf[0] == '\0') | |
744 | break; | 746 | break; | |
745 | if (mod->mod_nrequired == MAXMODDEPS - 1) { | 747 | if (mod->mod_nrequired == MAXMODDEPS - 1) { | |
746 | error = EINVAL; | 748 | error = EINVAL; | |
747 | module_error("too many required modules (%d)", | 749 | module_error("too many required modules (%d)", | |
748 | mod->mod_nrequired); | 750 | mod->mod_nrequired); | |
749 | goto fail; | 751 | goto fail; | |
750 | } | 752 | } | |
751 | if (strcmp(buf, mi->mi_name) == 0) { | 753 | if (strcmp(buf, mi->mi_name) == 0) { | |
752 | error = EDEADLK; | 754 | error = EDEADLK; | |
753 | module_error("self-dependency detected for " | 755 | module_error("self-dependency detected for " | |
754 | "`%s'", mi->mi_name); | 756 | "`%s'", mi->mi_name); | |
755 | goto fail; | 757 | goto fail; | |
756 | } | 758 | } | |
757 | error = module_do_load(buf, true, flags, NULL, | 759 | error = module_do_load(buf, true, flags, NULL, | |
758 | &mod->mod_required[mod->mod_nrequired++], | 760 | &mod->mod_required[mod->mod_nrequired++], | |
759 | MODULE_CLASS_ANY, true); | 761 | MODULE_CLASS_ANY, true); | |
760 | if (error != 0) | 762 | if (error != 0) | |
761 | goto fail; | 763 | goto fail; | |
762 | } | 764 | } | |
763 | } | 765 | } | |
764 | 766 | |||
765 | /* | 767 | /* | |
766 | * We loaded all needed modules successfully: perform global | 768 | * We loaded all needed modules successfully: perform global | |
767 | * relocations and initialize. | 769 | * relocations and initialize. | |
768 | */ | 770 | */ | |
769 | error = kobj_affix(mod->mod_kobj, mi->mi_name); | 771 | error = kobj_affix(mod->mod_kobj, mi->mi_name); | |
770 | if (error != 0) { | 772 | if (error != 0) { | |
771 | /* Cannot touch 'mi' as the module is now gone. */ | 773 | /* Cannot touch 'mi' as the module is now gone. */ | |
772 | module_error("unable to affix module `%s'", name); | 774 | module_error("unable to affix module `%s'", name); | |
773 | goto fail2; | 775 | goto fail2; | |
774 | } | 776 | } | |
775 | 777 | |||
776 | KASSERT(module_active == NULL); | 778 | KASSERT(module_active == NULL); | |
777 | module_active = mod; | 779 | module_active = mod; | |
778 | error = (*mi->mi_modcmd)(MODULE_CMD_INIT, props); | 780 | error = (*mi->mi_modcmd)(MODULE_CMD_INIT, props); | |
779 | module_active = NULL; | 781 | module_active = NULL; | |
780 | if (error != 0) { | 782 | if (error != 0) { | |
781 | module_error("modcmd function returned error %d for `%s'", | 783 | module_error("modcmd function returned error %d for `%s'", | |
782 | error, mi->mi_name); | 784 | error, mi->mi_name); | |
783 | goto fail; | 785 | goto fail; | |
784 | } | 786 | } | |
785 | 787 | |||
786 | /* | 788 | /* | |
787 | * Good, the module loaded successfully. Put it onto the | 789 | * Good, the module loaded successfully. Put it onto the | |
788 | * list and add references to its requisite modules. | 790 | * list and add references to its requisite modules. | |
789 | */ | 791 | */ | |
790 | TAILQ_REMOVE(&pending, mod, mod_chain); | 792 | TAILQ_REMOVE(&pending, mod, mod_chain); | |
791 | module_enqueue(mod); | 793 | module_enqueue(mod); | |
792 | if (modp != NULL) { | 794 | if (modp != NULL) { | |
793 | *modp = mod; | 795 | *modp = mod; | |
794 | } | 796 | } | |
795 | if (autoload) { | 797 | if (autoload) { | |
796 | /* | 798 | /* | |
797 | * Arrange to try unloading the module after | 799 | * Arrange to try unloading the module after | |
798 | * a short delay. | 800 | * a short delay. | |
799 | */ | 801 | */ | |
800 | mod->mod_autotime = time_second + module_autotime; | 802 | mod->mod_autotime = time_second + module_autotime; | |
801 | module_thread_kick(); | 803 | module_thread_kick(); | |
802 | } | 804 | } | |
803 | depth--; | 805 | depth--; | |
804 | if (path != NULL) | 806 | if (path != NULL) | |
805 | PNBUF_PUT(path); | 807 | PNBUF_PUT(path); | |
806 | return 0; | 808 | return 0; | |
807 | 809 | |||
808 | fail: | 810 | fail: | |
809 | kobj_unload(mod->mod_kobj); | 811 | kobj_unload(mod->mod_kobj); | |
810 | fail2: | 812 | fail2: | |
811 | TAILQ_REMOVE(&pending, mod, mod_chain); | 813 | TAILQ_REMOVE(&pending, mod, mod_chain); | |
812 | kmem_free(mod, sizeof(*mod)); | 814 | kmem_free(mod, sizeof(*mod)); | |
813 | depth--; | 815 | depth--; | |
814 | if (path != NULL) | 816 | if (path != NULL) | |
815 | PNBUF_PUT(path); | 817 | PNBUF_PUT(path); | |
816 | return error; | 818 | return error; | |
817 | } | 819 | } | |
818 | 820 | |||
819 | /* | 821 | /* | |
820 | * module_do_unload: | 822 | * module_do_unload: | |
821 | * | 823 | * | |
822 | * Helper routine: do the dirty work of unloading a module. | 824 | * Helper routine: do the dirty work of unloading a module. | |
823 | */ | 825 | */ | |
824 | static int | 826 | static int | |
825 | module_do_unload(const char *name) | 827 | module_do_unload(const char *name) | |
826 | { | 828 | { | |
827 | module_t *mod; | 829 | module_t *mod; | |
828 | int error; | 830 | int error; | |
829 | u_int i; | 831 | u_int i; | |
830 | 832 | |||
831 | KASSERT(mutex_owned(&module_lock)); | 833 | KASSERT(mutex_owned(&module_lock)); | |
832 | 834 | |||
833 | mod = module_lookup(name); | 835 | mod = module_lookup(name); | |
834 | if (mod == NULL) { | 836 | if (mod == NULL) { | |
835 | module_error("module `%s' not found", name); | 837 | module_error("module `%s' not found", name); | |
836 | return ENOENT; | 838 | return ENOENT; | |
837 | } | 839 | } | |
838 | if (mod->mod_refcnt != 0 || mod->mod_source == MODULE_SOURCE_KERNEL) { | 840 | if (mod->mod_refcnt != 0 || mod->mod_source == MODULE_SOURCE_KERNEL) { | |
839 | module_print("module `%s' busy", name); | 841 | module_print("module `%s' busy", name); | |
840 | return EBUSY; | 842 | return EBUSY; | |
841 | } | 843 | } | |
842 | KASSERT(module_active == NULL); | 844 | KASSERT(module_active == NULL); | |
843 | module_active = mod; | 845 | module_active = mod; | |
844 | error = (*mod->mod_info->mi_modcmd)(MODULE_CMD_FINI, NULL); | 846 | error = (*mod->mod_info->mi_modcmd)(MODULE_CMD_FINI, NULL); | |
845 | module_active = NULL; | 847 | module_active = NULL; | |
846 | if (error != 0) { | 848 | if (error != 0) { | |
847 | module_print("cannot unload module `%s' error=%d", name, | 849 | module_print("cannot unload module `%s' error=%d", name, | |
848 | error); | 850 | error); | |
849 | return error; | 851 | return error; | |
850 | } | 852 | } | |
851 | module_count--; | 853 | module_count--; | |
852 | TAILQ_REMOVE(&module_list, mod, mod_chain); | 854 | TAILQ_REMOVE(&module_list, mod, mod_chain); | |
853 | for (i = 0; i < mod->mod_nrequired; i++) { | 855 | for (i = 0; i < mod->mod_nrequired; i++) { | |
854 | mod->mod_required[i]->mod_refcnt--; | 856 | mod->mod_required[i]->mod_refcnt--; | |
855 | } | 857 | } | |
856 | if (mod->mod_kobj != NULL) { | 858 | if (mod->mod_kobj != NULL) { | |
857 | kobj_unload(mod->mod_kobj); | 859 | kobj_unload(mod->mod_kobj); | |
858 | } | 860 | } | |
859 | kmem_free(mod, sizeof(*mod)); | 861 | kmem_free(mod, sizeof(*mod)); | |
860 | module_gen++; | 862 | module_gen++; | |
861 | 863 | |||
862 | return 0; | 864 | return 0; | |
863 | } | 865 | } | |
864 | 866 | |||
865 | /* | 867 | /* | |
866 | * module_prime: | 868 | * module_prime: | |
867 | * | 869 | * | |
868 | * Push a module loaded by the bootloader onto our internal | 870 | * Push a module loaded by the bootloader onto our internal | |
869 | * list. | 871 | * list. | |
870 | */ | 872 | */ | |
871 | int | 873 | int | |
872 | module_prime(void *base, size_t size) | 874 | module_prime(void *base, size_t size) | |
873 | { | 875 | { | |
874 | module_t *mod; | 876 | module_t *mod; | |
875 | int error; | 877 | int error; | |
876 | 878 | |||
877 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | 879 | mod = kmem_zalloc(sizeof(*mod), KM_SLEEP); | |
878 | if (mod == NULL) { | 880 | if (mod == NULL) { | |
879 | return ENOMEM; | 881 | return ENOMEM; | |
880 | } | 882 | } | |
881 | mod->mod_source = MODULE_SOURCE_BOOT; | 883 | mod->mod_source = MODULE_SOURCE_BOOT; | |
882 | 884 | |||
883 | error = kobj_load_mem(&mod->mod_kobj, base, size); | 885 | error = kobj_load_mem(&mod->mod_kobj, base, size); | |
884 | if (error != 0) { | 886 | if (error != 0) { | |
885 | kmem_free(mod, sizeof(*mod)); | 887 | kmem_free(mod, sizeof(*mod)); | |
886 | module_error("unable to load object pushed by boot loader"); | 888 | module_error("unable to load object pushed by boot loader"); | |
887 | return error; | 889 | return error; | |
888 | } | 890 | } | |
889 | error = module_fetch_info(mod); | 891 | error = module_fetch_info(mod); | |
890 | if (error != 0) { | 892 | if (error != 0) { | |
891 | kobj_unload(mod->mod_kobj); | 893 | kobj_unload(mod->mod_kobj); | |
892 | kmem_free(mod, sizeof(*mod)); | 894 | kmem_free(mod, sizeof(*mod)); | |
893 | module_error("unable to load object pushed by boot loader"); | 895 | module_error("unable to load object pushed by boot loader"); | |
894 | return error; | 896 | return error; | |
895 | } | 897 | } | |
896 | 898 | |||
897 | TAILQ_INSERT_TAIL(&module_bootlist, mod, mod_chain); | 899 | TAILQ_INSERT_TAIL(&module_bootlist, mod, mod_chain); | |
898 | 900 | |||
899 | return 0; | 901 | return 0; | |
900 | } | 902 | } | |
901 | 903 | |||
902 | /* | 904 | /* | |
903 | * module_fetch_into: | 905 | * module_fetch_into: | |
904 | * | 906 | * | |
905 | * Fetch modinfo record from a loaded module. | 907 | * Fetch modinfo record from a loaded module. | |
906 | */ | 908 | */ | |
907 | static int | 909 | static int | |
908 | module_fetch_info(module_t *mod) | 910 | module_fetch_info(module_t *mod) | |
909 | { | 911 | { | |
910 | int error; | 912 | int error; | |
911 | void *addr; | 913 | void *addr; | |
912 | size_t size; | 914 | size_t size; | |
913 | 915 | |||
914 | /* | 916 | /* | |
915 | * Find module info record and check compatibility. | 917 | * Find module info record and check compatibility. | |
916 | */ | 918 | */ | |
917 | error = kobj_find_section(mod->mod_kobj, "link_set_modules", | 919 | error = kobj_find_section(mod->mod_kobj, "link_set_modules", | |
918 | &addr, &size); | 920 | &addr, &size); | |
919 | if (error != 0) { | 921 | if (error != 0) { | |
920 | module_error("`link_set_modules' section not present"); | 922 | module_error("`link_set_modules' section not present"); | |
921 | return error; | 923 | return error; | |
922 | } | 924 | } | |
923 | if (size != sizeof(modinfo_t **)) { | 925 | if (size != sizeof(modinfo_t **)) { | |
924 | module_error("`link_set_modules' section wrong size"); | 926 | module_error("`link_set_modules' section wrong size"); | |
925 | return error; | 927 | return error; | |
926 | } | 928 | } | |
927 | mod->mod_info = *(modinfo_t **)addr; | 929 | mod->mod_info = *(modinfo_t **)addr; | |
928 | 930 | |||
929 | return 0; | 931 | return 0; | |
930 | } | 932 | } | |
931 | 933 | |||
932 | /* | 934 | /* | |
933 | * module_find_section: | 935 | * module_find_section: | |
934 | * | 936 | * | |
935 | * Allows a module that is being initialized to look up a section | 937 | * Allows a module that is being initialized to look up a section | |
936 | * within its ELF object. | 938 | * within its ELF object. | |
937 | */ | 939 | */ | |
938 | int | 940 | int | |
939 | module_find_section(const char *name, void **addr, size_t *size) | 941 | module_find_section(const char *name, void **addr, size_t *size) | |
940 | { | 942 | { | |
941 | 943 | |||
942 | KASSERT(mutex_owned(&module_lock)); | 944 | KASSERT(mutex_owned(&module_lock)); | |
943 | KASSERT(module_active != NULL); | 945 | KASSERT(module_active != NULL); | |
944 | 946 | |||
945 | return kobj_find_section(module_active->mod_kobj, name, addr, size); | 947 | return kobj_find_section(module_active->mod_kobj, name, addr, size); | |
946 | } | 948 | } | |
947 | 949 | |||
948 | /* | 950 | /* | |
949 | * module_thread: | 951 | * module_thread: | |
950 | * | 952 | * | |
951 | * Automatically unload modules. We try once to unload autoloaded | 953 | * Automatically unload modules. We try once to unload autoloaded | |
952 | * modules after module_autotime seconds. If the system is under | 954 | * modules after module_autotime seconds. If the system is under | |
953 | * severe memory pressure, we'll try unloading all modules. | 955 | * severe memory pressure, we'll try unloading all modules. | |
954 | */ | 956 | */ | |
955 | static void | 957 | static void | |
956 | module_thread(void *cookie) | 958 | module_thread(void *cookie) | |
957 | { | 959 | { | |
958 | module_t *mod, *next; | 960 | module_t *mod, *next; | |
959 | modinfo_t *mi; | 961 | modinfo_t *mi; | |
960 | int error; | 962 | int error; | |
961 | 963 | |||
962 | for (;;) { | 964 | for (;;) { | |
963 | mutex_enter(&module_lock); | 965 | mutex_enter(&module_lock); | |
964 | for (mod = TAILQ_FIRST(&module_list); mod != NULL; mod = next) { | 966 | for (mod = TAILQ_FIRST(&module_list); mod != NULL; mod = next) { | |
965 | next = TAILQ_NEXT(mod, mod_chain); | 967 | next = TAILQ_NEXT(mod, mod_chain); | |
966 | if (uvmexp.free < uvmexp.freemin) { | 968 | if (uvmexp.free < uvmexp.freemin) { | |
967 | module_thread_ticks = hz; | 969 | module_thread_ticks = hz; | |
968 | } else if (mod->mod_autotime == 0) { | 970 | } else if (mod->mod_autotime == 0) { | |
969 | continue; | 971 | continue; | |
970 | } else if (time_second < mod->mod_autotime) { | 972 | } else if (time_second < mod->mod_autotime) { | |
971 | module_thread_ticks = hz; | 973 | module_thread_ticks = hz; | |
972 | continue; | 974 | continue; | |
973 | } else { | 975 | } else { | |
974 | mod->mod_autotime = 0; | 976 | mod->mod_autotime = 0; | |
975 | } | 977 | } | |
976 | /* | 978 | /* | |
977 | * If this module wants to avoid autounload then | 979 | * If this module wants to avoid autounload then | |
978 | * skip it. Some modules can ping-pong in and out | 980 | * skip it. Some modules can ping-pong in and out | |
979 | * because their use is transient but often. | 981 | * because their use is transient but often. | |
980 | * Example: exec_script. | 982 | * Example: exec_script. | |
981 | */ | 983 | */ | |
982 | mi = mod->mod_info; | 984 | mi = mod->mod_info; | |
983 | error = (*mi->mi_modcmd)(MODULE_CMD_AUTOUNLOAD, NULL); | 985 | error = (*mi->mi_modcmd)(MODULE_CMD_AUTOUNLOAD, NULL); | |
984 | if (error == 0 || error == ENOTTY) { | 986 | if (error == 0 || error == ENOTTY) { | |
985 | (void)module_do_unload(mi->mi_name); | 987 | (void)module_do_unload(mi->mi_name); | |
986 | } | 988 | } | |
987 | } | 989 | } | |
988 | mutex_exit(&module_lock); | 990 | mutex_exit(&module_lock); | |
989 | 991 | |||
990 | mutex_enter(&module_thread_lock); | 992 | mutex_enter(&module_thread_lock); | |
991 | (void)cv_timedwait(&module_thread_cv, &module_thread_lock, | 993 | (void)cv_timedwait(&module_thread_cv, &module_thread_lock, | |
992 | module_thread_ticks); | 994 | module_thread_ticks); | |
993 | module_thread_ticks = 0; | 995 | module_thread_ticks = 0; | |
994 | mutex_exit(&module_thread_lock); | 996 | mutex_exit(&module_thread_lock); | |
995 | } | 997 | } | |
996 | } | 998 | } | |
997 | 999 | |||
998 | /* | 1000 | /* | |
999 | * module_thread: | 1001 | * module_thread: | |
1000 | * | 1002 | * | |
1001 | * Kick the module thread into action, perhaps because the | 1003 | * Kick the module thread into action, perhaps because the | |
1002 | * system is low on memory. | 1004 | * system is low on memory. | |
1003 | */ | 1005 | */ | |
1004 | void | 1006 | void | |
1005 | module_thread_kick(void) | 1007 | module_thread_kick(void) | |
1006 | { | 1008 | { | |
1007 | 1009 | |||
1008 | mutex_enter(&module_thread_lock); | 1010 | mutex_enter(&module_thread_lock); | |
1009 | module_thread_ticks = hz; | 1011 | module_thread_ticks = hz; | |
1010 | cv_broadcast(&module_thread_cv); | 1012 | cv_broadcast(&module_thread_cv); | |
1011 | mutex_exit(&module_thread_lock); | 1013 | mutex_exit(&module_thread_lock); | |
1012 | } | 1014 | } | |
1013 | 1015 | |||
1014 | #ifdef DDB | 1016 | #ifdef DDB | |
1015 | /* | 1017 | /* | |
1016 | * module_whatis: | 1018 | * module_whatis: | |
1017 | * | 1019 | * | |
1018 | * Helper routine for DDB. | 1020 | * Helper routine for DDB. | |
1019 | */ | 1021 | */ | |
1020 | void | 1022 | void | |
1021 | module_whatis(uintptr_t addr, void (*pr)(const char *, ...)) | 1023 | module_whatis(uintptr_t addr, void (*pr)(const char *, ...)) | |
1022 | { | 1024 | { | |
1023 | module_t *mod; | 1025 | module_t *mod; | |
1024 | size_t msize; | 1026 | size_t msize; | |
1025 | vaddr_t maddr; | 1027 | vaddr_t maddr; | |
1026 | 1028 | |||
1027 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | 1029 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | |
1028 | if (mod->mod_kobj == NULL) { | 1030 | if (mod->mod_kobj == NULL) { | |
1029 | continue; | 1031 | continue; | |
1030 | } | 1032 | } | |
1031 | kobj_stat(mod->mod_kobj, &maddr, &msize); | 1033 | kobj_stat(mod->mod_kobj, &maddr, &msize); | |
1032 | if (addr < maddr || addr >= maddr + msize) { | 1034 | if (addr < maddr || addr >= maddr + msize) { | |
1033 | continue; | 1035 | continue; | |
1034 | } | 1036 | } | |
1035 | (*pr)("%p is %p+%zu, in kernel module `%s'\n", | 1037 | (*pr)("%p is %p+%zu, in kernel module `%s'\n", | |
1036 | (void *)addr, (void *)maddr, | 1038 | (void *)addr, (void *)maddr, | |
1037 | (size_t)(addr - maddr), mod->mod_info->mi_name); | 1039 | (size_t)(addr - maddr), mod->mod_info->mi_name); | |
1038 | } | 1040 | } | |
1039 | } | 1041 | } | |
1040 | 1042 | |||
1041 | /* | 1043 | /* | |
1042 | * module_print_list: | 1044 | * module_print_list: | |
1043 | * | 1045 | * | |
1044 | * Helper routine for DDB. | 1046 | * Helper routine for DDB. | |
1045 | */ | 1047 | */ | |
1046 | void | 1048 | void | |
1047 | module_print_list(void (*pr)(const char *, ...)) | 1049 | module_print_list(void (*pr)(const char *, ...)) | |
1048 | { | 1050 | { | |
1049 | const char *src; | 1051 | const char *src; | |
1050 | module_t *mod; | 1052 | module_t *mod; | |
1051 | size_t msize; | 1053 | size_t msize; | |
1052 | vaddr_t maddr; | 1054 | vaddr_t maddr; | |
1053 | 1055 | |||
1054 | (*pr)("%16s %16s %8s %8s\n", "NAME", "TEXT/DATA", "SIZE", "SOURCE"); | 1056 | (*pr)("%16s %16s %8s %8s\n", "NAME", "TEXT/DATA", "SIZE", "SOURCE"); | |
1055 | 1057 | |||
1056 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | 1058 | TAILQ_FOREACH(mod, &module_list, mod_chain) { | |
1057 | switch (mod->mod_source) { | 1059 | switch (mod->mod_source) { | |
1058 | case MODULE_SOURCE_KERNEL: | 1060 | case MODULE_SOURCE_KERNEL: | |
1059 | src = "builtin"; | 1061 | src = "builtin"; | |
1060 | break; | 1062 | break; | |
1061 | case MODULE_SOURCE_FILESYS: | 1063 | case MODULE_SOURCE_FILESYS: | |
1062 | src = "filesys"; | 1064 | src = "filesys"; | |
1063 | break; | 1065 | break; | |
1064 | case MODULE_SOURCE_BOOT: | 1066 | case MODULE_SOURCE_BOOT: | |
1065 | src = "boot"; | 1067 | src = "boot"; | |
1066 | break; | 1068 | break; | |
1067 | default: | 1069 | default: | |
1068 | src = "unknown"; | 1070 | src = "unknown"; | |
1069 | break; | 1071 | break; | |
1070 | } | 1072 | } | |
1071 | if (mod->mod_kobj != NULL) { | 1073 | if (mod->mod_kobj != NULL) { | |
1072 | kobj_stat(mod->mod_kobj, &maddr, &msize); | 1074 | kobj_stat(mod->mod_kobj, &maddr, &msize); | |
1073 | } else { | 1075 | } else { | |
1074 | maddr = 0; | 1076 | maddr = 0; | |
1075 | msize = 0; | 1077 | msize = 0; | |
1076 | } | 1078 | } | |
1077 | (*pr)("%16s %16lx %8ld %8s\n", mod->mod_info->mi_name, | 1079 | (*pr)("%16s %16lx %8ld %8s\n", mod->mod_info->mi_name, | |
1078 | (long)maddr, (long)msize, src); | 1080 | (long)maddr, (long)msize, src); | |
1079 | } | 1081 | } | |
1080 | } | 1082 | } | |
1081 | #endif /* DDB */ | 1083 | #endif /* DDB */ |
--- src/sys/kern/subr_kobj.c 2009/05/25 22:33:00 1.37
+++ src/sys/kern/subr_kobj.c 2009/05/26 08:34:23 1.38
@@ -1,1149 +1,1150 @@ | @@ -1,1149 +1,1150 @@ | |||
1 | /* $NetBSD: subr_kobj.c,v 1.37 2009/05/25 22:33:00 jnemeth Exp $ */ | 1 | /* $NetBSD: subr_kobj.c,v 1.38 2009/05/26 08:34:23 jnemeth Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software developed for The NetBSD Foundation | 7 | * This code is derived from software developed for The NetBSD Foundation | |
8 | * by Andrew Doran. | 8 | * by Andrew Doran. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /*- | 32 | /*- | |
33 | * Copyright (c) 1998-2000 Doug Rabson | 33 | * Copyright (c) 1998-2000 Doug Rabson | |
34 | * Copyright (c) 2004 Peter Wemm | 34 | * Copyright (c) 2004 Peter Wemm | |
35 | * All rights reserved. | 35 | * All rights reserved. | |
36 | * | 36 | * | |
37 | * Redistribution and use in source and binary forms, with or without | 37 | * Redistribution and use in source and binary forms, with or without | |
38 | * modification, are permitted provided that the following conditions | 38 | * modification, are permitted provided that the following conditions | |
39 | * are met: | 39 | * are met: | |
40 | * 1. Redistributions of source code must retain the above copyright | 40 | * 1. Redistributions of source code must retain the above copyright | |
41 | * notice, this list of conditions and the following disclaimer. | 41 | * notice, this list of conditions and the following disclaimer. | |
42 | * 2. Redistributions in binary form must reproduce the above copyright | 42 | * 2. Redistributions in binary form must reproduce the above copyright | |
43 | * notice, this list of conditions and the following disclaimer in the | 43 | * notice, this list of conditions and the following disclaimer in the | |
44 | * documentation and/or other materials provided with the distribution. | 44 | * documentation and/or other materials provided with the distribution. | |
45 | * | 45 | * | |
46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
56 | * SUCH DAMAGE. | 56 | * SUCH DAMAGE. | |
57 | */ | 57 | */ | |
58 | 58 | |||
59 | /* | 59 | /* | |
60 | * Kernel loader for ELF objects. | 60 | * Kernel loader for ELF objects. | |
61 | * | 61 | * | |
62 | * TODO: adjust kmem_alloc() calls to avoid needless fragmentation. | 62 | * TODO: adjust kmem_alloc() calls to avoid needless fragmentation. | |
63 | */ | 63 | */ | |
64 | 64 | |||
65 | #include <sys/cdefs.h> | 65 | #include <sys/cdefs.h> | |
66 | __KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.37 2009/05/25 22:33:00 jnemeth Exp $"); | 66 | __KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.38 2009/05/26 08:34:23 jnemeth Exp $"); | |
67 | 67 | |||
68 | #include "opt_modular.h" | 68 | #include "opt_modular.h" | |
69 | 69 | |||
70 | #include <sys/kobj_impl.h> | 70 | #include <sys/kobj_impl.h> | |
71 | 71 | |||
72 | #ifdef MODULAR | 72 | #ifdef MODULAR | |
73 | 73 | |||
74 | #include <sys/param.h> | 74 | #include <sys/param.h> | |
75 | #include <sys/kernel.h> | 75 | #include <sys/kernel.h> | |
76 | #include <sys/kmem.h> | 76 | #include <sys/kmem.h> | |
77 | #include <sys/proc.h> | 77 | #include <sys/proc.h> | |
78 | #include <sys/namei.h> | 78 | #include <sys/namei.h> | |
79 | #include <sys/vnode.h> | 79 | #include <sys/vnode.h> | |
80 | #include <sys/fcntl.h> | 80 | #include <sys/fcntl.h> | |
81 | #include <sys/ksyms.h> | 81 | #include <sys/ksyms.h> | |
82 | #include <sys/module.h> | 82 | #include <sys/module.h> | |
83 | 83 | |||
84 | #include <machine/stdarg.h> | 84 | #include <machine/stdarg.h> | |
85 | 85 | |||
86 | #include <uvm/uvm_extern.h> | 86 | #include <uvm/uvm_extern.h> | |
87 | 87 | |||
88 | static int kobj_relocate(kobj_t, bool); | 88 | static int kobj_relocate(kobj_t, bool); | |
89 | static int kobj_checksyms(kobj_t, bool); | 89 | static int kobj_checksyms(kobj_t, bool); | |
90 | static void kobj_error(const char *, ...); | 90 | static void kobj_error(const char *, ...); | |
91 | static int kobj_read(kobj_t, void **, size_t, off_t); | 91 | static int kobj_read(kobj_t, void **, size_t, off_t); | |
92 | static int kobj_read_bits(kobj_t, void *, size_t, off_t); | 92 | static int kobj_read_bits(kobj_t, void *, size_t, off_t); | |
93 | static void kobj_jettison(kobj_t); | 93 | static void kobj_jettison(kobj_t); | |
94 | static void kobj_free(kobj_t, void *, size_t); | 94 | static void kobj_free(kobj_t, void *, size_t); | |
95 | static void kobj_close(kobj_t); | 95 | static void kobj_close(kobj_t); | |
96 | static int kobj_load(kobj_t); | 96 | static int kobj_load(kobj_t); | |
97 | 97 | |||
98 | extern struct vm_map *module_map; | 98 | extern struct vm_map *module_map; | |
99 | 99 | |||
100 | /* | 100 | /* | |
101 | * kobj_load_file: | 101 | * kobj_load_file: | |
102 | * | 102 | * | |
103 | * Load an object located in the file system. | 103 | * Load an object located in the file system. | |
104 | */ | 104 | */ | |
105 | int | 105 | int | |
106 | kobj_load_file(kobj_t *kop, const char *path, const uint32_t flags) | 106 | kobj_load_file(kobj_t *kop, const char *path, const bool nochroot) | |
107 | { | 107 | { | |
108 | struct nameidata nd; | 108 | struct nameidata nd; | |
109 | kauth_cred_t cred; | 109 | kauth_cred_t cred; | |
110 | int error; | 110 | int error; | |
111 | kobj_t ko; | 111 | kobj_t ko; | |
112 | 112 | |||
113 | cred = kauth_cred_get(); | 113 | cred = kauth_cred_get(); | |
114 | 114 | |||
115 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); | 115 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); | |
116 | if (ko == NULL) { | 116 | if (ko == NULL) { | |
117 | return ENOMEM; | 117 | return ENOMEM; | |
118 | } | 118 | } | |
119 | 119 | |||
120 | NDINIT(&nd, LOOKUP, flags, UIO_SYSSPACE, path); | 120 | NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), | |
121 | UIO_SYSSPACE, path); | |||
121 | error = vn_open(&nd, FREAD, 0); | 122 | error = vn_open(&nd, FREAD, 0); | |
122 | 123 | |||
123 | if (error != 0) { | 124 | if (error != 0) { | |
124 | kmem_free(ko, sizeof(*ko)); | 125 | kmem_free(ko, sizeof(*ko)); | |
125 | return error; | 126 | return error; | |
126 | } | 127 | } | |
127 | 128 | |||
128 | ko->ko_type = KT_VNODE; | 129 | ko->ko_type = KT_VNODE; | |
129 | ko->ko_source = nd.ni_vp; | 130 | ko->ko_source = nd.ni_vp; | |
130 | *kop = ko; | 131 | *kop = ko; | |
131 | return kobj_load(ko); | 132 | return kobj_load(ko); | |
132 | } | 133 | } | |
133 | 134 | |||
134 | /* | 135 | /* | |
135 | * kobj_load_mem: | 136 | * kobj_load_mem: | |
136 | * | 137 | * | |
137 | * Load an object already resident in memory. If size is not -1, | 138 | * Load an object already resident in memory. If size is not -1, | |
138 | * the complete size of the object is known. | 139 | * the complete size of the object is known. | |
139 | */ | 140 | */ | |
140 | int | 141 | int | |
141 | kobj_load_mem(kobj_t *kop, void *base, ssize_t size) | 142 | kobj_load_mem(kobj_t *kop, void *base, ssize_t size) | |
142 | { | 143 | { | |
143 | kobj_t ko; | 144 | kobj_t ko; | |
144 | 145 | |||
145 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); | 146 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); | |
146 | if (ko == NULL) { | 147 | if (ko == NULL) { | |
147 | return ENOMEM; | 148 | return ENOMEM; | |
148 | } | 149 | } | |
149 | 150 | |||
150 | ko->ko_type = KT_MEMORY; | 151 | ko->ko_type = KT_MEMORY; | |
151 | ko->ko_source = base; | 152 | ko->ko_source = base; | |
152 | ko->ko_memsize = size; | 153 | ko->ko_memsize = size; | |
153 | *kop = ko; | 154 | *kop = ko; | |
154 | return kobj_load(ko); | 155 | return kobj_load(ko); | |
155 | } | 156 | } | |
156 | 157 | |||
157 | /* | 158 | /* | |
158 | * kobj_close: | 159 | * kobj_close: | |
159 | * | 160 | * | |
160 | * Close an open ELF object. | 161 | * Close an open ELF object. | |
161 | */ | 162 | */ | |
162 | static void | 163 | static void | |
163 | kobj_close(kobj_t ko) | 164 | kobj_close(kobj_t ko) | |
164 | { | 165 | { | |
165 | 166 | |||
166 | if (ko->ko_source == NULL) { | 167 | if (ko->ko_source == NULL) { | |
167 | return; | 168 | return; | |
168 | } | 169 | } | |
169 | 170 | |||
170 | switch (ko->ko_type) { | 171 | switch (ko->ko_type) { | |
171 | case KT_VNODE: | 172 | case KT_VNODE: | |
172 | VOP_UNLOCK(ko->ko_source, 0); | 173 | VOP_UNLOCK(ko->ko_source, 0); | |
173 | vn_close(ko->ko_source, FREAD, kauth_cred_get()); | 174 | vn_close(ko->ko_source, FREAD, kauth_cred_get()); | |
174 | break; | 175 | break; | |
175 | case KT_MEMORY: | 176 | case KT_MEMORY: | |
176 | /* nothing */ | 177 | /* nothing */ | |
177 | break; | 178 | break; | |
178 | default: | 179 | default: | |
179 | panic("kobj_close: unknown type"); | 180 | panic("kobj_close: unknown type"); | |
180 | break; | 181 | break; | |
181 | } | 182 | } | |
182 | 183 | |||
183 | ko->ko_source = NULL; | 184 | ko->ko_source = NULL; | |
184 | } | 185 | } | |
185 | 186 | |||
186 | /* | 187 | /* | |
187 | * kobj_load: | 188 | * kobj_load: | |
188 | * | 189 | * | |
189 | * Load an ELF object and prepare to link into the running kernel | 190 | * Load an ELF object and prepare to link into the running kernel | |
190 | * image. | 191 | * image. | |
191 | */ | 192 | */ | |
192 | static int | 193 | static int | |
193 | kobj_load(kobj_t ko) | 194 | kobj_load(kobj_t ko) | |
194 | { | 195 | { | |
195 | Elf_Ehdr *hdr; | 196 | Elf_Ehdr *hdr; | |
196 | Elf_Shdr *shdr; | 197 | Elf_Shdr *shdr; | |
197 | Elf_Sym *es; | 198 | Elf_Sym *es; | |
198 | vaddr_t mapbase; | 199 | vaddr_t mapbase; | |
199 | size_t mapsize; | 200 | size_t mapsize; | |
200 | int error; | 201 | int error; | |
201 | int symtabindex; | 202 | int symtabindex; | |
202 | int symstrindex; | 203 | int symstrindex; | |
203 | int nsym; | 204 | int nsym; | |
204 | int pb, rl, ra; | 205 | int pb, rl, ra; | |
205 | int alignmask; | 206 | int alignmask; | |
206 | int i, j; | 207 | int i, j; | |
207 | void *addr; | 208 | void *addr; | |
208 | 209 | |||
209 | KASSERT(ko->ko_type != KT_UNSET); | 210 | KASSERT(ko->ko_type != KT_UNSET); | |
210 | KASSERT(ko->ko_source != NULL); | 211 | KASSERT(ko->ko_source != NULL); | |
211 | 212 | |||
212 | shdr = NULL; | 213 | shdr = NULL; | |
213 | mapsize = 0; | 214 | mapsize = 0; | |
214 | error = 0; | 215 | error = 0; | |
215 | hdr = NULL; | 216 | hdr = NULL; | |
216 | 217 | |||
217 | /* | 218 | /* | |
218 | * Read the elf header from the file. | 219 | * Read the elf header from the file. | |
219 | */ | 220 | */ | |
220 | error = kobj_read(ko, (void **)&hdr, sizeof(*hdr), 0); | 221 | error = kobj_read(ko, (void **)&hdr, sizeof(*hdr), 0); | |
221 | if (error != 0) | 222 | if (error != 0) | |
222 | goto out; | 223 | goto out; | |
223 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) { | 224 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) { | |
224 | kobj_error("not an ELF object"); | 225 | kobj_error("not an ELF object"); | |
225 | error = ENOEXEC; | 226 | error = ENOEXEC; | |
226 | goto out; | 227 | goto out; | |
227 | } | 228 | } | |
228 | 229 | |||
229 | if (hdr->e_ident[EI_VERSION] != EV_CURRENT || | 230 | if (hdr->e_ident[EI_VERSION] != EV_CURRENT || | |
230 | hdr->e_version != EV_CURRENT) { | 231 | hdr->e_version != EV_CURRENT) { | |
231 | kobj_error("unsupported file version"); | 232 | kobj_error("unsupported file version"); | |
232 | error = ENOEXEC; | 233 | error = ENOEXEC; | |
233 | goto out; | 234 | goto out; | |
234 | } | 235 | } | |
235 | if (hdr->e_type != ET_REL) { | 236 | if (hdr->e_type != ET_REL) { | |
236 | kobj_error("unsupported file type"); | 237 | kobj_error("unsupported file type"); | |
237 | error = ENOEXEC; | 238 | error = ENOEXEC; | |
238 | goto out; | 239 | goto out; | |
239 | } | 240 | } | |
240 | switch (hdr->e_machine) { | 241 | switch (hdr->e_machine) { | |
241 | #if ELFSIZE == 32 | 242 | #if ELFSIZE == 32 | |
242 | ELF32_MACHDEP_ID_CASES | 243 | ELF32_MACHDEP_ID_CASES | |
243 | #else | 244 | #else | |
244 | ELF64_MACHDEP_ID_CASES | 245 | ELF64_MACHDEP_ID_CASES | |
245 | #endif | 246 | #endif | |
246 | default: | 247 | default: | |
247 | kobj_error("unsupported machine"); | 248 | kobj_error("unsupported machine"); | |
248 | error = ENOEXEC; | 249 | error = ENOEXEC; | |
249 | goto out; | 250 | goto out; | |
250 | } | 251 | } | |
251 | 252 | |||
252 | ko->ko_nprogtab = 0; | 253 | ko->ko_nprogtab = 0; | |
253 | ko->ko_shdr = 0; | 254 | ko->ko_shdr = 0; | |
254 | ko->ko_nrel = 0; | 255 | ko->ko_nrel = 0; | |
255 | ko->ko_nrela = 0; | 256 | ko->ko_nrela = 0; | |
256 | 257 | |||
257 | /* | 258 | /* | |
258 | * Allocate and read in the section header. | 259 | * Allocate and read in the section header. | |
259 | */ | 260 | */ | |
260 | ko->ko_shdrsz = hdr->e_shnum * hdr->e_shentsize; | 261 | ko->ko_shdrsz = hdr->e_shnum * hdr->e_shentsize; | |
261 | if (ko->ko_shdrsz == 0 || hdr->e_shoff == 0 || | 262 | if (ko->ko_shdrsz == 0 || hdr->e_shoff == 0 || | |
262 | hdr->e_shentsize != sizeof(Elf_Shdr)) { | 263 | hdr->e_shentsize != sizeof(Elf_Shdr)) { | |
263 | error = ENOEXEC; | 264 | error = ENOEXEC; | |
264 | goto out; | 265 | goto out; | |
265 | } | 266 | } | |
266 | error = kobj_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff); | 267 | error = kobj_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff); | |
267 | if (error != 0) { | 268 | if (error != 0) { | |
268 | goto out; | 269 | goto out; | |
269 | } | 270 | } | |
270 | ko->ko_shdr = shdr; | 271 | ko->ko_shdr = shdr; | |
271 | 272 | |||
272 | /* | 273 | /* | |
273 | * Scan the section header for information and table sizing. | 274 | * Scan the section header for information and table sizing. | |
274 | */ | 275 | */ | |
275 | nsym = 0; | 276 | nsym = 0; | |
276 | symtabindex = -1; | 277 | symtabindex = -1; | |
277 | symstrindex = -1; | 278 | symstrindex = -1; | |
278 | for (i = 0; i < hdr->e_shnum; i++) { | 279 | for (i = 0; i < hdr->e_shnum; i++) { | |
279 | switch (shdr[i].sh_type) { | 280 | switch (shdr[i].sh_type) { | |
280 | case SHT_PROGBITS: | 281 | case SHT_PROGBITS: | |
281 | case SHT_NOBITS: | 282 | case SHT_NOBITS: | |
282 | ko->ko_nprogtab++; | 283 | ko->ko_nprogtab++; | |
283 | break; | 284 | break; | |
284 | case SHT_SYMTAB: | 285 | case SHT_SYMTAB: | |
285 | nsym++; | 286 | nsym++; | |
286 | symtabindex = i; | 287 | symtabindex = i; | |
287 | symstrindex = shdr[i].sh_link; | 288 | symstrindex = shdr[i].sh_link; | |
288 | break; | 289 | break; | |
289 | case SHT_REL: | 290 | case SHT_REL: | |
290 | ko->ko_nrel++; | 291 | ko->ko_nrel++; | |
291 | break; | 292 | break; | |
292 | case SHT_RELA: | 293 | case SHT_RELA: | |
293 | ko->ko_nrela++; | 294 | ko->ko_nrela++; | |
294 | break; | 295 | break; | |
295 | case SHT_STRTAB: | 296 | case SHT_STRTAB: | |
296 | break; | 297 | break; | |
297 | } | 298 | } | |
298 | } | 299 | } | |
299 | if (ko->ko_nprogtab == 0) { | 300 | if (ko->ko_nprogtab == 0) { | |
300 | kobj_error("file has no contents"); | 301 | kobj_error("file has no contents"); | |
301 | error = ENOEXEC; | 302 | error = ENOEXEC; | |
302 | goto out; | 303 | goto out; | |
303 | } | 304 | } | |
304 | if (nsym != 1) { | 305 | if (nsym != 1) { | |
305 | /* Only allow one symbol table for now */ | 306 | /* Only allow one symbol table for now */ | |
306 | kobj_error("file has no valid symbol table"); | 307 | kobj_error("file has no valid symbol table"); | |
307 | error = ENOEXEC; | 308 | error = ENOEXEC; | |
308 | goto out; | 309 | goto out; | |
309 | } | 310 | } | |
310 | if (symstrindex < 0 || symstrindex > hdr->e_shnum || | 311 | if (symstrindex < 0 || symstrindex > hdr->e_shnum || | |
311 | shdr[symstrindex].sh_type != SHT_STRTAB) { | 312 | shdr[symstrindex].sh_type != SHT_STRTAB) { | |
312 | kobj_error("file has invalid symbol strings"); | 313 | kobj_error("file has invalid symbol strings"); | |
313 | error = ENOEXEC; | 314 | error = ENOEXEC; | |
314 | goto out; | 315 | goto out; | |
315 | } | 316 | } | |
316 | 317 | |||
317 | /* | 318 | /* | |
318 | * Allocate space for tracking the load chunks. | 319 | * Allocate space for tracking the load chunks. | |
319 | */ | 320 | */ | |
320 | if (ko->ko_nprogtab != 0) { | 321 | if (ko->ko_nprogtab != 0) { | |
321 | ko->ko_progtab = kmem_zalloc(ko->ko_nprogtab * | 322 | ko->ko_progtab = kmem_zalloc(ko->ko_nprogtab * | |
322 | sizeof(*ko->ko_progtab), KM_SLEEP); | 323 | sizeof(*ko->ko_progtab), KM_SLEEP); | |
323 | if (ko->ko_progtab == NULL) { | 324 | if (ko->ko_progtab == NULL) { | |
324 | error = ENOMEM; | 325 | error = ENOMEM; | |
325 | goto out; | 326 | goto out; | |
326 | } | 327 | } | |
327 | } | 328 | } | |
328 | if (ko->ko_nrel != 0) { | 329 | if (ko->ko_nrel != 0) { | |
329 | ko->ko_reltab = kmem_zalloc(ko->ko_nrel * | 330 | ko->ko_reltab = kmem_zalloc(ko->ko_nrel * | |
330 | sizeof(*ko->ko_reltab), KM_SLEEP); | 331 | sizeof(*ko->ko_reltab), KM_SLEEP); | |
331 | if (ko->ko_reltab == NULL) { | 332 | if (ko->ko_reltab == NULL) { | |
332 | error = ENOMEM; | 333 | error = ENOMEM; | |
333 | goto out; | 334 | goto out; | |
334 | } | 335 | } | |
335 | } | 336 | } | |
336 | if (ko->ko_nrela != 0) { | 337 | if (ko->ko_nrela != 0) { | |
337 | ko->ko_relatab = kmem_zalloc(ko->ko_nrela * | 338 | ko->ko_relatab = kmem_zalloc(ko->ko_nrela * | |
338 | sizeof(*ko->ko_relatab), KM_SLEEP); | 339 | sizeof(*ko->ko_relatab), KM_SLEEP); | |
339 | if (ko->ko_relatab == NULL) { | 340 | if (ko->ko_relatab == NULL) { | |
340 | error = ENOMEM; | 341 | error = ENOMEM; | |
341 | goto out; | 342 | goto out; | |
342 | } | 343 | } | |
343 | } | 344 | } | |
344 | if (symtabindex == -1) { | 345 | if (symtabindex == -1) { | |
345 | kobj_error("lost symbol table index"); | 346 | kobj_error("lost symbol table index"); | |
346 | goto out; | 347 | goto out; | |
347 | } | 348 | } | |
348 | 349 | |||
349 | /* | 350 | /* | |
350 | * Allocate space for and load the symbol table. | 351 | * Allocate space for and load the symbol table. | |
351 | */ | 352 | */ | |
352 | ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); | 353 | ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); | |
353 | if (ko->ko_symcnt == 0) { | 354 | if (ko->ko_symcnt == 0) { | |
354 | kobj_error("no symbol table"); | 355 | kobj_error("no symbol table"); | |
355 | goto out; | 356 | goto out; | |
356 | } | 357 | } | |
357 | error = kobj_read(ko, (void **)&ko->ko_symtab, | 358 | error = kobj_read(ko, (void **)&ko->ko_symtab, | |
358 | ko->ko_symcnt * sizeof(Elf_Sym), | 359 | ko->ko_symcnt * sizeof(Elf_Sym), | |
359 | shdr[symtabindex].sh_offset); | 360 | shdr[symtabindex].sh_offset); | |
360 | if (error != 0) { | 361 | if (error != 0) { | |
361 | goto out; | 362 | goto out; | |
362 | } | 363 | } | |
363 | 364 | |||
364 | /* | 365 | /* | |
365 | * Allocate space for and load the symbol strings. | 366 | * Allocate space for and load the symbol strings. | |
366 | */ | 367 | */ | |
367 | ko->ko_strtabsz = shdr[symstrindex].sh_size; | 368 | ko->ko_strtabsz = shdr[symstrindex].sh_size; | |
368 | if (ko->ko_strtabsz == 0) { | 369 | if (ko->ko_strtabsz == 0) { | |
369 | kobj_error("no symbol strings"); | 370 | kobj_error("no symbol strings"); | |
370 | goto out; | 371 | goto out; | |
371 | } | 372 | } | |
372 | error = kobj_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz, | 373 | error = kobj_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz, | |
373 | shdr[symstrindex].sh_offset); | 374 | shdr[symstrindex].sh_offset); | |
374 | if (error != 0) { | 375 | if (error != 0) { | |
375 | goto out; | 376 | goto out; | |
376 | } | 377 | } | |
377 | 378 | |||
378 | /* | 379 | /* | |
379 | * Do we have a string table for the section names? | 380 | * Do we have a string table for the section names? | |
380 | */ | 381 | */ | |
381 | if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_size != 0 && | 382 | if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_size != 0 && | |
382 | shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { | 383 | shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { | |
383 | ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size; | 384 | ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size; | |
384 | error = kobj_read(ko, (void **)&ko->ko_shstrtab, | 385 | error = kobj_read(ko, (void **)&ko->ko_shstrtab, | |
385 | shdr[hdr->e_shstrndx].sh_size, | 386 | shdr[hdr->e_shstrndx].sh_size, | |
386 | shdr[hdr->e_shstrndx].sh_offset); | 387 | shdr[hdr->e_shstrndx].sh_offset); | |
387 | if (error != 0) { | 388 | if (error != 0) { | |
388 | goto out; | 389 | goto out; | |
389 | } | 390 | } | |
390 | } | 391 | } | |
391 | 392 | |||
392 | /* | 393 | /* | |
393 | * Size up code/data(progbits) and bss(nobits). | 394 | * Size up code/data(progbits) and bss(nobits). | |
394 | */ | 395 | */ | |
395 | alignmask = 0; | 396 | alignmask = 0; | |
396 | mapbase = 0; | 397 | mapbase = 0; | |
397 | for (i = 0; i < hdr->e_shnum; i++) { | 398 | for (i = 0; i < hdr->e_shnum; i++) { | |
398 | switch (shdr[i].sh_type) { | 399 | switch (shdr[i].sh_type) { | |
399 | case SHT_PROGBITS: | 400 | case SHT_PROGBITS: | |
400 | case SHT_NOBITS: | 401 | case SHT_NOBITS: | |
401 | if (mapbase == 0) | 402 | if (mapbase == 0) | |
402 | mapbase = shdr[i].sh_offset; | 403 | mapbase = shdr[i].sh_offset; | |
403 | alignmask = shdr[i].sh_addralign - 1; | 404 | alignmask = shdr[i].sh_addralign - 1; | |
404 | mapsize += alignmask; | 405 | mapsize += alignmask; | |
405 | mapsize &= ~alignmask; | 406 | mapsize &= ~alignmask; | |
406 | mapsize += shdr[i].sh_size; | 407 | mapsize += shdr[i].sh_size; | |
407 | break; | 408 | break; | |
408 | } | 409 | } | |
409 | } | 410 | } | |
410 | 411 | |||
411 | /* | 412 | /* | |
412 | * We know how much space we need for the text/data/bss/etc. | 413 | * We know how much space we need for the text/data/bss/etc. | |
413 | * This stuff needs to be in a single chunk so that profiling etc | 414 | * This stuff needs to be in a single chunk so that profiling etc | |
414 | * can get the bounds and gdb can associate offsets with modules. | 415 | * can get the bounds and gdb can associate offsets with modules. | |
415 | */ | 416 | */ | |
416 | if (mapsize == 0) { | 417 | if (mapsize == 0) { | |
417 | kobj_error("no text/data/bss"); | 418 | kobj_error("no text/data/bss"); | |
418 | goto out; | 419 | goto out; | |
419 | } | 420 | } | |
420 | if (ko->ko_type == KT_MEMORY) { | 421 | if (ko->ko_type == KT_MEMORY) { | |
421 | mapbase += (vaddr_t)ko->ko_source; | 422 | mapbase += (vaddr_t)ko->ko_source; | |
422 | } else { | 423 | } else { | |
423 | mapbase = uvm_km_alloc(module_map, round_page(mapsize), | 424 | mapbase = uvm_km_alloc(module_map, round_page(mapsize), | |
424 | 0, UVM_KMF_WIRED | UVM_KMF_EXEC); | 425 | 0, UVM_KMF_WIRED | UVM_KMF_EXEC); | |
425 | if (mapbase == 0) { | 426 | if (mapbase == 0) { | |
426 | error = ENOMEM; | 427 | error = ENOMEM; | |
427 | goto out; | 428 | goto out; | |
428 | } | 429 | } | |
429 | } | 430 | } | |
430 | ko->ko_address = mapbase; | 431 | ko->ko_address = mapbase; | |
431 | ko->ko_size = mapsize; | 432 | ko->ko_size = mapsize; | |
432 | 433 | |||
433 | /* | 434 | /* | |
434 | * Now load code/data(progbits), zero bss(nobits), allocate space | 435 | * Now load code/data(progbits), zero bss(nobits), allocate space | |
435 | * for and load relocs | 436 | * for and load relocs | |
436 | */ | 437 | */ | |
437 | pb = 0; | 438 | pb = 0; | |
438 | rl = 0; | 439 | rl = 0; | |
439 | ra = 0; | 440 | ra = 0; | |
440 | alignmask = 0; | 441 | alignmask = 0; | |
441 | for (i = 0; i < hdr->e_shnum; i++) { | 442 | for (i = 0; i < hdr->e_shnum; i++) { | |
442 | switch (shdr[i].sh_type) { | 443 | switch (shdr[i].sh_type) { | |
443 | case SHT_PROGBITS: | 444 | case SHT_PROGBITS: | |
444 | case SHT_NOBITS: | 445 | case SHT_NOBITS: | |
445 | alignmask = shdr[i].sh_addralign - 1; | 446 | alignmask = shdr[i].sh_addralign - 1; | |
446 | if (ko->ko_type == KT_MEMORY) { | 447 | if (ko->ko_type == KT_MEMORY) { | |
447 | addr = (void *)(shdr[i].sh_offset + | 448 | addr = (void *)(shdr[i].sh_offset + | |
448 | (vaddr_t)ko->ko_source); | 449 | (vaddr_t)ko->ko_source); | |
449 | if (((vaddr_t)addr & alignmask) != 0) { | 450 | if (((vaddr_t)addr & alignmask) != 0) { | |
450 | kobj_error("section %d not aligned\n", | 451 | kobj_error("section %d not aligned\n", | |
451 | i); | 452 | i); | |
452 | goto out; | 453 | goto out; | |
453 | } | 454 | } | |
454 | } else { | 455 | } else { | |
455 | mapbase += alignmask; | 456 | mapbase += alignmask; | |
456 | mapbase &= ~alignmask; | 457 | mapbase &= ~alignmask; | |
457 | addr = (void *)mapbase; | 458 | addr = (void *)mapbase; | |
458 | mapbase += shdr[i].sh_size; | 459 | mapbase += shdr[i].sh_size; | |
459 | } | 460 | } | |
460 | ko->ko_progtab[pb].addr = addr; | 461 | ko->ko_progtab[pb].addr = addr; | |
461 | if (shdr[i].sh_type == SHT_PROGBITS) { | 462 | if (shdr[i].sh_type == SHT_PROGBITS) { | |
462 | ko->ko_progtab[pb].name = "<<PROGBITS>>"; | 463 | ko->ko_progtab[pb].name = "<<PROGBITS>>"; | |
463 | error = kobj_read_bits(ko, addr, | 464 | error = kobj_read_bits(ko, addr, | |
464 | shdr[i].sh_size, shdr[i].sh_offset); | 465 | shdr[i].sh_size, shdr[i].sh_offset); | |
465 | if (error != 0) { | 466 | if (error != 0) { | |
466 | goto out; | 467 | goto out; | |
467 | } | 468 | } | |
468 | } else if (ko->ko_type == KT_MEMORY && | 469 | } else if (ko->ko_type == KT_MEMORY && | |
469 | shdr[i].sh_size != 0) { | 470 | shdr[i].sh_size != 0) { | |
470 | kobj_error("non-loadable BSS section in " | 471 | kobj_error("non-loadable BSS section in " | |
471 | "pre-loaded module"); | 472 | "pre-loaded module"); | |
472 | error = EINVAL; | 473 | error = EINVAL; | |
473 | goto out; | 474 | goto out; | |
474 | } else { | 475 | } else { | |
475 | ko->ko_progtab[pb].name = "<<NOBITS>>"; | 476 | ko->ko_progtab[pb].name = "<<NOBITS>>"; | |
476 | memset(addr, 0, shdr[i].sh_size); | 477 | memset(addr, 0, shdr[i].sh_size); | |
477 | } | 478 | } | |
478 | ko->ko_progtab[pb].size = shdr[i].sh_size; | 479 | ko->ko_progtab[pb].size = shdr[i].sh_size; | |
479 | ko->ko_progtab[pb].sec = i; | 480 | ko->ko_progtab[pb].sec = i; | |
480 | if (ko->ko_shstrtab != NULL && shdr[i].sh_name != 0) { | 481 | if (ko->ko_shstrtab != NULL && shdr[i].sh_name != 0) { | |
481 | ko->ko_progtab[pb].name = | 482 | ko->ko_progtab[pb].name = | |
482 | ko->ko_shstrtab + shdr[i].sh_name; | 483 | ko->ko_shstrtab + shdr[i].sh_name; | |
483 | } | 484 | } | |
484 | 485 | |||
485 | /* Update all symbol values with the offset. */ | 486 | /* Update all symbol values with the offset. */ | |
486 | for (j = 0; j < ko->ko_symcnt; j++) { | 487 | for (j = 0; j < ko->ko_symcnt; j++) { | |
487 | es = &ko->ko_symtab[j]; | 488 | es = &ko->ko_symtab[j]; | |
488 | if (es->st_shndx != i) { | 489 | if (es->st_shndx != i) { | |
489 | continue; | 490 | continue; | |
490 | } | 491 | } | |
491 | es->st_value += (Elf_Addr)addr; | 492 | es->st_value += (Elf_Addr)addr; | |
492 | } | 493 | } | |
493 | pb++; | 494 | pb++; | |
494 | break; | 495 | break; | |
495 | case SHT_REL: | 496 | case SHT_REL: | |
496 | ko->ko_reltab[rl].size = shdr[i].sh_size; | 497 | ko->ko_reltab[rl].size = shdr[i].sh_size; | |
497 | ko->ko_reltab[rl].size -= | 498 | ko->ko_reltab[rl].size -= | |
498 | shdr[i].sh_size % sizeof(Elf_Rel); | 499 | shdr[i].sh_size % sizeof(Elf_Rel); | |
499 | if (ko->ko_reltab[rl].size != 0) { | 500 | if (ko->ko_reltab[rl].size != 0) { | |
500 | ko->ko_reltab[rl].nrel = | 501 | ko->ko_reltab[rl].nrel = | |
501 | shdr[i].sh_size / sizeof(Elf_Rel); | 502 | shdr[i].sh_size / sizeof(Elf_Rel); | |
502 | ko->ko_reltab[rl].sec = shdr[i].sh_info; | 503 | ko->ko_reltab[rl].sec = shdr[i].sh_info; | |
503 | error = kobj_read(ko, | 504 | error = kobj_read(ko, | |
504 | (void **)&ko->ko_reltab[rl].rel, | 505 | (void **)&ko->ko_reltab[rl].rel, | |
505 | ko->ko_reltab[rl].size, | 506 | ko->ko_reltab[rl].size, | |
506 | shdr[i].sh_offset); | 507 | shdr[i].sh_offset); | |
507 | if (error != 0) { | 508 | if (error != 0) { | |
508 | goto out; | 509 | goto out; | |
509 | } | 510 | } | |
510 | } | 511 | } | |
511 | rl++; | 512 | rl++; | |
512 | break; | 513 | break; | |
513 | case SHT_RELA: | 514 | case SHT_RELA: | |
514 | ko->ko_relatab[ra].size = shdr[i].sh_size; | 515 | ko->ko_relatab[ra].size = shdr[i].sh_size; | |
515 | ko->ko_relatab[ra].size -= | 516 | ko->ko_relatab[ra].size -= | |
516 | shdr[i].sh_size % sizeof(Elf_Rela); | 517 | shdr[i].sh_size % sizeof(Elf_Rela); | |
517 | if (ko->ko_relatab[ra].size != 0) { | 518 | if (ko->ko_relatab[ra].size != 0) { | |
518 | ko->ko_relatab[ra].nrela = | 519 | ko->ko_relatab[ra].nrela = | |
519 | shdr[i].sh_size / sizeof(Elf_Rela); | 520 | shdr[i].sh_size / sizeof(Elf_Rela); | |
520 | ko->ko_relatab[ra].sec = shdr[i].sh_info; | 521 | ko->ko_relatab[ra].sec = shdr[i].sh_info; | |
521 | error = kobj_read(ko, | 522 | error = kobj_read(ko, | |
522 | (void **)&ko->ko_relatab[ra].rela, | 523 | (void **)&ko->ko_relatab[ra].rela, | |
523 | shdr[i].sh_size, | 524 | shdr[i].sh_size, | |
524 | shdr[i].sh_offset); | 525 | shdr[i].sh_offset); | |
525 | if (error != 0) { | 526 | if (error != 0) { | |
526 | goto out; | 527 | goto out; | |
527 | } | 528 | } | |
528 | } | 529 | } | |
529 | ra++; | 530 | ra++; | |
530 | break; | 531 | break; | |
531 | default: | 532 | default: | |
532 | break; | 533 | break; | |
533 | } | 534 | } | |
534 | } | 535 | } | |
535 | if (pb != ko->ko_nprogtab) { | 536 | if (pb != ko->ko_nprogtab) { | |
536 | panic("lost progbits"); | 537 | panic("lost progbits"); | |
537 | } | 538 | } | |
538 | if (rl != ko->ko_nrel) { | 539 | if (rl != ko->ko_nrel) { | |
539 | panic("lost rel"); | 540 | panic("lost rel"); | |
540 | } | 541 | } | |
541 | if (ra != ko->ko_nrela) { | 542 | if (ra != ko->ko_nrela) { | |
542 | panic("lost rela"); | 543 | panic("lost rela"); | |
543 | } | 544 | } | |
544 | if (ko->ko_type != KT_MEMORY && mapbase != ko->ko_address + mapsize) { | 545 | if (ko->ko_type != KT_MEMORY && mapbase != ko->ko_address + mapsize) { | |
545 | panic("mapbase 0x%lx != address %lx + mapsize %ld (0x%lx)\n", | 546 | panic("mapbase 0x%lx != address %lx + mapsize %ld (0x%lx)\n", | |
546 | (long)mapbase, (long)ko->ko_address, (long)mapsize, | 547 | (long)mapbase, (long)ko->ko_address, (long)mapsize, | |
547 | (long)ko->ko_address + mapsize); | 548 | (long)ko->ko_address + mapsize); | |
548 | } | 549 | } | |
549 | 550 | |||
550 | /* | 551 | /* | |
551 | * Perform local relocations only. Relocations relating to global | 552 | * Perform local relocations only. Relocations relating to global | |
552 | * symbols will be done by kobj_affix(). | 553 | * symbols will be done by kobj_affix(). | |
553 | */ | 554 | */ | |
554 | error = kobj_checksyms(ko, false); | 555 | error = kobj_checksyms(ko, false); | |
555 | if (error == 0) { | 556 | if (error == 0) { | |
556 | error = kobj_relocate(ko, true); | 557 | error = kobj_relocate(ko, true); | |
557 | } | 558 | } | |
558 | out: | 559 | out: | |
559 | if (hdr != NULL) { | 560 | if (hdr != NULL) { | |
560 | kobj_free(ko, hdr, sizeof(*hdr)); | 561 | kobj_free(ko, hdr, sizeof(*hdr)); | |
561 | } | 562 | } | |
562 | kobj_close(ko); | 563 | kobj_close(ko); | |
563 | if (error != 0) { | 564 | if (error != 0) { | |
564 | kobj_unload(ko); | 565 | kobj_unload(ko); | |
565 | } | 566 | } | |
566 | 567 | |||
567 | return error; | 568 | return error; | |
568 | } | 569 | } | |
569 | 570 | |||
570 | /* | 571 | /* | |
571 | * kobj_unload: | 572 | * kobj_unload: | |
572 | * | 573 | * | |
573 | * Unload an object previously loaded by kobj_load(). | 574 | * Unload an object previously loaded by kobj_load(). | |
574 | */ | 575 | */ | |
575 | void | 576 | void | |
576 | kobj_unload(kobj_t ko) | 577 | kobj_unload(kobj_t ko) | |
577 | { | 578 | { | |
578 | int error; | 579 | int error; | |
579 | 580 | |||
580 | kobj_close(ko); | 581 | kobj_close(ko); | |
581 | kobj_jettison(ko); | 582 | kobj_jettison(ko); | |
582 | 583 | |||
583 | /* | 584 | /* | |
584 | * Notify MD code that a module has been unloaded. | 585 | * Notify MD code that a module has been unloaded. | |
585 | */ | 586 | */ | |
586 | if (ko->ko_loaded) { | 587 | if (ko->ko_loaded) { | |
587 | error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size, | 588 | error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size, | |
588 | false); | 589 | false); | |
589 | if (error != 0) { | 590 | if (error != 0) { | |
590 | kobj_error("machine dependent deinit failed"); | 591 | kobj_error("machine dependent deinit failed"); | |
591 | } | 592 | } | |
592 | } | 593 | } | |
593 | if (ko->ko_address != 0 && ko->ko_type != KT_MEMORY) { | 594 | if (ko->ko_address != 0 && ko->ko_type != KT_MEMORY) { | |
594 | uvm_km_free(module_map, ko->ko_address, round_page(ko->ko_size), | 595 | uvm_km_free(module_map, ko->ko_address, round_page(ko->ko_size), | |
595 | UVM_KMF_WIRED); | 596 | UVM_KMF_WIRED); | |
596 | } | 597 | } | |
597 | if (ko->ko_ksyms == true) { | 598 | if (ko->ko_ksyms == true) { | |
598 | ksyms_modunload(ko->ko_name); | 599 | ksyms_modunload(ko->ko_name); | |
599 | } | 600 | } | |
600 | if (ko->ko_symtab != NULL) { | 601 | if (ko->ko_symtab != NULL) { | |
601 | kobj_free(ko, ko->ko_symtab, ko->ko_symcnt * sizeof(Elf_Sym)); | 602 | kobj_free(ko, ko->ko_symtab, ko->ko_symcnt * sizeof(Elf_Sym)); | |
602 | } | 603 | } | |
603 | if (ko->ko_strtab != NULL) { | 604 | if (ko->ko_strtab != NULL) { | |
604 | kobj_free(ko, ko->ko_strtab, ko->ko_strtabsz); | 605 | kobj_free(ko, ko->ko_strtab, ko->ko_strtabsz); | |
605 | } | 606 | } | |
606 | if (ko->ko_progtab != NULL) { | 607 | if (ko->ko_progtab != NULL) { | |
607 | kobj_free(ko, ko->ko_progtab, ko->ko_nprogtab * | 608 | kobj_free(ko, ko->ko_progtab, ko->ko_nprogtab * | |
608 | sizeof(*ko->ko_progtab)); | 609 | sizeof(*ko->ko_progtab)); | |
609 | ko->ko_progtab = NULL; | 610 | ko->ko_progtab = NULL; | |
610 | } | 611 | } | |
611 | if (ko->ko_shstrtab) { | 612 | if (ko->ko_shstrtab) { | |
612 | kobj_free(ko, ko->ko_shstrtab, ko->ko_shstrtabsz); | 613 | kobj_free(ko, ko->ko_shstrtab, ko->ko_shstrtabsz); | |
613 | ko->ko_shstrtab = NULL; | 614 | ko->ko_shstrtab = NULL; | |
614 | } | 615 | } | |
615 | 616 | |||
616 | kmem_free(ko, sizeof(*ko)); | 617 | kmem_free(ko, sizeof(*ko)); | |
617 | } | 618 | } | |
618 | 619 | |||
619 | /* | 620 | /* | |
620 | * kobj_stat: | 621 | * kobj_stat: | |
621 | * | 622 | * | |
622 | * Return size and load address of an object. | 623 | * Return size and load address of an object. | |
623 | */ | 624 | */ | |
624 | void | 625 | void | |
625 | kobj_stat(kobj_t ko, vaddr_t *address, size_t *size) | 626 | kobj_stat(kobj_t ko, vaddr_t *address, size_t *size) | |
626 | { | 627 | { | |
627 | 628 | |||
628 | if (address != NULL) { | 629 | if (address != NULL) { | |
629 | *address = ko->ko_address; | 630 | *address = ko->ko_address; | |
630 | } | 631 | } | |
631 | if (size != NULL) { | 632 | if (size != NULL) { | |
632 | *size = ko->ko_size; | 633 | *size = ko->ko_size; | |
633 | } | 634 | } | |
634 | } | 635 | } | |
635 | 636 | |||
636 | /* | 637 | /* | |
637 | * kobj_affix: | 638 | * kobj_affix: | |
638 | * | 639 | * | |
639 | * Set an object's name and perform global relocs. May only be | 640 | * Set an object's name and perform global relocs. May only be | |
640 | * called after the module and any requisite modules are loaded. | 641 | * called after the module and any requisite modules are loaded. | |
641 | */ | 642 | */ | |
642 | int | 643 | int | |
643 | kobj_affix(kobj_t ko, const char *name) | 644 | kobj_affix(kobj_t ko, const char *name) | |
644 | { | 645 | { | |
645 | int error; | 646 | int error; | |
646 | 647 | |||
647 | KASSERT(ko->ko_ksyms == false); | 648 | KASSERT(ko->ko_ksyms == false); | |
648 | KASSERT(ko->ko_loaded == false); | 649 | KASSERT(ko->ko_loaded == false); | |
649 | 650 | |||
650 | strlcpy(ko->ko_name, name, sizeof(ko->ko_name)); | 651 | strlcpy(ko->ko_name, name, sizeof(ko->ko_name)); | |
651 | 652 | |||
652 | /* Cache addresses of undefined symbols. */ | 653 | /* Cache addresses of undefined symbols. */ | |
653 | error = kobj_checksyms(ko, true); | 654 | error = kobj_checksyms(ko, true); | |
654 | 655 | |||
655 | /* Now do global relocations. */ | 656 | /* Now do global relocations. */ | |
656 | if (error == 0) | 657 | if (error == 0) | |
657 | error = kobj_relocate(ko, false); | 658 | error = kobj_relocate(ko, false); | |
658 | 659 | |||
659 | /* | 660 | /* | |
660 | * Now that we know the name, register the symbol table. | 661 | * Now that we know the name, register the symbol table. | |
661 | * Do after global relocations because ksyms will pack | 662 | * Do after global relocations because ksyms will pack | |
662 | * the table. | 663 | * the table. | |
663 | */ | 664 | */ | |
664 | if (error == 0) { | 665 | if (error == 0) { | |
665 | ksyms_modload(ko->ko_name, ko->ko_symtab, ko->ko_symcnt * | 666 | ksyms_modload(ko->ko_name, ko->ko_symtab, ko->ko_symcnt * | |
666 | sizeof(Elf_Sym), ko->ko_strtab, ko->ko_strtabsz); | 667 | sizeof(Elf_Sym), ko->ko_strtab, ko->ko_strtabsz); | |
667 | ko->ko_ksyms = true; | 668 | ko->ko_ksyms = true; | |
668 | } | 669 | } | |
669 | 670 | |||
670 | /* Jettison unneeded memory post-link. */ | 671 | /* Jettison unneeded memory post-link. */ | |
671 | kobj_jettison(ko); | 672 | kobj_jettison(ko); | |
672 | 673 | |||
673 | /* | 674 | /* | |
674 | * Notify MD code that a module has been loaded. | 675 | * Notify MD code that a module has been loaded. | |
675 | * | 676 | * | |
676 | * Most architectures use this opportunity to flush their caches. | 677 | * Most architectures use this opportunity to flush their caches. | |
677 | */ | 678 | */ | |
678 | if (error == 0) { | 679 | if (error == 0) { | |
679 | error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size, | 680 | error = kobj_machdep(ko, (void *)ko->ko_address, ko->ko_size, | |
680 | true); | 681 | true); | |
681 | if (error != 0) { | 682 | if (error != 0) { | |
682 | kobj_error("machine dependent init failed"); | 683 | kobj_error("machine dependent init failed"); | |
683 | } | 684 | } | |
684 | ko->ko_loaded = true; | 685 | ko->ko_loaded = true; | |
685 | } | 686 | } | |
686 | 687 | |||
687 | /* If there was an error, destroy the whole object. */ | 688 | /* If there was an error, destroy the whole object. */ | |
688 | if (error != 0) { | 689 | if (error != 0) { | |
689 | kobj_unload(ko); | 690 | kobj_unload(ko); | |
690 | } | 691 | } | |
691 | 692 | |||
692 | return error; | 693 | return error; | |
693 | } | 694 | } | |
694 | 695 | |||
695 | /* | 696 | /* | |
696 | * kobj_find_section: | 697 | * kobj_find_section: | |
697 | * | 698 | * | |
698 | * Given a section name, search the loaded object and return | 699 | * Given a section name, search the loaded object and return | |
699 | * virtual address if present and loaded. | 700 | * virtual address if present and loaded. | |
700 | */ | 701 | */ | |
701 | int | 702 | int | |
702 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) | 703 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) | |
703 | { | 704 | { | |
704 | int i; | 705 | int i; | |
705 | 706 | |||
706 | KASSERT(ko->ko_progtab != NULL); | 707 | KASSERT(ko->ko_progtab != NULL); | |
707 | 708 | |||
708 | for (i = 0; i < ko->ko_nprogtab; i++) { | 709 | for (i = 0; i < ko->ko_nprogtab; i++) { | |
709 | if (strcmp(ko->ko_progtab[i].name, name) == 0) { | 710 | if (strcmp(ko->ko_progtab[i].name, name) == 0) { | |
710 | if (addr != NULL) { | 711 | if (addr != NULL) { | |
711 | *addr = ko->ko_progtab[i].addr; | 712 | *addr = ko->ko_progtab[i].addr; | |
712 | } | 713 | } | |
713 | if (size != NULL) { | 714 | if (size != NULL) { | |
714 | *size = ko->ko_progtab[i].size; | 715 | *size = ko->ko_progtab[i].size; | |
715 | } | 716 | } | |
716 | return 0; | 717 | return 0; | |
717 | } | 718 | } | |
718 | } | 719 | } | |
719 | 720 | |||
720 | return ENOENT; | 721 | return ENOENT; | |
721 | } | 722 | } | |
722 | 723 | |||
723 | /* | 724 | /* | |
724 | * kobj_jettison: | 725 | * kobj_jettison: | |
725 | * | 726 | * | |
726 | * Release object data not needed after performing relocations. | 727 | * Release object data not needed after performing relocations. | |
727 | */ | 728 | */ | |
728 | static void | 729 | static void | |
729 | kobj_jettison(kobj_t ko) | 730 | kobj_jettison(kobj_t ko) | |
730 | { | 731 | { | |
731 | int i; | 732 | int i; | |
732 | 733 | |||
733 | if (ko->ko_reltab != NULL) { | 734 | if (ko->ko_reltab != NULL) { | |
734 | for (i = 0; i < ko->ko_nrel; i++) { | 735 | for (i = 0; i < ko->ko_nrel; i++) { | |
735 | if (ko->ko_reltab[i].rel) { | 736 | if (ko->ko_reltab[i].rel) { | |
736 | kobj_free(ko, ko->ko_reltab[i].rel, | 737 | kobj_free(ko, ko->ko_reltab[i].rel, | |
737 | ko->ko_reltab[i].size); | 738 | ko->ko_reltab[i].size); | |
738 | } | 739 | } | |
739 | } | 740 | } | |
740 | kobj_free(ko, ko->ko_reltab, ko->ko_nrel * | 741 | kobj_free(ko, ko->ko_reltab, ko->ko_nrel * | |
741 | sizeof(*ko->ko_reltab)); | 742 | sizeof(*ko->ko_reltab)); | |
742 | ko->ko_reltab = NULL; | 743 | ko->ko_reltab = NULL; | |
743 | ko->ko_nrel = 0; | 744 | ko->ko_nrel = 0; | |
744 | } | 745 | } | |
745 | if (ko->ko_relatab != NULL) { | 746 | if (ko->ko_relatab != NULL) { | |
746 | for (i = 0; i < ko->ko_nrela; i++) { | 747 | for (i = 0; i < ko->ko_nrela; i++) { | |
747 | if (ko->ko_relatab[i].rela) { | 748 | if (ko->ko_relatab[i].rela) { | |
748 | kobj_free(ko, ko->ko_relatab[i].rela, | 749 | kobj_free(ko, ko->ko_relatab[i].rela, | |
749 | ko->ko_relatab[i].size); | 750 | ko->ko_relatab[i].size); | |
750 | } | 751 | } | |
751 | } | 752 | } | |
752 | kobj_free(ko, ko->ko_relatab, ko->ko_nrela * | 753 | kobj_free(ko, ko->ko_relatab, ko->ko_nrela * | |
753 | sizeof(*ko->ko_relatab)); | 754 | sizeof(*ko->ko_relatab)); | |
754 | ko->ko_relatab = NULL; | 755 | ko->ko_relatab = NULL; | |
755 | ko->ko_nrela = 0; | 756 | ko->ko_nrela = 0; | |
756 | } | 757 | } | |
757 | if (ko->ko_shdr != NULL) { | 758 | if (ko->ko_shdr != NULL) { | |
758 | kobj_free(ko, ko->ko_shdr, ko->ko_shdrsz); | 759 | kobj_free(ko, ko->ko_shdr, ko->ko_shdrsz); | |
759 | ko->ko_shdr = NULL; | 760 | ko->ko_shdr = NULL; | |
760 | } | 761 | } | |
761 | } | 762 | } | |
762 | 763 | |||
763 | /* | 764 | /* | |
764 | * kobj_sym_lookup: | 765 | * kobj_sym_lookup: | |
765 | * | 766 | * | |
766 | * Symbol lookup function to be used when the symbol index | 767 | * Symbol lookup function to be used when the symbol index | |
767 | * is known (ie during relocation). | 768 | * is known (ie during relocation). | |
768 | */ | 769 | */ | |
769 | uintptr_t | 770 | uintptr_t | |
770 | kobj_sym_lookup(kobj_t ko, uintptr_t symidx) | 771 | kobj_sym_lookup(kobj_t ko, uintptr_t symidx) | |
771 | { | 772 | { | |
772 | const Elf_Sym *sym; | 773 | const Elf_Sym *sym; | |
773 | const char *symbol; | 774 | const char *symbol; | |
774 | 775 | |||
775 | /* Don't even try to lookup the symbol if the index is bogus. */ | 776 | /* Don't even try to lookup the symbol if the index is bogus. */ | |
776 | if (symidx >= ko->ko_symcnt) | 777 | if (symidx >= ko->ko_symcnt) | |
777 | return 0; | 778 | return 0; | |
778 | 779 | |||
779 | sym = ko->ko_symtab + symidx; | 780 | sym = ko->ko_symtab + symidx; | |
780 | 781 | |||
781 | /* Quick answer if there is a definition included. */ | 782 | /* Quick answer if there is a definition included. */ | |
782 | if (sym->st_shndx != SHN_UNDEF) { | 783 | if (sym->st_shndx != SHN_UNDEF) { | |
783 | return (uintptr_t)sym->st_value; | 784 | return (uintptr_t)sym->st_value; | |
784 | } | 785 | } | |
785 | 786 | |||
786 | /* If we get here, then it is undefined and needs a lookup. */ | 787 | /* If we get here, then it is undefined and needs a lookup. */ | |
787 | switch (ELF_ST_BIND(sym->st_info)) { | 788 | switch (ELF_ST_BIND(sym->st_info)) { | |
788 | case STB_LOCAL: | 789 | case STB_LOCAL: | |
789 | /* Local, but undefined? huh? */ | 790 | /* Local, but undefined? huh? */ | |
790 | kobj_error("local symbol undefined"); | 791 | kobj_error("local symbol undefined"); | |
791 | return 0; | 792 | return 0; | |
792 | 793 | |||
793 | case STB_GLOBAL: | 794 | case STB_GLOBAL: | |
794 | /* Relative to Data or Function name */ | 795 | /* Relative to Data or Function name */ | |
795 | symbol = ko->ko_strtab + sym->st_name; | 796 | symbol = ko->ko_strtab + sym->st_name; | |
796 | 797 | |||
797 | /* Force a lookup failure if the symbol name is bogus. */ | 798 | /* Force a lookup failure if the symbol name is bogus. */ | |
798 | if (*symbol == 0) { | 799 | if (*symbol == 0) { | |
799 | kobj_error("bad symbol name"); | 800 | kobj_error("bad symbol name"); | |
800 | return 0; | 801 | return 0; | |
801 | } | 802 | } | |
802 | 803 | |||
803 | return (uintptr_t)sym->st_value; | 804 | return (uintptr_t)sym->st_value; | |
804 | 805 | |||
805 | case STB_WEAK: | 806 | case STB_WEAK: | |
806 | kobj_error("weak symbols not supported\n"); | 807 | kobj_error("weak symbols not supported\n"); | |
807 | return 0; | 808 | return 0; | |
808 | 809 | |||
809 | default: | 810 | default: | |
810 | return 0; | 811 | return 0; | |
811 | } | 812 | } | |
812 | } | 813 | } | |
813 | 814 | |||
814 | /* | 815 | /* | |
815 | * kobj_findbase: | 816 | * kobj_findbase: | |
816 | * | 817 | * | |
817 | * Return base address of the given section. | 818 | * Return base address of the given section. | |
818 | */ | 819 | */ | |
819 | static uintptr_t | 820 | static uintptr_t | |
820 | kobj_findbase(kobj_t ko, int sec) | 821 | kobj_findbase(kobj_t ko, int sec) | |
821 | { | 822 | { | |
822 | int i; | 823 | int i; | |
823 | 824 | |||
824 | for (i = 0; i < ko->ko_nprogtab; i++) { | 825 | for (i = 0; i < ko->ko_nprogtab; i++) { | |
825 | if (sec == ko->ko_progtab[i].sec) { | 826 | if (sec == ko->ko_progtab[i].sec) { | |
826 | return (uintptr_t)ko->ko_progtab[i].addr; | 827 | return (uintptr_t)ko->ko_progtab[i].addr; | |
827 | } | 828 | } | |
828 | } | 829 | } | |
829 | return 0; | 830 | return 0; | |
830 | } | 831 | } | |
831 | 832 | |||
832 | /* | 833 | /* | |
833 | * kobj_checksyms: | 834 | * kobj_checksyms: | |
834 | * | 835 | * | |
835 | * Scan symbol table for duplicates or resolve references to | 836 | * Scan symbol table for duplicates or resolve references to | |
836 | * exernal symbols. | 837 | * exernal symbols. | |
837 | */ | 838 | */ | |
838 | static int | 839 | static int | |
839 | kobj_checksyms(kobj_t ko, bool undefined) | 840 | kobj_checksyms(kobj_t ko, bool undefined) | |
840 | { | 841 | { | |
841 | unsigned long rval; | 842 | unsigned long rval; | |
842 | Elf_Sym *sym, *ms; | 843 | Elf_Sym *sym, *ms; | |
843 | const char *name; | 844 | const char *name; | |
844 | int error; | 845 | int error; | |
845 | 846 | |||
846 | error = 0; | 847 | error = 0; | |
847 | 848 | |||
848 | for (ms = (sym = ko->ko_symtab) + ko->ko_symcnt; sym < ms; sym++) { | 849 | for (ms = (sym = ko->ko_symtab) + ko->ko_symcnt; sym < ms; sym++) { | |
849 | /* Check validity of the symbol. */ | 850 | /* Check validity of the symbol. */ | |
850 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL || | 851 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL || | |
851 | sym->st_name == 0) | 852 | sym->st_name == 0) | |
852 | continue; | 853 | continue; | |
853 | if (undefined != (sym->st_shndx == SHN_UNDEF)) { | 854 | if (undefined != (sym->st_shndx == SHN_UNDEF)) { | |
854 | continue; | 855 | continue; | |
855 | } | 856 | } | |
856 | 857 | |||
857 | /* | 858 | /* | |
858 | * Look it up. Don't need to lock, as it is known that | 859 | * Look it up. Don't need to lock, as it is known that | |
859 | * the symbol tables aren't going to change (we hold | 860 | * the symbol tables aren't going to change (we hold | |
860 | * module_lock). | 861 | * module_lock). | |
861 | */ | 862 | */ | |
862 | name = ko->ko_strtab + sym->st_name; | 863 | name = ko->ko_strtab + sym->st_name; | |
863 | if (ksyms_getval_unlocked(NULL, name, &rval, | 864 | if (ksyms_getval_unlocked(NULL, name, &rval, | |
864 | KSYMS_EXTERN) != 0) { | 865 | KSYMS_EXTERN) != 0) { | |
865 | if (undefined) { | 866 | if (undefined) { | |
866 | kobj_error("symbol `%s' not found", name); | 867 | kobj_error("symbol `%s' not found", name); | |
867 | error = ENOEXEC; | 868 | error = ENOEXEC; | |
868 | } | 869 | } | |
869 | continue; | 870 | continue; | |
870 | } | 871 | } | |
871 | 872 | |||
872 | /* Save values of undefined globals. */ | 873 | /* Save values of undefined globals. */ | |
873 | if (undefined) { | 874 | if (undefined) { | |
874 | sym->st_value = (Elf_Addr)rval; | 875 | sym->st_value = (Elf_Addr)rval; | |
875 | continue; | 876 | continue; | |
876 | } | 877 | } | |
877 | 878 | |||
878 | /* Check (and complain) about differing values. */ | 879 | /* Check (and complain) about differing values. */ | |
879 | if (sym->st_value == rval) { | 880 | if (sym->st_value == rval) { | |
880 | continue; | 881 | continue; | |
881 | } | 882 | } | |
882 | if (strcmp(name, "_bss_start") == 0 || | 883 | if (strcmp(name, "_bss_start") == 0 || | |
883 | strcmp(name, "__bss_start") == 0 || | 884 | strcmp(name, "__bss_start") == 0 || | |
884 | strcmp(name, "_bss_end__") == 0 || | 885 | strcmp(name, "_bss_end__") == 0 || | |
885 | strcmp(name, "__bss_end__") == 0 || | 886 | strcmp(name, "__bss_end__") == 0 || | |
886 | strcmp(name, "_edata") == 0 || | 887 | strcmp(name, "_edata") == 0 || | |
887 | strcmp(name, "_end") == 0 || | 888 | strcmp(name, "_end") == 0 || | |
888 | strcmp(name, "__end") == 0 || | 889 | strcmp(name, "__end") == 0 || | |
889 | strcmp(name, "__end__") == 0 || | 890 | strcmp(name, "__end__") == 0 || | |
890 | strncmp(name, "__start_link_set_", 17) == 0 || | 891 | strncmp(name, "__start_link_set_", 17) == 0 || | |
891 | strncmp(name, "__stop_link_set_", 16)) { | 892 | strncmp(name, "__stop_link_set_", 16)) { | |
892 | continue; | 893 | continue; | |
893 | } | 894 | } | |
894 | kobj_error("global symbol `%s' redefined\n", name); | 895 | kobj_error("global symbol `%s' redefined\n", name); | |
895 | error = ENOEXEC; | 896 | error = ENOEXEC; | |
896 | } | 897 | } | |
897 | 898 | |||
898 | return error; | 899 | return error; | |
899 | } | 900 | } | |
900 | 901 | |||
901 | /* | 902 | /* | |
902 | * kobj_relocate: | 903 | * kobj_relocate: | |
903 | * | 904 | * | |
904 | * Resolve relocations for the loaded object. | 905 | * Resolve relocations for the loaded object. | |
905 | */ | 906 | */ | |
906 | static int | 907 | static int | |
907 | kobj_relocate(kobj_t ko, bool local) | 908 | kobj_relocate(kobj_t ko, bool local) | |
908 | { | 909 | { | |
909 | const Elf_Rel *rellim; | 910 | const Elf_Rel *rellim; | |
910 | const Elf_Rel *rel; | 911 | const Elf_Rel *rel; | |
911 | const Elf_Rela *relalim; | 912 | const Elf_Rela *relalim; | |
912 | const Elf_Rela *rela; | 913 | const Elf_Rela *rela; | |
913 | const Elf_Sym *sym; | 914 | const Elf_Sym *sym; | |
914 | uintptr_t base; | 915 | uintptr_t base; | |
915 | int i, error; | 916 | int i, error; | |
916 | uintptr_t symidx; | 917 | uintptr_t symidx; | |
917 | 918 | |||
918 | /* | 919 | /* | |
919 | * Perform relocations without addend if there are any. | 920 | * Perform relocations without addend if there are any. | |
920 | */ | 921 | */ | |
921 | for (i = 0; i < ko->ko_nrel; i++) { | 922 | for (i = 0; i < ko->ko_nrel; i++) { | |
922 | rel = ko->ko_reltab[i].rel; | 923 | rel = ko->ko_reltab[i].rel; | |
923 | if (rel == NULL) { | 924 | if (rel == NULL) { | |
924 | continue; | 925 | continue; | |
925 | } | 926 | } | |
926 | rellim = rel + ko->ko_reltab[i].nrel; | 927 | rellim = rel + ko->ko_reltab[i].nrel; | |
927 | base = kobj_findbase(ko, ko->ko_reltab[i].sec); | 928 | base = kobj_findbase(ko, ko->ko_reltab[i].sec); | |
928 | if (base == 0) { | 929 | if (base == 0) { | |
929 | panic("lost base for e_reltab"); | 930 | panic("lost base for e_reltab"); | |
930 | } | 931 | } | |
931 | for (; rel < rellim; rel++) { | 932 | for (; rel < rellim; rel++) { | |
932 | symidx = ELF_R_SYM(rel->r_info); | 933 | symidx = ELF_R_SYM(rel->r_info); | |
933 | if (symidx >= ko->ko_symcnt) { | 934 | if (symidx >= ko->ko_symcnt) { | |
934 | continue; | 935 | continue; | |
935 | } | 936 | } | |
936 | sym = ko->ko_symtab + symidx; | 937 | sym = ko->ko_symtab + symidx; | |
937 | if (local != (ELF_ST_BIND(sym->st_info) == STB_LOCAL)) { | 938 | if (local != (ELF_ST_BIND(sym->st_info) == STB_LOCAL)) { | |
938 | continue; | 939 | continue; | |
939 | } | 940 | } | |
940 | error = kobj_reloc(ko, base, rel, false, local); | 941 | error = kobj_reloc(ko, base, rel, false, local); | |
941 | if (error != 0) { | 942 | if (error != 0) { | |
942 | return ENOENT; | 943 | return ENOENT; | |
943 | } | 944 | } | |
944 | } | 945 | } | |
945 | } | 946 | } | |
946 | 947 | |||
947 | /* | 948 | /* | |
948 | * Perform relocations with addend if there are any. | 949 | * Perform relocations with addend if there are any. | |
949 | */ | 950 | */ | |
950 | for (i = 0; i < ko->ko_nrela; i++) { | 951 | for (i = 0; i < ko->ko_nrela; i++) { | |
951 | rela = ko->ko_relatab[i].rela; | 952 | rela = ko->ko_relatab[i].rela; | |
952 | if (rela == NULL) { | 953 | if (rela == NULL) { | |
953 | continue; | 954 | continue; | |
954 | } | 955 | } | |
955 | relalim = rela + ko->ko_relatab[i].nrela; | 956 | relalim = rela + ko->ko_relatab[i].nrela; | |
956 | base = kobj_findbase(ko, ko->ko_relatab[i].sec); | 957 | base = kobj_findbase(ko, ko->ko_relatab[i].sec); | |
957 | if (base == 0) { | 958 | if (base == 0) { | |
958 | panic("lost base for e_relatab"); | 959 | panic("lost base for e_relatab"); | |
959 | } | 960 | } | |
960 | for (; rela < relalim; rela++) { | 961 | for (; rela < relalim; rela++) { | |
961 | symidx = ELF_R_SYM(rela->r_info); | 962 | symidx = ELF_R_SYM(rela->r_info); | |
962 | if (symidx >= ko->ko_symcnt) { | 963 | if (symidx >= ko->ko_symcnt) { | |
963 | continue; | 964 | continue; | |
964 | } | 965 | } | |
965 | sym = ko->ko_symtab + symidx; | 966 | sym = ko->ko_symtab + symidx; | |
966 | if (local != (ELF_ST_BIND(sym->st_info) == STB_LOCAL)) { | 967 | if (local != (ELF_ST_BIND(sym->st_info) == STB_LOCAL)) { | |
967 | continue; | 968 | continue; | |
968 | } | 969 | } | |
969 | error = kobj_reloc(ko, base, rela, true, local); | 970 | error = kobj_reloc(ko, base, rela, true, local); | |
970 | if (error != 0) { | 971 | if (error != 0) { | |
971 | return ENOENT; | 972 | return ENOENT; | |
972 | } | 973 | } | |
973 | } | 974 | } | |
974 | } | 975 | } | |
975 | 976 | |||
976 | return 0; | 977 | return 0; | |
977 | } | 978 | } | |
978 | 979 | |||
979 | /* | 980 | /* | |
980 | * kobj_error: | 981 | * kobj_error: | |
981 | * | 982 | * | |
982 | * Utility function: log an error. | 983 | * Utility function: log an error. | |
983 | */ | 984 | */ | |
984 | static void | 985 | static void | |
985 | kobj_error(const char *fmt, ...) | 986 | kobj_error(const char *fmt, ...) | |
986 | { | 987 | { | |
987 | va_list ap; | 988 | va_list ap; | |
988 | 989 | |||
989 | va_start(ap, fmt); | 990 | va_start(ap, fmt); | |
990 | printf("WARNING: linker error: "); | 991 | printf("WARNING: linker error: "); | |
991 | vprintf(fmt, ap); | 992 | vprintf(fmt, ap); | |
992 | printf("\n"); | 993 | printf("\n"); | |
993 | va_end(ap); | 994 | va_end(ap); | |
994 | } | 995 | } | |
995 | 996 | |||
996 | /* | 997 | /* | |
997 | * kobj_read: | 998 | * kobj_read: | |
998 | * | 999 | * | |
999 | * Utility function: read from the object. | 1000 | * Utility function: read from the object. | |
1000 | */ | 1001 | */ | |
1001 | static int | 1002 | static int | |
1002 | kobj_read(kobj_t ko, void **basep, size_t size, off_t off) | 1003 | kobj_read(kobj_t ko, void **basep, size_t size, off_t off) | |
1003 | { | 1004 | { | |
1004 | size_t resid; | 1005 | size_t resid; | |
1005 | void *base; | 1006 | void *base; | |
1006 | int error; | 1007 | int error; | |
1007 | 1008 | |||
1008 | KASSERT(ko->ko_source != NULL); | 1009 | KASSERT(ko->ko_source != NULL); | |
1009 | 1010 | |||
1010 | switch (ko->ko_type) { | 1011 | switch (ko->ko_type) { | |
1011 | case KT_VNODE: | 1012 | case KT_VNODE: | |
1012 | base = kmem_alloc(size, KM_SLEEP); | 1013 | base = kmem_alloc(size, KM_SLEEP); | |
1013 | if (base == NULL) { | 1014 | if (base == NULL) { | |
1014 | error = ENOMEM; | 1015 | error = ENOMEM; | |
1015 | break; | 1016 | break; | |
1016 | } | 1017 | } | |
1017 | error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off, | 1018 | error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off, | |
1018 | UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, | 1019 | UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, | |
1019 | curlwp); | 1020 | curlwp); | |
1020 | if (error == 0 && resid != 0) { | 1021 | if (error == 0 && resid != 0) { | |
1021 | error = EINVAL; | 1022 | error = EINVAL; | |
1022 | } | 1023 | } | |
1023 | if (error != 0) { | 1024 | if (error != 0) { | |
1024 | kmem_free(base, size); | 1025 | kmem_free(base, size); | |
1025 | base = NULL; | 1026 | base = NULL; | |
1026 | } | 1027 | } | |
1027 | break; | 1028 | break; | |
1028 | case KT_MEMORY: | 1029 | case KT_MEMORY: | |
1029 | if (ko->ko_memsize != -1 && off + size > ko->ko_memsize) { | 1030 | if (ko->ko_memsize != -1 && off + size > ko->ko_memsize) { | |
1030 | kobj_error("kobj_read: preloaded object short"); | 1031 | kobj_error("kobj_read: preloaded object short"); | |
1031 | error = EINVAL; | 1032 | error = EINVAL; | |
1032 | base = NULL; | 1033 | base = NULL; | |
1033 | } else { | 1034 | } else { | |
1034 | base = (uint8_t *)ko->ko_source + off; | 1035 | base = (uint8_t *)ko->ko_source + off; | |
1035 | error = 0; | 1036 | error = 0; | |
1036 | } | 1037 | } | |
1037 | break; | 1038 | break; | |
1038 | default: | 1039 | default: | |
1039 | panic("kobj_read: invalid type"); | 1040 | panic("kobj_read: invalid type"); | |
1040 | } | 1041 | } | |
1041 | 1042 | |||
1042 | *basep = base; | 1043 | *basep = base; | |
1043 | return error; | 1044 | return error; | |
1044 | } | 1045 | } | |
1045 | 1046 | |||
1046 | /* | 1047 | /* | |
1047 | * kobj_read_bits: | 1048 | * kobj_read_bits: | |
1048 | * | 1049 | * | |
1049 | * Utility function: load a section from the object. | 1050 | * Utility function: load a section from the object. | |
1050 | */ | 1051 | */ | |
1051 | static int | 1052 | static int | |
1052 | kobj_read_bits(kobj_t ko, void *base, size_t size, off_t off) | 1053 | kobj_read_bits(kobj_t ko, void *base, size_t size, off_t off) | |
1053 | { | 1054 | { | |
1054 | size_t resid; | 1055 | size_t resid; | |
1055 | int error; | 1056 | int error; | |
1056 | 1057 | |||
1057 | KASSERT(ko->ko_source != NULL); | 1058 | KASSERT(ko->ko_source != NULL); | |
1058 | 1059 | |||
1059 | switch (ko->ko_type) { | 1060 | switch (ko->ko_type) { | |
1060 | case KT_VNODE: | 1061 | case KT_VNODE: | |
1061 | KASSERT((uintptr_t)base >= (uintptr_t)ko->ko_address); | 1062 | KASSERT((uintptr_t)base >= (uintptr_t)ko->ko_address); | |
1062 | KASSERT((uintptr_t)base + size <= | 1063 | KASSERT((uintptr_t)base + size <= | |
1063 | (uintptr_t)ko->ko_address + ko->ko_size); | 1064 | (uintptr_t)ko->ko_address + ko->ko_size); | |
1064 | error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off, | 1065 | error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off, | |
1065 | UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, | 1066 | UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, | |
1066 | curlwp); | 1067 | curlwp); | |
1067 | if (error == 0 && resid != 0) { | 1068 | if (error == 0 && resid != 0) { | |
1068 | error = EINVAL; | 1069 | error = EINVAL; | |
1069 | } | 1070 | } | |
1070 | break; | 1071 | break; | |
1071 | case KT_MEMORY: | 1072 | case KT_MEMORY: | |
1072 | if (ko->ko_memsize != -1 && off + size > ko->ko_memsize) { | 1073 | if (ko->ko_memsize != -1 && off + size > ko->ko_memsize) { | |
1073 | kobj_error("kobj_read_bits: preloaded object short"); | 1074 | kobj_error("kobj_read_bits: preloaded object short"); | |
1074 | error = EINVAL; | 1075 | error = EINVAL; | |
1075 | } else if ((uint8_t *)base != (uint8_t *)ko->ko_source + off) { | 1076 | } else if ((uint8_t *)base != (uint8_t *)ko->ko_source + off) { | |
1076 | kobj_error("kobj_read_bits: object not aligned"); | 1077 | kobj_error("kobj_read_bits: object not aligned"); | |
1077 | kobj_error("source=%p base=%p off=%d size=%zd", | 1078 | kobj_error("source=%p base=%p off=%d size=%zd", | |
1078 | ko->ko_source, base, (int)off, size); | 1079 | ko->ko_source, base, (int)off, size); | |
1079 | error = EINVAL; | 1080 | error = EINVAL; | |
1080 | } else { | 1081 | } else { | |
1081 | /* Nothing to do. Loading in-situ. */ | 1082 | /* Nothing to do. Loading in-situ. */ | |
1082 | error = 0; | 1083 | error = 0; | |
1083 | } | 1084 | } | |
1084 | break; | 1085 | break; | |
1085 | default: | 1086 | default: | |
1086 | panic("kobj_read: invalid type"); | 1087 | panic("kobj_read: invalid type"); | |
1087 | } | 1088 | } | |
1088 | 1089 | |||
1089 | return error; | 1090 | return error; | |
1090 | } | 1091 | } | |
1091 | 1092 | |||
1092 | /* | 1093 | /* | |
1093 | * kobj_free: | 1094 | * kobj_free: | |
1094 | * | 1095 | * | |
1095 | * Utility function: free memory if it was allocated from the heap. | 1096 | * Utility function: free memory if it was allocated from the heap. | |
1096 | */ | 1097 | */ | |
1097 | static void | 1098 | static void | |
1098 | kobj_free(kobj_t ko, void *base, size_t size) | 1099 | kobj_free(kobj_t ko, void *base, size_t size) | |
1099 | { | 1100 | { | |
1100 | 1101 | |||
1101 | if (ko->ko_type != KT_MEMORY) | 1102 | if (ko->ko_type != KT_MEMORY) | |
1102 | kmem_free(base, size); | 1103 | kmem_free(base, size); | |
1103 | } | 1104 | } | |
1104 | 1105 | |||
1105 | #else /* MODULAR */ | 1106 | #else /* MODULAR */ | |
1106 | 1107 | |||
1107 | int | 1108 | int | |
1108 | kobj_load_file(kobj_t *kop, const char *name, const uint32_t flags) | 1109 | kobj_load_file(kobj_t *kop, const char *name, const bool nochroot) | |
1109 | { | 1110 | { | |
1110 | 1111 | |||
1111 | return ENOSYS; | 1112 | return ENOSYS; | |
1112 | } | 1113 | } | |
1113 | 1114 | |||
1114 | int | 1115 | int | |
1115 | kobj_load_mem(kobj_t *kop, void *base, ssize_t size) | 1116 | kobj_load_mem(kobj_t *kop, void *base, ssize_t size) | |
1116 | { | 1117 | { | |
1117 | 1118 | |||
1118 | return ENOSYS; | 1119 | return ENOSYS; | |
1119 | } | 1120 | } | |
1120 | 1121 | |||
1121 | void | 1122 | void | |
1122 | kobj_unload(kobj_t ko) | 1123 | kobj_unload(kobj_t ko) | |
1123 | { | 1124 | { | |
1124 | 1125 | |||
1125 | panic("not modular"); | 1126 | panic("not modular"); | |
1126 | } | 1127 | } | |
1127 | 1128 | |||
1128 | void | 1129 | void | |
1129 | kobj_stat(kobj_t ko, vaddr_t *base, size_t *size) | 1130 | kobj_stat(kobj_t ko, vaddr_t *base, size_t *size) | |
1130 | { | 1131 | { | |
1131 | 1132 | |||
1132 | panic("not modular"); | 1133 | panic("not modular"); | |
1133 | } | 1134 | } | |
1134 | 1135 | |||
1135 | int | 1136 | int | |
1136 | kobj_affix(kobj_t ko, const char *name) | 1137 | kobj_affix(kobj_t ko, const char *name) | |
1137 | { | 1138 | { | |
1138 | 1139 | |||
1139 | panic("not modular"); | 1140 | panic("not modular"); | |
1140 | } | 1141 | } | |
1141 | 1142 | |||
1142 | int | 1143 | int | |
1143 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) | 1144 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) | |
1144 | { | 1145 | { | |
1145 | 1146 | |||
1146 | panic("not modular"); | 1147 | panic("not modular"); | |
1147 | } | 1148 | } | |
1148 | 1149 | |||
1149 | #endif /* MODULAR */ | 1150 | #endif /* MODULAR */ |
--- src/sys/sys/kobj.h 2009/05/25 22:33:00 1.10
+++ src/sys/sys/kobj.h 2009/05/26 08:34:22 1.11
@@ -1,47 +1,47 @@ | @@ -1,47 +1,47 @@ | |||
1 | /* $NetBSD: kobj.h,v 1.10 2009/05/25 22:33:00 jnemeth Exp $ */ | 1 | /* $NetBSD: kobj.h,v 1.11 2009/05/26 08:34:22 jnemeth Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | 26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #ifndef _SYS_KOBJ_H_ | 29 | #ifndef _SYS_KOBJ_H_ | |
30 | #define _SYS_KOBJ_H_ | 30 | #define _SYS_KOBJ_H_ | |
31 | 31 | |||
32 | typedef struct kobj *kobj_t; | 32 | typedef struct kobj *kobj_t; | |
33 | 33 | |||
34 | /* External interface. */ | 34 | /* External interface. */ | |
35 | int kobj_load_file(kobj_t *, const char *, const uint32_t); | 35 | int kobj_load_file(kobj_t *, const char *, const bool); | |
36 | int kobj_load_mem(kobj_t *, void *, ssize_t); | 36 | int kobj_load_mem(kobj_t *, void *, ssize_t); | |
37 | int kobj_affix(kobj_t, const char *); | 37 | int kobj_affix(kobj_t, const char *); | |
38 | void kobj_unload(kobj_t); | 38 | void kobj_unload(kobj_t); | |
39 | void kobj_stat(kobj_t, vaddr_t *, size_t *); | 39 | void kobj_stat(kobj_t, vaddr_t *, size_t *); | |
40 | int kobj_find_section(kobj_t, const char *, void **, size_t *); | 40 | int kobj_find_section(kobj_t, const char *, void **, size_t *); | |
41 | 41 | |||
42 | /* MI-MD interface. */ | 42 | /* MI-MD interface. */ | |
43 | uintptr_t kobj_sym_lookup(kobj_t, uintptr_t); | 43 | uintptr_t kobj_sym_lookup(kobj_t, uintptr_t); | |
44 | int kobj_reloc(kobj_t, uintptr_t, const void *, bool, bool); | 44 | int kobj_reloc(kobj_t, uintptr_t, const void *, bool, bool); | |
45 | int kobj_machdep(kobj_t, void *, size_t, bool); | 45 | int kobj_machdep(kobj_t, void *, size_t, bool); | |
46 | 46 | |||
47 | #endif /* !_SYS_KOBJ_H_ */ | 47 | #endif /* !_SYS_KOBJ_H_ */ |