root / util / module.c @ feature-archipelago
History | View | Annotate | Download (4.9 kB)
1 | 0bfe3ca5 | Anthony Liguori | /*
|
---|---|---|---|
2 | 0bfe3ca5 | Anthony Liguori | * QEMU Module Infrastructure
|
3 | 0bfe3ca5 | Anthony Liguori | *
|
4 | 0bfe3ca5 | Anthony Liguori | * Copyright IBM, Corp. 2009
|
5 | 0bfe3ca5 | Anthony Liguori | *
|
6 | 0bfe3ca5 | Anthony Liguori | * Authors:
|
7 | 0bfe3ca5 | Anthony Liguori | * Anthony Liguori <aliguori@us.ibm.com>
|
8 | 0bfe3ca5 | Anthony Liguori | *
|
9 | 0bfe3ca5 | Anthony Liguori | * This work is licensed under the terms of the GNU GPL, version 2. See
|
10 | 0bfe3ca5 | Anthony Liguori | * the COPYING file in the top-level directory.
|
11 | 0bfe3ca5 | Anthony Liguori | *
|
12 | 6b620ca3 | Paolo Bonzini | * Contributions after 2012-01-13 are licensed under the terms of the
|
13 | 6b620ca3 | Paolo Bonzini | * GNU GPL, version 2 or (at your option) any later version.
|
14 | 0bfe3ca5 | Anthony Liguori | */
|
15 | 0bfe3ca5 | Anthony Liguori | |
16 | e26110cf | Fam Zheng | #include <stdlib.h> |
17 | d844a7b6 | Fam Zheng | #include "qemu-common.h" |
18 | aa0d1f44 | Paolo Bonzini | #ifdef CONFIG_MODULES
|
19 | e26110cf | Fam Zheng | #include <gmodule.h> |
20 | aa0d1f44 | Paolo Bonzini | #endif
|
21 | 1de7afc9 | Paolo Bonzini | #include "qemu/queue.h" |
22 | 1de7afc9 | Paolo Bonzini | #include "qemu/module.h" |
23 | 0bfe3ca5 | Anthony Liguori | |
24 | 0bfe3ca5 | Anthony Liguori | typedef struct ModuleEntry |
25 | 0bfe3ca5 | Anthony Liguori | { |
26 | 0bfe3ca5 | Anthony Liguori | void (*init)(void); |
27 | 72cf2d4f | Blue Swirl | QTAILQ_ENTRY(ModuleEntry) node; |
28 | e26110cf | Fam Zheng | module_init_type type; |
29 | 0bfe3ca5 | Anthony Liguori | } ModuleEntry; |
30 | 0bfe3ca5 | Anthony Liguori | |
31 | 72cf2d4f | Blue Swirl | typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
32 | 0bfe3ca5 | Anthony Liguori | |
33 | f7897430 | Anthony Liguori | static ModuleTypeList init_type_list[MODULE_INIT_MAX];
|
34 | 0bfe3ca5 | Anthony Liguori | |
35 | e26110cf | Fam Zheng | static ModuleTypeList dso_init_list;
|
36 | e26110cf | Fam Zheng | |
37 | e26110cf | Fam Zheng | static void init_lists(void) |
38 | 0bfe3ca5 | Anthony Liguori | { |
39 | f7897430 | Anthony Liguori | static int inited; |
40 | f7897430 | Anthony Liguori | int i;
|
41 | 0bfe3ca5 | Anthony Liguori | |
42 | f7897430 | Anthony Liguori | if (inited) {
|
43 | f7897430 | Anthony Liguori | return;
|
44 | 0bfe3ca5 | Anthony Liguori | } |
45 | 0bfe3ca5 | Anthony Liguori | |
46 | f7897430 | Anthony Liguori | for (i = 0; i < MODULE_INIT_MAX; i++) { |
47 | 72cf2d4f | Blue Swirl | QTAILQ_INIT(&init_type_list[i]); |
48 | f7897430 | Anthony Liguori | } |
49 | 0bfe3ca5 | Anthony Liguori | |
50 | e26110cf | Fam Zheng | QTAILQ_INIT(&dso_init_list); |
51 | e26110cf | Fam Zheng | |
52 | f7897430 | Anthony Liguori | inited = 1;
|
53 | f7897430 | Anthony Liguori | } |
54 | 0bfe3ca5 | Anthony Liguori | |
55 | 0bfe3ca5 | Anthony Liguori | |
56 | f7897430 | Anthony Liguori | static ModuleTypeList *find_type(module_init_type type)
|
57 | f7897430 | Anthony Liguori | { |
58 | f7897430 | Anthony Liguori | ModuleTypeList *l; |
59 | 0bfe3ca5 | Anthony Liguori | |
60 | e26110cf | Fam Zheng | init_lists(); |
61 | f7897430 | Anthony Liguori | |
62 | f7897430 | Anthony Liguori | l = &init_type_list[type]; |
63 | 0bfe3ca5 | Anthony Liguori | |
64 | f7897430 | Anthony Liguori | return l;
|
65 | 0bfe3ca5 | Anthony Liguori | } |
66 | 0bfe3ca5 | Anthony Liguori | |
67 | 0bfe3ca5 | Anthony Liguori | void register_module_init(void (*fn)(void), module_init_type type) |
68 | 0bfe3ca5 | Anthony Liguori | { |
69 | 0bfe3ca5 | Anthony Liguori | ModuleEntry *e; |
70 | 0bfe3ca5 | Anthony Liguori | ModuleTypeList *l; |
71 | 0bfe3ca5 | Anthony Liguori | |
72 | 7267c094 | Anthony Liguori | e = g_malloc0(sizeof(*e));
|
73 | 0bfe3ca5 | Anthony Liguori | e->init = fn; |
74 | e26110cf | Fam Zheng | e->type = type; |
75 | 0bfe3ca5 | Anthony Liguori | |
76 | f7897430 | Anthony Liguori | l = find_type(type); |
77 | 0bfe3ca5 | Anthony Liguori | |
78 | 72cf2d4f | Blue Swirl | QTAILQ_INSERT_TAIL(l, e, node); |
79 | 0bfe3ca5 | Anthony Liguori | } |
80 | 0bfe3ca5 | Anthony Liguori | |
81 | e26110cf | Fam Zheng | void register_dso_module_init(void (*fn)(void), module_init_type type) |
82 | e26110cf | Fam Zheng | { |
83 | e26110cf | Fam Zheng | ModuleEntry *e; |
84 | e26110cf | Fam Zheng | |
85 | e26110cf | Fam Zheng | init_lists(); |
86 | e26110cf | Fam Zheng | |
87 | e26110cf | Fam Zheng | e = g_malloc0(sizeof(*e));
|
88 | e26110cf | Fam Zheng | e->init = fn; |
89 | e26110cf | Fam Zheng | e->type = type; |
90 | e26110cf | Fam Zheng | |
91 | e26110cf | Fam Zheng | QTAILQ_INSERT_TAIL(&dso_init_list, e, node); |
92 | e26110cf | Fam Zheng | } |
93 | e26110cf | Fam Zheng | |
94 | e26110cf | Fam Zheng | static void module_load(module_init_type type); |
95 | e26110cf | Fam Zheng | |
96 | 0bfe3ca5 | Anthony Liguori | void module_call_init(module_init_type type)
|
97 | 0bfe3ca5 | Anthony Liguori | { |
98 | 0bfe3ca5 | Anthony Liguori | ModuleTypeList *l; |
99 | 0bfe3ca5 | Anthony Liguori | ModuleEntry *e; |
100 | 0bfe3ca5 | Anthony Liguori | |
101 | e26110cf | Fam Zheng | module_load(type); |
102 | f7897430 | Anthony Liguori | l = find_type(type); |
103 | 0bfe3ca5 | Anthony Liguori | |
104 | 72cf2d4f | Blue Swirl | QTAILQ_FOREACH(e, l, node) { |
105 | 0bfe3ca5 | Anthony Liguori | e->init(); |
106 | 0bfe3ca5 | Anthony Liguori | } |
107 | 0bfe3ca5 | Anthony Liguori | } |
108 | e26110cf | Fam Zheng | |
109 | e26110cf | Fam Zheng | #ifdef CONFIG_MODULES
|
110 | e26110cf | Fam Zheng | static int module_load_file(const char *fname) |
111 | e26110cf | Fam Zheng | { |
112 | e26110cf | Fam Zheng | GModule *g_module; |
113 | e26110cf | Fam Zheng | void (*sym)(void); |
114 | e26110cf | Fam Zheng | const char *dsosuf = HOST_DSOSUF; |
115 | e26110cf | Fam Zheng | int len = strlen(fname);
|
116 | e26110cf | Fam Zheng | int suf_len = strlen(dsosuf);
|
117 | e26110cf | Fam Zheng | ModuleEntry *e, *next; |
118 | e26110cf | Fam Zheng | int ret;
|
119 | e26110cf | Fam Zheng | |
120 | e26110cf | Fam Zheng | if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
|
121 | e26110cf | Fam Zheng | /* wrong suffix */
|
122 | e26110cf | Fam Zheng | ret = -EINVAL; |
123 | e26110cf | Fam Zheng | goto out;
|
124 | e26110cf | Fam Zheng | } |
125 | e26110cf | Fam Zheng | if (access(fname, F_OK)) {
|
126 | e26110cf | Fam Zheng | ret = -ENOENT; |
127 | e26110cf | Fam Zheng | goto out;
|
128 | e26110cf | Fam Zheng | } |
129 | e26110cf | Fam Zheng | |
130 | e26110cf | Fam Zheng | assert(QTAILQ_EMPTY(&dso_init_list)); |
131 | e26110cf | Fam Zheng | |
132 | e26110cf | Fam Zheng | g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); |
133 | e26110cf | Fam Zheng | if (!g_module) {
|
134 | e26110cf | Fam Zheng | fprintf(stderr, "Failed to open module: %s\n",
|
135 | e26110cf | Fam Zheng | g_module_error()); |
136 | e26110cf | Fam Zheng | ret = -EINVAL; |
137 | e26110cf | Fam Zheng | goto out;
|
138 | e26110cf | Fam Zheng | } |
139 | e26110cf | Fam Zheng | if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
|
140 | e26110cf | Fam Zheng | fprintf(stderr, "Failed to initialize module: %s\n",
|
141 | e26110cf | Fam Zheng | fname); |
142 | e26110cf | Fam Zheng | /* Print some info if this is a QEMU module (but from different build),
|
143 | e26110cf | Fam Zheng | * this will make debugging user problems easier. */
|
144 | e26110cf | Fam Zheng | if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) { |
145 | e26110cf | Fam Zheng | fprintf(stderr, |
146 | e26110cf | Fam Zheng | "Note: only modules from the same build can be loaded.\n");
|
147 | e26110cf | Fam Zheng | } |
148 | e26110cf | Fam Zheng | g_module_close(g_module); |
149 | e26110cf | Fam Zheng | ret = -EINVAL; |
150 | e26110cf | Fam Zheng | } else {
|
151 | e26110cf | Fam Zheng | QTAILQ_FOREACH(e, &dso_init_list, node) { |
152 | e26110cf | Fam Zheng | register_module_init(e->init, e->type); |
153 | e26110cf | Fam Zheng | } |
154 | e26110cf | Fam Zheng | ret = 0;
|
155 | e26110cf | Fam Zheng | } |
156 | e26110cf | Fam Zheng | |
157 | e26110cf | Fam Zheng | QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) { |
158 | e26110cf | Fam Zheng | QTAILQ_REMOVE(&dso_init_list, e, node); |
159 | e26110cf | Fam Zheng | g_free(e); |
160 | e26110cf | Fam Zheng | } |
161 | e26110cf | Fam Zheng | out:
|
162 | e26110cf | Fam Zheng | return ret;
|
163 | e26110cf | Fam Zheng | } |
164 | e26110cf | Fam Zheng | #endif
|
165 | e26110cf | Fam Zheng | |
166 | e26110cf | Fam Zheng | void module_load(module_init_type type)
|
167 | e26110cf | Fam Zheng | { |
168 | e26110cf | Fam Zheng | #ifdef CONFIG_MODULES
|
169 | e26110cf | Fam Zheng | char *fname = NULL; |
170 | e26110cf | Fam Zheng | const char **mp; |
171 | e26110cf | Fam Zheng | static const char *block_modules[] = { |
172 | e26110cf | Fam Zheng | CONFIG_BLOCK_MODULES |
173 | e26110cf | Fam Zheng | }; |
174 | e26110cf | Fam Zheng | char *exec_dir;
|
175 | e26110cf | Fam Zheng | char *dirs[3]; |
176 | e26110cf | Fam Zheng | int i = 0; |
177 | e26110cf | Fam Zheng | int ret;
|
178 | e26110cf | Fam Zheng | |
179 | e26110cf | Fam Zheng | if (!g_module_supported()) {
|
180 | e26110cf | Fam Zheng | fprintf(stderr, "Module is not supported by system.\n");
|
181 | e26110cf | Fam Zheng | return;
|
182 | e26110cf | Fam Zheng | } |
183 | e26110cf | Fam Zheng | |
184 | e26110cf | Fam Zheng | switch (type) {
|
185 | e26110cf | Fam Zheng | case MODULE_INIT_BLOCK:
|
186 | e26110cf | Fam Zheng | mp = block_modules; |
187 | e26110cf | Fam Zheng | break;
|
188 | e26110cf | Fam Zheng | default:
|
189 | e26110cf | Fam Zheng | /* no other types have dynamic modules for now*/
|
190 | e26110cf | Fam Zheng | return;
|
191 | e26110cf | Fam Zheng | } |
192 | e26110cf | Fam Zheng | |
193 | e26110cf | Fam Zheng | exec_dir = qemu_get_exec_dir(); |
194 | e26110cf | Fam Zheng | dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
|
195 | e26110cf | Fam Zheng | dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : ""); |
196 | e26110cf | Fam Zheng | dirs[i++] = g_strdup_printf("%s", exec_dir ? : ""); |
197 | e26110cf | Fam Zheng | assert(i == ARRAY_SIZE(dirs)); |
198 | e26110cf | Fam Zheng | g_free(exec_dir); |
199 | e26110cf | Fam Zheng | exec_dir = NULL;
|
200 | e26110cf | Fam Zheng | |
201 | e26110cf | Fam Zheng | for ( ; *mp; mp++) {
|
202 | e26110cf | Fam Zheng | for (i = 0; i < ARRAY_SIZE(dirs); i++) { |
203 | e26110cf | Fam Zheng | fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF);
|
204 | e26110cf | Fam Zheng | ret = module_load_file(fname); |
205 | e26110cf | Fam Zheng | /* Try loading until loaded a module file */
|
206 | e26110cf | Fam Zheng | if (!ret) {
|
207 | e26110cf | Fam Zheng | break;
|
208 | e26110cf | Fam Zheng | } |
209 | e26110cf | Fam Zheng | g_free(fname); |
210 | e26110cf | Fam Zheng | fname = NULL;
|
211 | e26110cf | Fam Zheng | } |
212 | e26110cf | Fam Zheng | if (ret == -ENOENT) {
|
213 | e26110cf | Fam Zheng | fprintf(stderr, "Can't find module: %s\n", *mp);
|
214 | e26110cf | Fam Zheng | } |
215 | e26110cf | Fam Zheng | |
216 | e26110cf | Fam Zheng | g_free(fname); |
217 | e26110cf | Fam Zheng | } |
218 | e26110cf | Fam Zheng | |
219 | e26110cf | Fam Zheng | for (i = 0; i < ARRAY_SIZE(dirs); i++) { |
220 | e26110cf | Fam Zheng | g_free(dirs[i]); |
221 | e26110cf | Fam Zheng | } |
222 | e26110cf | Fam Zheng | |
223 | e26110cf | Fam Zheng | #endif
|
224 | e26110cf | Fam Zheng | } |