xref: /openbmc/qemu/util/module.c (revision 9a48e367)
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 #include "qemu-common.h"
18 #ifdef CONFIG_MODULES
19 #include <gmodule.h>
20 #endif
21 #include "qemu/queue.h"
22 #include "qemu/module.h"
23 
24 typedef struct ModuleEntry
25 {
26     void (*init)(void);
27     QTAILQ_ENTRY(ModuleEntry) node;
28     module_init_type type;
29 } ModuleEntry;
30 
31 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
32 
33 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
34 
35 static ModuleTypeList dso_init_list;
36 
37 static void init_lists(void)
38 {
39     static int inited;
40     int i;
41 
42     if (inited) {
43         return;
44     }
45 
46     for (i = 0; i < MODULE_INIT_MAX; i++) {
47         QTAILQ_INIT(&init_type_list[i]);
48     }
49 
50     QTAILQ_INIT(&dso_init_list);
51 
52     inited = 1;
53 }
54 
55 
56 static ModuleTypeList *find_type(module_init_type type)
57 {
58     init_lists();
59 
60     return &init_type_list[type];
61 }
62 
63 void register_module_init(void (*fn)(void), module_init_type type)
64 {
65     ModuleEntry *e;
66     ModuleTypeList *l;
67 
68     e = g_malloc0(sizeof(*e));
69     e->init = fn;
70     e->type = type;
71 
72     l = find_type(type);
73 
74     QTAILQ_INSERT_TAIL(l, e, node);
75 }
76 
77 void register_dso_module_init(void (*fn)(void), module_init_type type)
78 {
79     ModuleEntry *e;
80 
81     init_lists();
82 
83     e = g_malloc0(sizeof(*e));
84     e->init = fn;
85     e->type = type;
86 
87     QTAILQ_INSERT_TAIL(&dso_init_list, e, node);
88 }
89 
90 static void module_load(module_init_type type);
91 
92 void module_call_init(module_init_type type)
93 {
94     ModuleTypeList *l;
95     ModuleEntry *e;
96 
97     module_load(type);
98     l = find_type(type);
99 
100     QTAILQ_FOREACH(e, l, node) {
101         e->init();
102     }
103 }
104 
105 #ifdef CONFIG_MODULES
106 static int module_load_file(const char *fname)
107 {
108     GModule *g_module;
109     void (*sym)(void);
110     const char *dsosuf = HOST_DSOSUF;
111     int len = strlen(fname);
112     int suf_len = strlen(dsosuf);
113     ModuleEntry *e, *next;
114     int ret;
115 
116     if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
117         /* wrong suffix */
118         ret = -EINVAL;
119         goto out;
120     }
121     if (access(fname, F_OK)) {
122         ret = -ENOENT;
123         goto out;
124     }
125 
126     assert(QTAILQ_EMPTY(&dso_init_list));
127 
128     g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
129     if (!g_module) {
130         fprintf(stderr, "Failed to open module: %s\n",
131                 g_module_error());
132         ret = -EINVAL;
133         goto out;
134     }
135     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
136         fprintf(stderr, "Failed to initialize module: %s\n",
137                 fname);
138         /* Print some info if this is a QEMU module (but from different build),
139          * this will make debugging user problems easier. */
140         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
141             fprintf(stderr,
142                     "Note: only modules from the same build can be loaded.\n");
143         }
144         g_module_close(g_module);
145         ret = -EINVAL;
146     } else {
147         QTAILQ_FOREACH(e, &dso_init_list, node) {
148             register_module_init(e->init, e->type);
149         }
150         ret = 0;
151     }
152 
153     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
154         QTAILQ_REMOVE(&dso_init_list, e, node);
155         g_free(e);
156     }
157 out:
158     return ret;
159 }
160 #endif
161 
162 static void module_load(module_init_type type)
163 {
164 #ifdef CONFIG_MODULES
165     char *fname = NULL;
166     const char **mp;
167     static const char *block_modules[] = {
168         CONFIG_BLOCK_MODULES
169     };
170     char *exec_dir;
171     char *dirs[3];
172     int i = 0;
173     int ret;
174 
175     if (!g_module_supported()) {
176         fprintf(stderr, "Module is not supported by system.\n");
177         return;
178     }
179 
180     switch (type) {
181     case MODULE_INIT_BLOCK:
182         mp = block_modules;
183         break;
184     default:
185         /* no other types have dynamic modules for now*/
186         return;
187     }
188 
189     exec_dir = qemu_get_exec_dir();
190     dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
191     dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
192     dirs[i++] = g_strdup_printf("%s", exec_dir ? : "");
193     assert(i == ARRAY_SIZE(dirs));
194     g_free(exec_dir);
195     exec_dir = NULL;
196 
197     for ( ; *mp; mp++) {
198         for (i = 0; i < ARRAY_SIZE(dirs); i++) {
199             fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF);
200             ret = module_load_file(fname);
201             g_free(fname);
202             fname = NULL;
203             /* Try loading until loaded a module file */
204             if (!ret) {
205                 break;
206             }
207         }
208     }
209 
210     for (i = 0; i < ARRAY_SIZE(dirs); i++) {
211         g_free(dirs[i]);
212     }
213 
214 #endif
215 }
216