Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 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 | * |
Paolo Bonzini | 6b620ca | 2012-01-13 17:44:23 +0100 | [diff] [blame] | 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. |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 14 | */ |
| 15 | |
Peter Maydell | aafd758 | 2016-01-29 17:49:55 +0000 | [diff] [blame] | 16 | #include "qemu/osdep.h" |
Paolo Bonzini | aa0d1f4 | 2014-02-25 17:36:55 +0100 | [diff] [blame] | 17 | #ifdef CONFIG_MODULES |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 18 | #include <gmodule.h> |
Paolo Bonzini | aa0d1f4 | 2014-02-25 17:36:55 +0100 | [diff] [blame] | 19 | #endif |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 20 | #include "qemu/queue.h" |
| 21 | #include "qemu/module.h" |
Paolo Bonzini | 1b93406 | 2020-08-18 12:00:18 +0200 | [diff] [blame] | 22 | #include "qemu/cutils.h" |
Gerd Hoffmann | 5111eda | 2021-06-24 12:38:18 +0200 | [diff] [blame] | 23 | #include "qemu/config-file.h" |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 24 | #include "qapi/error.h" |
Christian Ehrhardt | bd83c86 | 2020-03-10 15:58:06 +0100 | [diff] [blame] | 25 | #ifdef CONFIG_MODULE_UPGRADES |
| 26 | #include "qemu-version.h" |
| 27 | #endif |
Gerd Hoffmann | 819b8b1 | 2021-06-24 12:38:19 +0200 | [diff] [blame] | 28 | #include "trace.h" |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 29 | |
| 30 | typedef struct ModuleEntry |
| 31 | { |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 32 | void (*init)(void); |
Blue Swirl | 72cf2d4 | 2009-09-12 07:36:22 +0000 | [diff] [blame] | 33 | QTAILQ_ENTRY(ModuleEntry) node; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 34 | module_init_type type; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 35 | } ModuleEntry; |
| 36 | |
Blue Swirl | 72cf2d4 | 2009-09-12 07:36:22 +0000 | [diff] [blame] | 37 | typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 38 | |
| 39 | static ModuleTypeList init_type_list[MODULE_INIT_MAX]; |
Alexander Bulekov | 46a0757 | 2020-02-19 23:10:59 -0500 | [diff] [blame] | 40 | static bool modules_init_done[MODULE_INIT_MAX]; |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 41 | |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 42 | static ModuleTypeList dso_init_list; |
| 43 | |
| 44 | static void init_lists(void) |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 45 | { |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 46 | static int inited; |
| 47 | int i; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 48 | |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 49 | if (inited) { |
| 50 | return; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 51 | } |
| 52 | |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 53 | for (i = 0; i < MODULE_INIT_MAX; i++) { |
Blue Swirl | 72cf2d4 | 2009-09-12 07:36:22 +0000 | [diff] [blame] | 54 | QTAILQ_INIT(&init_type_list[i]); |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 55 | } |
| 56 | |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 57 | QTAILQ_INIT(&dso_init_list); |
| 58 | |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 59 | inited = 1; |
| 60 | } |
| 61 | |
| 62 | |
| 63 | static ModuleTypeList *find_type(module_init_type type) |
| 64 | { |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 65 | init_lists(); |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 66 | |
Eduardo Habkost | 9be3859 | 2016-06-13 18:57:58 -0300 | [diff] [blame] | 67 | return &init_type_list[type]; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | void register_module_init(void (*fn)(void), module_init_type type) |
| 71 | { |
| 72 | ModuleEntry *e; |
| 73 | ModuleTypeList *l; |
| 74 | |
Anthony Liguori | 7267c09 | 2011-08-20 22:09:37 -0500 | [diff] [blame] | 75 | e = g_malloc0(sizeof(*e)); |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 76 | e->init = fn; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 77 | e->type = type; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 78 | |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 79 | l = find_type(type); |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 80 | |
Blue Swirl | 72cf2d4 | 2009-09-12 07:36:22 +0000 | [diff] [blame] | 81 | QTAILQ_INSERT_TAIL(l, e, node); |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 82 | } |
| 83 | |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 84 | void 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 Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 97 | void module_call_init(module_init_type type) |
| 98 | { |
| 99 | ModuleTypeList *l; |
| 100 | ModuleEntry *e; |
| 101 | |
Alexander Bulekov | 46a0757 | 2020-02-19 23:10:59 -0500 | [diff] [blame] | 102 | if (modules_init_done[type]) { |
| 103 | return; |
| 104 | } |
| 105 | |
Anthony Liguori | f789743 | 2009-05-14 17:57:31 -0500 | [diff] [blame] | 106 | l = find_type(type); |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 107 | |
Blue Swirl | 72cf2d4 | 2009-09-12 07:36:22 +0000 | [diff] [blame] | 108 | QTAILQ_FOREACH(e, l, node) { |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 109 | e->init(); |
| 110 | } |
Alexander Bulekov | 46a0757 | 2020-02-19 23:10:59 -0500 | [diff] [blame] | 111 | |
| 112 | modules_init_done[type] = true; |
Anthony Liguori | 0bfe3ca | 2009-05-14 19:29:53 +0100 | [diff] [blame] | 113 | } |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 114 | |
| 115 | #ifdef CONFIG_MODULES |
Gerd Hoffmann | 5ebbfec | 2021-06-24 12:38:05 +0200 | [diff] [blame] | 116 | |
| 117 | static const QemuModinfo module_info_stub[] = { { |
| 118 | /* end of list */ |
| 119 | } }; |
| 120 | static const QemuModinfo *module_info = module_info_stub; |
Gerd Hoffmann | d7795d3 | 2021-06-24 12:38:20 +0200 | [diff] [blame] | 121 | static const char *module_arch; |
Gerd Hoffmann | 5ebbfec | 2021-06-24 12:38:05 +0200 | [diff] [blame] | 122 | |
| 123 | void module_init_info(const QemuModinfo *info) |
| 124 | { |
| 125 | module_info = info; |
| 126 | } |
| 127 | |
Gerd Hoffmann | d7795d3 | 2021-06-24 12:38:20 +0200 | [diff] [blame] | 128 | void module_allow_arch(const char *arch) |
| 129 | { |
| 130 | module_arch = arch; |
| 131 | } |
| 132 | |
| 133 | static 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 Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 148 | /* |
| 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 | */ |
| 157 | static bool module_load_dso(const char *fname, bool export_symbols, |
| 158 | Error **errp) |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 159 | { |
| 160 | GModule *g_module; |
| 161 | void (*sym)(void); |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 162 | ModuleEntry *e, *next; |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 163 | int flags; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 164 | |
| 165 | assert(QTAILQ_EMPTY(&dso_init_list)); |
| 166 | |
Gerd Hoffmann | 546323b | 2020-10-28 06:49:44 +0100 | [diff] [blame] | 167 | flags = 0; |
Gerd Hoffmann | 6f13fa7 | 2020-10-19 09:52:20 +0200 | [diff] [blame] | 168 | if (!export_symbols) { |
| 169 | flags |= G_MODULE_BIND_LOCAL; |
| 170 | } |
| 171 | g_module = g_module_open(fname, flags); |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 172 | if (!g_module) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 173 | error_setg(errp, "failed to open module: %s", g_module_error()); |
| 174 | return false; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 175 | } |
| 176 | if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 177 | 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 Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 182 | if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 183 | error_append_hint(errp, |
| 184 | "Only modules from the same build can be loaded.\n"); |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 185 | } |
| 186 | g_module_close(g_module); |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 187 | return false; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 188 | } |
| 189 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 190 | QTAILQ_FOREACH(e, &dso_init_list, node) { |
| 191 | e->init(); |
| 192 | register_module_init(e->init, e->type); |
| 193 | } |
Gerd Hoffmann | 819b8b1 | 2021-06-24 12:38:19 +0200 | [diff] [blame] | 194 | trace_module_load_module(fname); |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 195 | QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) { |
| 196 | QTAILQ_REMOVE(&dso_init_list, e, node); |
| 197 | g_free(e); |
| 198 | } |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 199 | return true; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 200 | } |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 201 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 202 | int module_load(const char *prefix, const char *name, Error **errp) |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 203 | { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 204 | int rv = -1; |
Christian Ehrhardt | bd83c86 | 2020-03-10 15:58:06 +0100 | [diff] [blame] | 205 | #ifdef CONFIG_MODULE_UPGRADES |
| 206 | char *version_dir; |
| 207 | #endif |
ryang | 900610e | 2018-07-04 14:10:10 -0400 | [diff] [blame] | 208 | const char *search_dir; |
Bruce Rogers | 267514b | 2020-04-10 19:07:46 -0600 | [diff] [blame] | 209 | char *dirs[5]; |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 210 | char *module_name; |
ryang | 900610e | 2018-07-04 14:10:10 -0400 | [diff] [blame] | 211 | int i = 0, n_dirs = 0; |
Gerd Hoffmann | 6f13fa7 | 2020-10-19 09:52:20 +0200 | [diff] [blame] | 212 | bool export_symbols = false; |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 213 | static GHashTable *loaded_modules; |
Gerd Hoffmann | e897b9a | 2021-06-24 12:38:16 +0200 | [diff] [blame] | 214 | const QemuModinfo *modinfo; |
| 215 | const char **sl; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 216 | |
| 217 | if (!g_module_supported()) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 218 | error_setg(errp, "%s", "this platform does not support GLib modules"); |
| 219 | return -1; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 220 | } |
| 221 | |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 222 | if (!loaded_modules) { |
| 223 | loaded_modules = g_hash_table_new(g_str_hash, g_str_equal); |
| 224 | } |
| 225 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 226 | /* allocate all resources managed by the out: label here */ |
| 227 | module_name = g_strdup_printf("%s%s", prefix, name); |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 228 | |
Marc-André Lureau | 64e16fb | 2021-03-16 17:44:56 +0400 | [diff] [blame] | 229 | if (g_hash_table_contains(loaded_modules, module_name)) { |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 230 | g_free(module_name); |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 231 | return 2; /* module already loaded */ |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 232 | } |
Marc-André Lureau | 64e16fb | 2021-03-16 17:44:56 +0400 | [diff] [blame] | 233 | g_hash_table_add(loaded_modules, module_name); |
Fam Zheng | dffa41b | 2016-09-05 10:50:44 +0800 | [diff] [blame] | 234 | |
ryang | 900610e | 2018-07-04 14:10:10 -0400 | [diff] [blame] | 235 | search_dir = getenv("QEMU_MODULE_DIR"); |
| 236 | if (search_dir != NULL) { |
| 237 | dirs[n_dirs++] = g_strdup_printf("%s", search_dir); |
| 238 | } |
Paolo Bonzini | 1b93406 | 2020-08-18 12:00:18 +0200 | [diff] [blame] | 239 | dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR); |
Christian Ehrhardt | bd83c86 | 2020-03-10 15:58:06 +0100 | [diff] [blame] | 240 | |
| 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 |
ryang | 900610e | 2018-07-04 14:10:10 -0400 | [diff] [blame] | 247 | assert(n_dirs <= ARRAY_SIZE(dirs)); |
| 248 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 249 | /* 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 Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 279 | } |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 280 | } |
| 281 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 282 | 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 | |
| 306 | out: |
| 307 | if (rv <= 0) { |
Marc-André Lureau | 81d8ccb | 2019-07-22 17:13:23 +0400 | [diff] [blame] | 308 | g_hash_table_remove(loaded_modules, module_name); |
Pan Nengyuan | 638be47 | 2019-12-20 09:34:10 +0800 | [diff] [blame] | 309 | g_free(module_name); |
Marc-André Lureau | 81d8ccb | 2019-07-22 17:13:23 +0400 | [diff] [blame] | 310 | } |
ryang | 900610e | 2018-07-04 14:10:10 -0400 | [diff] [blame] | 311 | for (i = 0; i < n_dirs; i++) { |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 312 | g_free(dirs[i]); |
| 313 | } |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 314 | return rv; |
Fam Zheng | e26110c | 2014-02-10 14:48:57 +0800 | [diff] [blame] | 315 | } |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 316 | |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 317 | static bool module_loaded_qom_all; |
| 318 | |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 319 | int module_load_qom(const char *type, Error **errp) |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 320 | { |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 321 | const QemuModinfo *modinfo; |
| 322 | const char **sl; |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 323 | int rv = 0; |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 324 | |
Gerd Hoffmann | d87350b | 2020-07-20 12:03:51 +0200 | [diff] [blame] | 325 | if (!type) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 326 | error_setg(errp, "%s", "type is NULL"); |
| 327 | return -1; |
Gerd Hoffmann | d87350b | 2020-07-20 12:03:51 +0200 | [diff] [blame] | 328 | } |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 329 | |
Gerd Hoffmann | 819b8b1 | 2021-06-24 12:38:19 +0200 | [diff] [blame] | 330 | trace_module_lookup_object_type(type); |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 331 | for (modinfo = module_info; modinfo->name != NULL; modinfo++) { |
| 332 | if (!modinfo->objs) { |
| 333 | continue; |
| 334 | } |
Gerd Hoffmann | ab0cfc3 | 2021-06-24 12:38:21 +0200 | [diff] [blame] | 335 | if (!module_check_arch(modinfo)) { |
| 336 | continue; |
| 337 | } |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 338 | for (sl = modinfo->objs; *sl != NULL; sl++) { |
| 339 | if (strcmp(type, *sl) == 0) { |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 340 | 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 Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 348 | } |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 349 | } |
| 350 | } |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 351 | return rv; |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | void module_load_qom_all(void) |
| 355 | { |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 356 | const QemuModinfo *modinfo; |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 357 | Error *local_err = NULL; |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 358 | |
| 359 | if (module_loaded_qom_all) { |
| 360 | return; |
| 361 | } |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 362 | |
| 363 | for (modinfo = module_info; modinfo->name != NULL; modinfo++) { |
| 364 | if (!modinfo->objs) { |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 365 | continue; |
| 366 | } |
Gerd Hoffmann | ab0cfc3 | 2021-06-24 12:38:21 +0200 | [diff] [blame] | 367 | if (!module_check_arch(modinfo)) { |
| 368 | continue; |
| 369 | } |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 370 | if (module_load("", modinfo->name, &local_err) < 0) { |
| 371 | error_report_err(local_err); |
| 372 | } |
Gerd Hoffmann | 2845774 | 2020-06-24 15:10:36 +0200 | [diff] [blame] | 373 | } |
| 374 | module_loaded_qom_all = true; |
| 375 | } |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 376 | |
Gerd Hoffmann | 5111eda | 2021-06-24 12:38:18 +0200 | [diff] [blame] | 377 | void 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 Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 388 | Error *local_err = NULL; |
| 389 | if (module_load("", modinfo->name, &local_err) < 0) { |
| 390 | error_report_err(local_err); |
| 391 | } |
Gerd Hoffmann | 5111eda | 2021-06-24 12:38:18 +0200 | [diff] [blame] | 392 | } |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 397 | #else |
| 398 | |
Gerd Hoffmann | d7795d3 | 2021-06-24 12:38:20 +0200 | [diff] [blame] | 399 | void module_allow_arch(const char *arch) {} |
Gerd Hoffmann | 5111eda | 2021-06-24 12:38:18 +0200 | [diff] [blame] | 400 | void qemu_load_module_for_opts(const char *group) {} |
Claudio Fontana | c551fb0 | 2022-09-29 11:30:33 +0200 | [diff] [blame] | 401 | int module_load(const char *prefix, const char *name, Error **errp) { return 2; } |
| 402 | int module_load_qom(const char *type, Error **errp) { return 2; } |
Gerd Hoffmann | 9f4a0f0 | 2021-06-24 12:38:17 +0200 | [diff] [blame] | 403 | void module_load_qom_all(void) {} |
| 404 | |
| 405 | #endif |