xref: /openbmc/qemu/util/module.c (revision 2106106d80489fb9b10cd3ccfaec811988e797cb)
1 /*
2  * QEMU Module Infrastructure
3  *
4  * Copyright IBM, Corp. 2009
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  * Contributions after 2012-01-13 are licensed under the terms of the
13  * GNU GPL, version 2 or (at your option) any later version.
14  */
15 
16 #include "qemu/osdep.h"
17 #ifdef CONFIG_MODULES
18 #include <gmodule.h>
19 #endif
20 #include "qemu/queue.h"
21 #include "qemu/module.h"
22 #include "qemu/cutils.h"
23 #include "qemu/config-file.h"
24 #ifdef CONFIG_MODULE_UPGRADES
25 #include "qemu-version.h"
26 #endif
27 #include "trace.h"
28 
29 typedef struct ModuleEntry
30 {
31     void (*init)(void);
32     QTAILQ_ENTRY(ModuleEntry) node;
33     module_init_type type;
34 } ModuleEntry;
35 
36 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
37 
38 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
39 static bool modules_init_done[MODULE_INIT_MAX];
40 
41 static ModuleTypeList dso_init_list;
42 
43 static void init_lists(void)
44 {
45     static int inited;
46     int i;
47 
48     if (inited) {
49         return;
50     }
51 
52     for (i = 0; i < MODULE_INIT_MAX; i++) {
53         QTAILQ_INIT(&init_type_list[i]);
54     }
55 
56     QTAILQ_INIT(&dso_init_list);
57 
58     inited = 1;
59 }
60 
61 
62 static ModuleTypeList *find_type(module_init_type type)
63 {
64     init_lists();
65 
66     return &init_type_list[type];
67 }
68 
69 void register_module_init(void (*fn)(void), module_init_type type)
70 {
71     ModuleEntry *e;
72     ModuleTypeList *l;
73 
74     e = g_malloc0(sizeof(*e));
75     e->init = fn;
76     e->type = type;
77 
78     l = find_type(type);
79 
80     QTAILQ_INSERT_TAIL(l, e, node);
81 }
82 
83 void register_dso_module_init(void (*fn)(void), module_init_type type)
84 {
85     ModuleEntry *e;
86 
87     init_lists();
88 
89     e = g_malloc0(sizeof(*e));
90     e->init = fn;
91     e->type = type;
92 
93     QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
94 }
95 
96 void module_call_init(module_init_type type)
97 {
98     ModuleTypeList *l;
99     ModuleEntry *e;
100 
101     if (modules_init_done[type]) {
102         return;
103     }
104 
105     l = find_type(type);
106 
107     QTAILQ_FOREACH(e, l, node) {
108         e->init();
109     }
110 
111     modules_init_done[type] = true;
112 }
113 
114 #ifdef CONFIG_MODULES
115 
116 static const QemuModinfo module_info_stub[] = { {
117     /* end of list */
118 } };
119 static const QemuModinfo *module_info = module_info_stub;
120 static const char *module_arch;
121 
122 void module_init_info(const QemuModinfo *info)
123 {
124     module_info = info;
125 }
126 
127 void module_allow_arch(const char *arch)
128 {
129     module_arch = arch;
130 }
131 
132 static bool module_check_arch(const QemuModinfo *modinfo)
133 {
134     if (modinfo->arch) {
135         if (!module_arch) {
136             /* no arch set -> ignore all */
137             return false;
138         }
139         if (strcmp(module_arch, modinfo->arch) != 0) {
140             /* mismatch */
141             return false;
142         }
143     }
144     return true;
145 }
146 
147 static int module_load_file(const char *fname, bool export_symbols)
148 {
149     GModule *g_module;
150     void (*sym)(void);
151     const char *dsosuf = CONFIG_HOST_DSOSUF;
152     int len = strlen(fname);
153     int suf_len = strlen(dsosuf);
154     ModuleEntry *e, *next;
155     int ret, flags;
156 
157     if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
158         /* wrong suffix */
159         ret = -EINVAL;
160         goto out;
161     }
162     if (access(fname, F_OK)) {
163         ret = -ENOENT;
164         goto out;
165     }
166 
167     assert(QTAILQ_EMPTY(&dso_init_list));
168 
169     flags = 0;
170     if (!export_symbols) {
171         flags |= G_MODULE_BIND_LOCAL;
172     }
173     g_module = g_module_open(fname, flags);
174     if (!g_module) {
175         fprintf(stderr, "Failed to open module: %s\n",
176                 g_module_error());
177         ret = -EINVAL;
178         goto out;
179     }
180     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
181         fprintf(stderr, "Failed to initialize module: %s\n",
182                 fname);
183         /* Print some info if this is a QEMU module (but from different build),
184          * this will make debugging user problems easier. */
185         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
186             fprintf(stderr,
187                     "Note: only modules from the same build can be loaded.\n");
188         }
189         g_module_close(g_module);
190         ret = -EINVAL;
191     } else {
192         QTAILQ_FOREACH(e, &dso_init_list, node) {
193             e->init();
194             register_module_init(e->init, e->type);
195         }
196         ret = 0;
197     }
198 
199     trace_module_load_module(fname);
200     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
201         QTAILQ_REMOVE(&dso_init_list, e, node);
202         g_free(e);
203     }
204 out:
205     return ret;
206 }
207 #endif
208 
209 bool module_load_one(const char *prefix, const char *lib_name)
210 {
211     bool success = false;
212 
213 #ifdef CONFIG_MODULES
214     char *fname = NULL;
215 #ifdef CONFIG_MODULE_UPGRADES
216     char *version_dir;
217 #endif
218     const char *search_dir;
219     char *dirs[5];
220     char *module_name;
221     int i = 0, n_dirs = 0;
222     int ret;
223     bool export_symbols = false;
224     static GHashTable *loaded_modules;
225     const QemuModinfo *modinfo;
226     const char **sl;
227 
228     if (!g_module_supported()) {
229         fprintf(stderr, "Module is not supported by system.\n");
230         return false;
231     }
232 
233     if (!loaded_modules) {
234         loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
235     }
236 
237     module_name = g_strdup_printf("%s%s", prefix, lib_name);
238 
239     if (g_hash_table_contains(loaded_modules, module_name)) {
240         g_free(module_name);
241         return true;
242     }
243     g_hash_table_add(loaded_modules, module_name);
244 
245     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
246         if (modinfo->arch) {
247             if (strcmp(modinfo->name, module_name) == 0) {
248                 if (!module_check_arch(modinfo)) {
249                     return false;
250                 }
251             }
252         }
253         if (modinfo->deps) {
254             if (strcmp(modinfo->name, module_name) == 0) {
255                 /* we depend on other module(s) */
256                 for (sl = modinfo->deps; *sl != NULL; sl++) {
257                     module_load_one("", *sl);
258                 }
259             } else {
260                 for (sl = modinfo->deps; *sl != NULL; sl++) {
261                     if (strcmp(module_name, *sl) == 0) {
262                         /* another module depends on us */
263                         export_symbols = true;
264                     }
265                 }
266             }
267         }
268     }
269 
270     search_dir = getenv("QEMU_MODULE_DIR");
271     if (search_dir != NULL) {
272         dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
273     }
274     dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
275 
276 #ifdef CONFIG_MODULE_UPGRADES
277     version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
278                              G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
279                              '_');
280     dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
281 #endif
282 
283     assert(n_dirs <= ARRAY_SIZE(dirs));
284 
285     for (i = 0; i < n_dirs; i++) {
286         fname = g_strdup_printf("%s/%s%s",
287                 dirs[i], module_name, CONFIG_HOST_DSOSUF);
288         ret = module_load_file(fname, export_symbols);
289         g_free(fname);
290         fname = NULL;
291         /* Try loading until loaded a module file */
292         if (!ret) {
293             success = true;
294             break;
295         }
296     }
297 
298     if (!success) {
299         g_hash_table_remove(loaded_modules, module_name);
300         g_free(module_name);
301     }
302 
303     for (i = 0; i < n_dirs; i++) {
304         g_free(dirs[i]);
305     }
306 
307 #endif
308     return success;
309 }
310 
311 #ifdef CONFIG_MODULES
312 
313 static bool module_loaded_qom_all;
314 
315 void module_load_qom_one(const char *type)
316 {
317     const QemuModinfo *modinfo;
318     const char **sl;
319 
320     if (!type) {
321         return;
322     }
323 
324     trace_module_lookup_object_type(type);
325     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
326         if (!modinfo->objs) {
327             continue;
328         }
329         if (!module_check_arch(modinfo)) {
330             continue;
331         }
332         for (sl = modinfo->objs; *sl != NULL; sl++) {
333             if (strcmp(type, *sl) == 0) {
334                 module_load_one("", modinfo->name);
335             }
336         }
337     }
338 }
339 
340 void module_load_qom_all(void)
341 {
342     const QemuModinfo *modinfo;
343 
344     if (module_loaded_qom_all) {
345         return;
346     }
347 
348     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
349         if (!modinfo->objs) {
350             continue;
351         }
352         if (!module_check_arch(modinfo)) {
353             continue;
354         }
355         module_load_one("", modinfo->name);
356     }
357     module_loaded_qom_all = true;
358 }
359 
360 void qemu_load_module_for_opts(const char *group)
361 {
362     const QemuModinfo *modinfo;
363     const char **sl;
364 
365     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
366         if (!modinfo->opts) {
367             continue;
368         }
369         for (sl = modinfo->opts; *sl != NULL; sl++) {
370             if (strcmp(group, *sl) == 0) {
371                 module_load_one("", modinfo->name);
372             }
373         }
374     }
375 }
376 
377 #else
378 
379 void module_allow_arch(const char *arch) {}
380 void qemu_load_module_for_opts(const char *group) {}
381 void module_load_qom_one(const char *type) {}
382 void module_load_qom_all(void) {}
383 
384 #endif
385