qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

module.c (10574B)


      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 #include "qapi/error.h"
     25 #ifdef CONFIG_MODULE_UPGRADES
     26 #include "qemu-version.h"
     27 #endif
     28 #include "trace.h"
     29 
     30 typedef struct ModuleEntry
     31 {
     32     void (*init)(void);
     33     QTAILQ_ENTRY(ModuleEntry) node;
     34     module_init_type type;
     35 } ModuleEntry;
     36 
     37 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
     38 
     39 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
     40 static bool modules_init_done[MODULE_INIT_MAX];
     41 
     42 static ModuleTypeList dso_init_list;
     43 
     44 static void init_lists(void)
     45 {
     46     static int inited;
     47     int i;
     48 
     49     if (inited) {
     50         return;
     51     }
     52 
     53     for (i = 0; i < MODULE_INIT_MAX; i++) {
     54         QTAILQ_INIT(&init_type_list[i]);
     55     }
     56 
     57     QTAILQ_INIT(&dso_init_list);
     58 
     59     inited = 1;
     60 }
     61 
     62 
     63 static ModuleTypeList *find_type(module_init_type type)
     64 {
     65     init_lists();
     66 
     67     return &init_type_list[type];
     68 }
     69 
     70 void register_module_init(void (*fn)(void), module_init_type type)
     71 {
     72     ModuleEntry *e;
     73     ModuleTypeList *l;
     74 
     75     e = g_malloc0(sizeof(*e));
     76     e->init = fn;
     77     e->type = type;
     78 
     79     l = find_type(type);
     80 
     81     QTAILQ_INSERT_TAIL(l, e, node);
     82 }
     83 
     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 
     97 void module_call_init(module_init_type type)
     98 {
     99     ModuleTypeList *l;
    100     ModuleEntry *e;
    101 
    102     if (modules_init_done[type]) {
    103         return;
    104     }
    105 
    106     l = find_type(type);
    107 
    108     QTAILQ_FOREACH(e, l, node) {
    109         e->init();
    110     }
    111 
    112     modules_init_done[type] = true;
    113 }
    114 
    115 #ifdef CONFIG_MODULES
    116 
    117 static const QemuModinfo module_info_stub[] = { {
    118     /* end of list */
    119 } };
    120 static const QemuModinfo *module_info = module_info_stub;
    121 static const char *module_arch;
    122 
    123 void module_init_info(const QemuModinfo *info)
    124 {
    125     module_info = info;
    126 }
    127 
    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 
    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)
    159 {
    160     GModule *g_module;
    161     void (*sym)(void);
    162     ModuleEntry *e, *next;
    163     int flags;
    164 
    165     assert(QTAILQ_EMPTY(&dso_init_list));
    166 
    167     flags = 0;
    168     if (!export_symbols) {
    169         flags |= G_MODULE_BIND_LOCAL;
    170     }
    171     g_module = g_module_open(fname, flags);
    172     if (!g_module) {
    173         error_setg(errp, "failed to open module: %s", g_module_error());
    174         return false;
    175     }
    176     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
    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          */
    182         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
    183             error_append_hint(errp,
    184                 "Only modules from the same build can be loaded.\n");
    185         }
    186         g_module_close(g_module);
    187         return false;
    188     }
    189 
    190     QTAILQ_FOREACH(e, &dso_init_list, node) {
    191         e->init();
    192         register_module_init(e->init, e->type);
    193     }
    194     trace_module_load_module(fname);
    195     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
    196         QTAILQ_REMOVE(&dso_init_list, e, node);
    197         g_free(e);
    198     }
    199     return true;
    200 }
    201 
    202 int module_load(const char *prefix, const char *name, Error **errp)
    203 {
    204     int rv = -1;
    205 #ifdef CONFIG_MODULE_UPGRADES
    206     char *version_dir;
    207 #endif
    208     const char *search_dir;
    209     char *dirs[5];
    210     char *module_name;
    211     int i = 0, n_dirs = 0;
    212     bool export_symbols = false;
    213     static GHashTable *loaded_modules;
    214     const QemuModinfo *modinfo;
    215     const char **sl;
    216 
    217     if (!g_module_supported()) {
    218         error_setg(errp, "%s", "this platform does not support GLib modules");
    219         return -1;
    220     }
    221 
    222     if (!loaded_modules) {
    223         loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
    224     }
    225 
    226     /* allocate all resources managed by the out: label here */
    227     module_name = g_strdup_printf("%s%s", prefix, name);
    228 
    229     if (g_hash_table_contains(loaded_modules, module_name)) {
    230         g_free(module_name);
    231         return 2; /* module already loaded */
    232     }
    233     g_hash_table_add(loaded_modules, module_name);
    234 
    235     search_dir = getenv("QEMU_MODULE_DIR");
    236     if (search_dir != NULL) {
    237         dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
    238     }
    239     dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
    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
    247     assert(n_dirs <= ARRAY_SIZE(dirs));
    248 
    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             }
    279         }
    280     }
    281 
    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) {
    308         g_hash_table_remove(loaded_modules, module_name);
    309         g_free(module_name);
    310     }
    311     for (i = 0; i < n_dirs; i++) {
    312         g_free(dirs[i]);
    313     }
    314     return rv;
    315 }
    316 
    317 static bool module_loaded_qom_all;
    318 
    319 int module_load_qom(const char *type, Error **errp)
    320 {
    321     const QemuModinfo *modinfo;
    322     const char **sl;
    323     int rv = 0;
    324 
    325     if (!type) {
    326         error_setg(errp, "%s", "type is NULL");
    327         return -1;
    328     }
    329 
    330     trace_module_lookup_object_type(type);
    331     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
    332         if (!modinfo->objs) {
    333             continue;
    334         }
    335         if (!module_check_arch(modinfo)) {
    336             continue;
    337         }
    338         for (sl = modinfo->objs; *sl != NULL; sl++) {
    339             if (strcmp(type, *sl) == 0) {
    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                 }
    348             }
    349         }
    350     }
    351     return rv;
    352 }
    353 
    354 void module_load_qom_all(void)
    355 {
    356     const QemuModinfo *modinfo;
    357     Error *local_err = NULL;
    358 
    359     if (module_loaded_qom_all) {
    360         return;
    361     }
    362 
    363     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
    364         if (!modinfo->objs) {
    365             continue;
    366         }
    367         if (!module_check_arch(modinfo)) {
    368             continue;
    369         }
    370         if (module_load("", modinfo->name, &local_err) < 0) {
    371             error_report_err(local_err);
    372         }
    373     }
    374     module_loaded_qom_all = true;
    375 }
    376 
    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) {
    388                 Error *local_err = NULL;
    389                 if (module_load("", modinfo->name, &local_err) < 0) {
    390                     error_report_err(local_err);
    391                 }
    392             }
    393         }
    394     }
    395 }
    396 
    397 #else
    398 
    399 void module_allow_arch(const char *arch) {}
    400 void qemu_load_module_for_opts(const char *group) {}
    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; }
    403 void module_load_qom_all(void) {}
    404 
    405 #endif