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 #ifdef CONFIG_MODULE_UPGRADES 23 #include "qemu-version.h" 24 #endif 25 26 typedef struct ModuleEntry 27 { 28 void (*init)(void); 29 QTAILQ_ENTRY(ModuleEntry) node; 30 module_init_type type; 31 } ModuleEntry; 32 33 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; 34 35 static ModuleTypeList init_type_list[MODULE_INIT_MAX]; 36 static bool modules_init_done[MODULE_INIT_MAX]; 37 38 static ModuleTypeList dso_init_list; 39 40 static void init_lists(void) 41 { 42 static int inited; 43 int i; 44 45 if (inited) { 46 return; 47 } 48 49 for (i = 0; i < MODULE_INIT_MAX; i++) { 50 QTAILQ_INIT(&init_type_list[i]); 51 } 52 53 QTAILQ_INIT(&dso_init_list); 54 55 inited = 1; 56 } 57 58 59 static ModuleTypeList *find_type(module_init_type type) 60 { 61 init_lists(); 62 63 return &init_type_list[type]; 64 } 65 66 void register_module_init(void (*fn)(void), module_init_type type) 67 { 68 ModuleEntry *e; 69 ModuleTypeList *l; 70 71 e = g_malloc0(sizeof(*e)); 72 e->init = fn; 73 e->type = type; 74 75 l = find_type(type); 76 77 QTAILQ_INSERT_TAIL(l, e, node); 78 } 79 80 void register_dso_module_init(void (*fn)(void), module_init_type type) 81 { 82 ModuleEntry *e; 83 84 init_lists(); 85 86 e = g_malloc0(sizeof(*e)); 87 e->init = fn; 88 e->type = type; 89 90 QTAILQ_INSERT_TAIL(&dso_init_list, e, node); 91 } 92 93 void module_call_init(module_init_type type) 94 { 95 ModuleTypeList *l; 96 ModuleEntry *e; 97 98 if (modules_init_done[type]) { 99 return; 100 } 101 102 l = find_type(type); 103 104 QTAILQ_FOREACH(e, l, node) { 105 e->init(); 106 } 107 108 modules_init_done[type] = true; 109 } 110 111 #ifdef CONFIG_MODULES 112 static int module_load_file(const char *fname) 113 { 114 GModule *g_module; 115 void (*sym)(void); 116 const char *dsosuf = CONFIG_HOST_DSOSUF; 117 int len = strlen(fname); 118 int suf_len = strlen(dsosuf); 119 ModuleEntry *e, *next; 120 int ret; 121 122 if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) { 123 /* wrong suffix */ 124 ret = -EINVAL; 125 goto out; 126 } 127 if (access(fname, F_OK)) { 128 ret = -ENOENT; 129 goto out; 130 } 131 132 assert(QTAILQ_EMPTY(&dso_init_list)); 133 134 g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); 135 if (!g_module) { 136 fprintf(stderr, "Failed to open module: %s\n", 137 g_module_error()); 138 ret = -EINVAL; 139 goto out; 140 } 141 if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) { 142 fprintf(stderr, "Failed to initialize module: %s\n", 143 fname); 144 /* Print some info if this is a QEMU module (but from different build), 145 * this will make debugging user problems easier. */ 146 if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) { 147 fprintf(stderr, 148 "Note: only modules from the same build can be loaded.\n"); 149 } 150 g_module_close(g_module); 151 ret = -EINVAL; 152 } else { 153 QTAILQ_FOREACH(e, &dso_init_list, node) { 154 e->init(); 155 register_module_init(e->init, e->type); 156 } 157 ret = 0; 158 } 159 160 QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) { 161 QTAILQ_REMOVE(&dso_init_list, e, node); 162 g_free(e); 163 } 164 out: 165 return ret; 166 } 167 #endif 168 169 bool module_load_one(const char *prefix, const char *lib_name) 170 { 171 bool success = false; 172 173 #ifdef CONFIG_MODULES 174 char *fname = NULL; 175 char *exec_dir; 176 #ifdef CONFIG_MODULE_UPGRADES 177 char *version_dir; 178 #endif 179 const char *search_dir; 180 char *dirs[5]; 181 char *module_name; 182 int i = 0, n_dirs = 0; 183 int ret; 184 static GHashTable *loaded_modules; 185 186 if (!g_module_supported()) { 187 fprintf(stderr, "Module is not supported by system.\n"); 188 return false; 189 } 190 191 if (!loaded_modules) { 192 loaded_modules = g_hash_table_new(g_str_hash, g_str_equal); 193 } 194 195 module_name = g_strdup_printf("%s%s", prefix, lib_name); 196 197 if (!g_hash_table_add(loaded_modules, module_name)) { 198 g_free(module_name); 199 return true; 200 } 201 202 exec_dir = qemu_get_exec_dir(); 203 search_dir = getenv("QEMU_MODULE_DIR"); 204 if (search_dir != NULL) { 205 dirs[n_dirs++] = g_strdup_printf("%s", search_dir); 206 } 207 dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); 208 dirs[n_dirs++] = g_strdup_printf("%s", exec_dir ? : ""); 209 210 #ifdef CONFIG_MODULE_UPGRADES 211 version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION), 212 G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~", 213 '_'); 214 dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir); 215 #endif 216 217 assert(n_dirs <= ARRAY_SIZE(dirs)); 218 219 g_free(exec_dir); 220 exec_dir = NULL; 221 222 for (i = 0; i < n_dirs; i++) { 223 fname = g_strdup_printf("%s/%s%s", 224 dirs[i], module_name, CONFIG_HOST_DSOSUF); 225 ret = module_load_file(fname); 226 g_free(fname); 227 fname = NULL; 228 /* Try loading until loaded a module file */ 229 if (!ret) { 230 success = true; 231 break; 232 } 233 } 234 235 if (!success) { 236 g_hash_table_remove(loaded_modules, module_name); 237 g_free(module_name); 238 } 239 240 for (i = 0; i < n_dirs; i++) { 241 g_free(dirs[i]); 242 } 243 244 #endif 245 return success; 246 } 247 248 /* 249 * Building devices and other qom objects modular is mostly useful in 250 * case they have dependencies to external shared libraries, so we can 251 * cut down the core qemu library dependencies. Which is the case for 252 * only a very few devices & objects. 253 * 254 * So with the expectation that this will be rather the exception than 255 * to rule and the list will not gain that many entries go with a 256 * simple manually maintained list for now. 257 */ 258 static struct { 259 const char *type; 260 const char *prefix; 261 const char *module; 262 } const qom_modules[] = { 263 { "ccid-card-passthru", "hw-", "usb-smartcard" }, 264 { "ccid-card-emulated", "hw-", "usb-smartcard" }, 265 { "usb-redir", "hw-", "usb-redirect" }, 266 { "qxl-vga", "hw-", "display-qxl" }, 267 { "qxl", "hw-", "display-qxl" }, 268 { "virtio-gpu-device", "hw-", "display-virtio-gpu" }, 269 { "vhost-user-gpu", "hw-", "display-virtio-gpu" }, 270 { "chardev-braille", "chardev-", "baum" }, 271 }; 272 273 static bool module_loaded_qom_all; 274 275 void module_load_qom_one(const char *type) 276 { 277 int i; 278 279 if (!type) { 280 return; 281 } 282 if (module_loaded_qom_all) { 283 return; 284 } 285 for (i = 0; i < ARRAY_SIZE(qom_modules); i++) { 286 if (strcmp(qom_modules[i].type, type) == 0) { 287 module_load_one(qom_modules[i].prefix, 288 qom_modules[i].module); 289 return; 290 } 291 } 292 } 293 294 void module_load_qom_all(void) 295 { 296 int i; 297 298 if (module_loaded_qom_all) { 299 return; 300 } 301 for (i = 0; i < ARRAY_SIZE(qom_modules); i++) { 302 if (i > 0 && (strcmp(qom_modules[i - 1].module, 303 qom_modules[i].module) == 0 && 304 strcmp(qom_modules[i - 1].prefix, 305 qom_modules[i].prefix) == 0)) { 306 /* one module implementing multiple types -> load only once */ 307 continue; 308 } 309 module_load_one(qom_modules[i].prefix, qom_modules[i].module); 310 } 311 module_loaded_qom_all = true; 312 } 313