blob: 32e263163c75dfa8e93ca67c739d4a501162353c [file] [log] [blame]
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +01001/*
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 *
Paolo Bonzini6b620ca2012-01-13 17:44:23 +010012 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010014 */
15
Peter Maydellaafd7582016-01-29 17:49:55 +000016#include "qemu/osdep.h"
Paolo Bonziniaa0d1f42014-02-25 17:36:55 +010017#ifdef CONFIG_MODULES
Fam Zhenge26110c2014-02-10 14:48:57 +080018#include <gmodule.h>
Paolo Bonziniaa0d1f42014-02-25 17:36:55 +010019#endif
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010020#include "qemu/queue.h"
21#include "qemu/module.h"
Paolo Bonzini1b934062020-08-18 12:00:18 +020022#include "qemu/cutils.h"
Gerd Hoffmann5111eda2021-06-24 12:38:18 +020023#include "qemu/config-file.h"
Claudio Fontanac551fb02022-09-29 11:30:33 +020024#include "qapi/error.h"
Christian Ehrhardtbd83c862020-03-10 15:58:06 +010025#ifdef CONFIG_MODULE_UPGRADES
26#include "qemu-version.h"
27#endif
Gerd Hoffmann819b8b12021-06-24 12:38:19 +020028#include "trace.h"
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010029
30typedef struct ModuleEntry
31{
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010032 void (*init)(void);
Blue Swirl72cf2d42009-09-12 07:36:22 +000033 QTAILQ_ENTRY(ModuleEntry) node;
Fam Zhenge26110c2014-02-10 14:48:57 +080034 module_init_type type;
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010035} ModuleEntry;
36
Blue Swirl72cf2d42009-09-12 07:36:22 +000037typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
Anthony Liguorif7897432009-05-14 17:57:31 -050038
39static ModuleTypeList init_type_list[MODULE_INIT_MAX];
Alexander Bulekov46a07572020-02-19 23:10:59 -050040static bool modules_init_done[MODULE_INIT_MAX];
Anthony Liguorif7897432009-05-14 17:57:31 -050041
Fam Zhenge26110c2014-02-10 14:48:57 +080042static ModuleTypeList dso_init_list;
43
44static void init_lists(void)
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010045{
Anthony Liguorif7897432009-05-14 17:57:31 -050046 static int inited;
47 int i;
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010048
Anthony Liguorif7897432009-05-14 17:57:31 -050049 if (inited) {
50 return;
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010051 }
52
Anthony Liguorif7897432009-05-14 17:57:31 -050053 for (i = 0; i < MODULE_INIT_MAX; i++) {
Blue Swirl72cf2d42009-09-12 07:36:22 +000054 QTAILQ_INIT(&init_type_list[i]);
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010055 }
56
Fam Zhenge26110c2014-02-10 14:48:57 +080057 QTAILQ_INIT(&dso_init_list);
58
Anthony Liguorif7897432009-05-14 17:57:31 -050059 inited = 1;
60}
61
62
63static ModuleTypeList *find_type(module_init_type type)
64{
Fam Zhenge26110c2014-02-10 14:48:57 +080065 init_lists();
Anthony Liguorif7897432009-05-14 17:57:31 -050066
Eduardo Habkost9be38592016-06-13 18:57:58 -030067 return &init_type_list[type];
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010068}
69
70void register_module_init(void (*fn)(void), module_init_type type)
71{
72 ModuleEntry *e;
73 ModuleTypeList *l;
74
Anthony Liguori7267c092011-08-20 22:09:37 -050075 e = g_malloc0(sizeof(*e));
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010076 e->init = fn;
Fam Zhenge26110c2014-02-10 14:48:57 +080077 e->type = type;
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010078
Anthony Liguorif7897432009-05-14 17:57:31 -050079 l = find_type(type);
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010080
Blue Swirl72cf2d42009-09-12 07:36:22 +000081 QTAILQ_INSERT_TAIL(l, e, node);
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010082}
83
Fam Zhenge26110c2014-02-10 14:48:57 +080084void register_dso_module_init(void (*fn)(void), module_init_type type)
85{
86 ModuleEntry *e;
87
88 init_lists();
89
90 e = g_malloc0(sizeof(*e));
91 e->init = fn;
92 e->type = type;
93
94 QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
95}
96
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +010097void module_call_init(module_init_type type)
98{
99 ModuleTypeList *l;
100 ModuleEntry *e;
101
Alexander Bulekov46a07572020-02-19 23:10:59 -0500102 if (modules_init_done[type]) {
103 return;
104 }
105
Anthony Liguorif7897432009-05-14 17:57:31 -0500106 l = find_type(type);
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +0100107
Blue Swirl72cf2d42009-09-12 07:36:22 +0000108 QTAILQ_FOREACH(e, l, node) {
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +0100109 e->init();
110 }
Alexander Bulekov46a07572020-02-19 23:10:59 -0500111
112 modules_init_done[type] = true;
Anthony Liguori0bfe3ca2009-05-14 19:29:53 +0100113}
Fam Zhenge26110c2014-02-10 14:48:57 +0800114
115#ifdef CONFIG_MODULES
Gerd Hoffmann5ebbfec2021-06-24 12:38:05 +0200116
117static const QemuModinfo module_info_stub[] = { {
118 /* end of list */
119} };
120static const QemuModinfo *module_info = module_info_stub;
Gerd Hoffmannd7795d32021-06-24 12:38:20 +0200121static const char *module_arch;
Gerd Hoffmann5ebbfec2021-06-24 12:38:05 +0200122
123void module_init_info(const QemuModinfo *info)
124{
125 module_info = info;
126}
127
Gerd Hoffmannd7795d32021-06-24 12:38:20 +0200128void module_allow_arch(const char *arch)
129{
130 module_arch = arch;
131}
132
133static bool module_check_arch(const QemuModinfo *modinfo)
134{
135 if (modinfo->arch) {
136 if (!module_arch) {
137 /* no arch set -> ignore all */
138 return false;
139 }
140 if (strcmp(module_arch, modinfo->arch) != 0) {
141 /* mismatch */
142 return false;
143 }
144 }
145 return true;
146}
147
Claudio Fontanac551fb02022-09-29 11:30:33 +0200148/*
149 * module_load_dso: attempt to load an existing dso file
150 *
151 * fname: full pathname of the file to load
152 * export_symbols: if true, add the symbols to the global name space
153 * errp: error to set.
154 *
155 * Return value: true on success, false on error, and errp will be set.
156 */
157static bool module_load_dso(const char *fname, bool export_symbols,
158 Error **errp)
Fam Zhenge26110c2014-02-10 14:48:57 +0800159{
160 GModule *g_module;
161 void (*sym)(void);
Fam Zhenge26110c2014-02-10 14:48:57 +0800162 ModuleEntry *e, *next;
Claudio Fontanac551fb02022-09-29 11:30:33 +0200163 int flags;
Fam Zhenge26110c2014-02-10 14:48:57 +0800164
165 assert(QTAILQ_EMPTY(&dso_init_list));
166
Gerd Hoffmann546323b2020-10-28 06:49:44 +0100167 flags = 0;
Gerd Hoffmann6f13fa72020-10-19 09:52:20 +0200168 if (!export_symbols) {
169 flags |= G_MODULE_BIND_LOCAL;
170 }
171 g_module = g_module_open(fname, flags);
Fam Zhenge26110c2014-02-10 14:48:57 +0800172 if (!g_module) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200173 error_setg(errp, "failed to open module: %s", g_module_error());
174 return false;
Fam Zhenge26110c2014-02-10 14:48:57 +0800175 }
176 if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200177 error_setg(errp, "failed to initialize module: %s", fname);
178 /*
179 * Print some info if this is a QEMU module (but from different build),
180 * this will make debugging user problems easier.
181 */
Fam Zhenge26110c2014-02-10 14:48:57 +0800182 if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200183 error_append_hint(errp,
184 "Only modules from the same build can be loaded.\n");
Fam Zhenge26110c2014-02-10 14:48:57 +0800185 }
186 g_module_close(g_module);
Claudio Fontanac551fb02022-09-29 11:30:33 +0200187 return false;
Fam Zhenge26110c2014-02-10 14:48:57 +0800188 }
189
Claudio Fontanac551fb02022-09-29 11:30:33 +0200190 QTAILQ_FOREACH(e, &dso_init_list, node) {
191 e->init();
192 register_module_init(e->init, e->type);
193 }
Gerd Hoffmann819b8b12021-06-24 12:38:19 +0200194 trace_module_load_module(fname);
Fam Zhenge26110c2014-02-10 14:48:57 +0800195 QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
196 QTAILQ_REMOVE(&dso_init_list, e, node);
197 g_free(e);
198 }
Claudio Fontanac551fb02022-09-29 11:30:33 +0200199 return true;
Fam Zhenge26110c2014-02-10 14:48:57 +0800200}
Fam Zhenge26110c2014-02-10 14:48:57 +0800201
Claudio Fontanac551fb02022-09-29 11:30:33 +0200202int module_load(const char *prefix, const char *name, Error **errp)
Fam Zhenge26110c2014-02-10 14:48:57 +0800203{
Claudio Fontanac551fb02022-09-29 11:30:33 +0200204 int rv = -1;
Christian Ehrhardtbd83c862020-03-10 15:58:06 +0100205#ifdef CONFIG_MODULE_UPGRADES
206 char *version_dir;
207#endif
ryang900610e2018-07-04 14:10:10 -0400208 const char *search_dir;
Bruce Rogers267514b2020-04-10 19:07:46 -0600209 char *dirs[5];
Fam Zhengdffa41b2016-09-05 10:50:44 +0800210 char *module_name;
ryang900610e2018-07-04 14:10:10 -0400211 int i = 0, n_dirs = 0;
Gerd Hoffmann6f13fa72020-10-19 09:52:20 +0200212 bool export_symbols = false;
Fam Zhengdffa41b2016-09-05 10:50:44 +0800213 static GHashTable *loaded_modules;
Gerd Hoffmanne897b9a2021-06-24 12:38:16 +0200214 const QemuModinfo *modinfo;
215 const char **sl;
Fam Zhenge26110c2014-02-10 14:48:57 +0800216
217 if (!g_module_supported()) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200218 error_setg(errp, "%s", "this platform does not support GLib modules");
219 return -1;
Fam Zhenge26110c2014-02-10 14:48:57 +0800220 }
221
Fam Zhengdffa41b2016-09-05 10:50:44 +0800222 if (!loaded_modules) {
223 loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
224 }
225
Claudio Fontanac551fb02022-09-29 11:30:33 +0200226 /* allocate all resources managed by the out: label here */
227 module_name = g_strdup_printf("%s%s", prefix, name);
Fam Zhengdffa41b2016-09-05 10:50:44 +0800228
Marc-André Lureau64e16fb2021-03-16 17:44:56 +0400229 if (g_hash_table_contains(loaded_modules, module_name)) {
Fam Zhengdffa41b2016-09-05 10:50:44 +0800230 g_free(module_name);
Claudio Fontanac551fb02022-09-29 11:30:33 +0200231 return 2; /* module already loaded */
Fam Zhengdffa41b2016-09-05 10:50:44 +0800232 }
Marc-André Lureau64e16fb2021-03-16 17:44:56 +0400233 g_hash_table_add(loaded_modules, module_name);
Fam Zhengdffa41b2016-09-05 10:50:44 +0800234
ryang900610e2018-07-04 14:10:10 -0400235 search_dir = getenv("QEMU_MODULE_DIR");
236 if (search_dir != NULL) {
237 dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
238 }
Paolo Bonzini1b934062020-08-18 12:00:18 +0200239 dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
Christian Ehrhardtbd83c862020-03-10 15:58:06 +0100240
241#ifdef CONFIG_MODULE_UPGRADES
242 version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
243 G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
244 '_');
245 dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
246#endif
ryang900610e2018-07-04 14:10:10 -0400247 assert(n_dirs <= ARRAY_SIZE(dirs));
248
Claudio Fontanac551fb02022-09-29 11:30:33 +0200249 /* end of resources managed by the out: label */
250
251 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
252 if (modinfo->arch) {
253 if (strcmp(modinfo->name, module_name) == 0) {
254 if (!module_check_arch(modinfo)) {
255 error_setg(errp, "module arch does not match: "
256 "expected '%s', got '%s'", module_arch, modinfo->arch);
257 goto out;
258 }
259 }
260 }
261 if (modinfo->deps) {
262 if (strcmp(modinfo->name, module_name) == 0) {
263 /* we depend on other module(s) */
264 for (sl = modinfo->deps; *sl != NULL; sl++) {
265 int subrv = module_load("", *sl, errp);
266 if (subrv <= 0) {
267 rv = subrv;
268 goto out;
269 }
270 }
271 } else {
272 for (sl = modinfo->deps; *sl != NULL; sl++) {
273 if (strcmp(module_name, *sl) == 0) {
274 /* another module depends on us */
275 export_symbols = true;
276 }
277 }
278 }
Fam Zhenge26110c2014-02-10 14:48:57 +0800279 }
Fam Zhenge26110c2014-02-10 14:48:57 +0800280 }
281
Claudio Fontanac551fb02022-09-29 11:30:33 +0200282 for (i = 0; i < n_dirs; i++) {
283 char *fname = g_strdup_printf("%s/%s%s",
284 dirs[i], module_name, CONFIG_HOST_DSOSUF);
285 int ret = access(fname, F_OK);
286 if (ret != 0 && (errno == ENOENT || errno == ENOTDIR)) {
287 /*
288 * if we don't find the module in this dir, try the next one.
289 * If we don't find it in any dir, that can be fine too: user
290 * did not install the module. We will return 0 in this case
291 * with no error set.
292 */
293 g_free(fname);
294 continue;
295 } else if (ret != 0) {
296 /* most common is EACCES here */
297 error_setg_errno(errp, errno, "error trying to access %s", fname);
298 } else if (module_load_dso(fname, export_symbols, errp)) {
299 rv = 1; /* module successfully loaded */
300 }
301 g_free(fname);
302 goto out;
303 }
304 rv = 0; /* module not found */
305
306out:
307 if (rv <= 0) {
Marc-André Lureau81d8ccb2019-07-22 17:13:23 +0400308 g_hash_table_remove(loaded_modules, module_name);
Pan Nengyuan638be472019-12-20 09:34:10 +0800309 g_free(module_name);
Marc-André Lureau81d8ccb2019-07-22 17:13:23 +0400310 }
ryang900610e2018-07-04 14:10:10 -0400311 for (i = 0; i < n_dirs; i++) {
Fam Zhenge26110c2014-02-10 14:48:57 +0800312 g_free(dirs[i]);
313 }
Claudio Fontanac551fb02022-09-29 11:30:33 +0200314 return rv;
Fam Zhenge26110c2014-02-10 14:48:57 +0800315}
Gerd Hoffmann28457742020-06-24 15:10:36 +0200316
Gerd Hoffmann28457742020-06-24 15:10:36 +0200317static bool module_loaded_qom_all;
318
Claudio Fontanac551fb02022-09-29 11:30:33 +0200319int module_load_qom(const char *type, Error **errp)
Gerd Hoffmann28457742020-06-24 15:10:36 +0200320{
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200321 const QemuModinfo *modinfo;
322 const char **sl;
Claudio Fontanac551fb02022-09-29 11:30:33 +0200323 int rv = 0;
Gerd Hoffmann28457742020-06-24 15:10:36 +0200324
Gerd Hoffmannd87350b2020-07-20 12:03:51 +0200325 if (!type) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200326 error_setg(errp, "%s", "type is NULL");
327 return -1;
Gerd Hoffmannd87350b2020-07-20 12:03:51 +0200328 }
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200329
Gerd Hoffmann819b8b12021-06-24 12:38:19 +0200330 trace_module_lookup_object_type(type);
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200331 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
332 if (!modinfo->objs) {
333 continue;
334 }
Gerd Hoffmannab0cfc32021-06-24 12:38:21 +0200335 if (!module_check_arch(modinfo)) {
336 continue;
337 }
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200338 for (sl = modinfo->objs; *sl != NULL; sl++) {
339 if (strcmp(type, *sl) == 0) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200340 if (rv > 0) {
341 error_setg(errp, "multiple modules providing '%s'", type);
342 return -1;
343 }
344 rv = module_load("", modinfo->name, errp);
345 if (rv < 0) {
346 return rv;
347 }
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200348 }
Gerd Hoffmann28457742020-06-24 15:10:36 +0200349 }
350 }
Claudio Fontanac551fb02022-09-29 11:30:33 +0200351 return rv;
Gerd Hoffmann28457742020-06-24 15:10:36 +0200352}
353
354void module_load_qom_all(void)
355{
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200356 const QemuModinfo *modinfo;
Claudio Fontanac551fb02022-09-29 11:30:33 +0200357 Error *local_err = NULL;
Gerd Hoffmann28457742020-06-24 15:10:36 +0200358
359 if (module_loaded_qom_all) {
360 return;
361 }
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200362
363 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
364 if (!modinfo->objs) {
Gerd Hoffmann28457742020-06-24 15:10:36 +0200365 continue;
366 }
Gerd Hoffmannab0cfc32021-06-24 12:38:21 +0200367 if (!module_check_arch(modinfo)) {
368 continue;
369 }
Claudio Fontanac551fb02022-09-29 11:30:33 +0200370 if (module_load("", modinfo->name, &local_err) < 0) {
371 error_report_err(local_err);
372 }
Gerd Hoffmann28457742020-06-24 15:10:36 +0200373 }
374 module_loaded_qom_all = true;
375}
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200376
Gerd Hoffmann5111eda2021-06-24 12:38:18 +0200377void qemu_load_module_for_opts(const char *group)
378{
379 const QemuModinfo *modinfo;
380 const char **sl;
381
382 for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
383 if (!modinfo->opts) {
384 continue;
385 }
386 for (sl = modinfo->opts; *sl != NULL; sl++) {
387 if (strcmp(group, *sl) == 0) {
Claudio Fontanac551fb02022-09-29 11:30:33 +0200388 Error *local_err = NULL;
389 if (module_load("", modinfo->name, &local_err) < 0) {
390 error_report_err(local_err);
391 }
Gerd Hoffmann5111eda2021-06-24 12:38:18 +0200392 }
393 }
394 }
395}
396
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200397#else
398
Gerd Hoffmannd7795d32021-06-24 12:38:20 +0200399void module_allow_arch(const char *arch) {}
Gerd Hoffmann5111eda2021-06-24 12:38:18 +0200400void qemu_load_module_for_opts(const char *group) {}
Claudio Fontanac551fb02022-09-29 11:30:33 +0200401int module_load(const char *prefix, const char *name, Error **errp) { return 2; }
402int module_load_qom(const char *type, Error **errp) { return 2; }
Gerd Hoffmann9f4a0f02021-06-24 12:38:17 +0200403void module_load_qom_all(void) {}
404
405#endif