Statistics
| Branch: | Revision:

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
}