xref: /openbmc/qemu/plugins/loader.c (revision 1d76437b)
1 /*
2  * QEMU Plugin Core Loader Code
3  *
4  * This is the code responsible for loading and unloading the plugins.
5  * Aside from the basic housekeeping tasks we also need to ensure any
6  * generated code is flushed when we remove a plugin so we cannot end
7  * up calling and unloaded helper function.
8  *
9  * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
10  * Copyright (C) 2019, Linaro
11  *
12  * License: GNU GPL, version 2 or later.
13  *   See the COPYING file in the top-level directory.
14  *
15  * SPDX-License-Identifier: GPL-2.0-or-later
16  */
17 
18 #include "qemu/osdep.h"
19 #include "qemu/error-report.h"
20 #include "qemu/config-file.h"
21 #include "qapi/error.h"
22 #include "qemu/lockable.h"
23 #include "qemu/option.h"
24 #include "qemu/rcu_queue.h"
25 #include "qemu/qht.h"
26 #include "qemu/bitmap.h"
27 #include "qemu/xxhash.h"
28 #include "qemu/plugin.h"
29 #include "hw/core/cpu.h"
30 #include "exec/exec-all.h"
31 #ifndef CONFIG_USER_ONLY
32 #include "hw/boards.h"
33 #endif
34 #include "qemu/compiler.h"
35 
36 #include "plugin.h"
37 
38 /*
39  * For convenience we use a bitmap for plugin.mask, but really all we need is a
40  * u32, which is what we store in TranslationBlock.
41  */
42 QEMU_BUILD_BUG_ON(QEMU_PLUGIN_EV_MAX > 32);
43 
44 struct qemu_plugin_desc {
45     char *path;
46     char **argv;
47     QTAILQ_ENTRY(qemu_plugin_desc) entry;
48     int argc;
49 };
50 
51 struct qemu_plugin_parse_arg {
52     QemuPluginList *head;
53     struct qemu_plugin_desc *curr;
54 };
55 
56 QemuOptsList qemu_plugin_opts = {
57     .name = "plugin",
58     .implied_opt_name = "file",
59     .head = QTAILQ_HEAD_INITIALIZER(qemu_plugin_opts.head),
60     .desc = {
61         /* do our own parsing to support multiple plugins */
62         { /* end of list */ }
63     },
64 };
65 
66 typedef int (*qemu_plugin_install_func_t)(qemu_plugin_id_t, const qemu_info_t *, int, char **);
67 
68 extern struct qemu_plugin_state plugin;
69 
70 void qemu_plugin_add_dyn_cb_arr(GArray *arr)
71 {
72     uint32_t hash = qemu_xxhash2((uint64_t)(uintptr_t)arr);
73     bool inserted;
74 
75     inserted = qht_insert(&plugin.dyn_cb_arr_ht, arr, hash, NULL);
76     g_assert(inserted);
77 }
78 
79 static struct qemu_plugin_desc *plugin_find_desc(QemuPluginList *head,
80                                                  const char *path)
81 {
82     struct qemu_plugin_desc *desc;
83 
84     QTAILQ_FOREACH(desc, head, entry) {
85         if (strcmp(desc->path, path) == 0) {
86             return desc;
87         }
88     }
89     return NULL;
90 }
91 
92 static int plugin_add(void *opaque, const char *name, const char *value,
93                       Error **errp)
94 {
95     struct qemu_plugin_parse_arg *arg = opaque;
96     struct qemu_plugin_desc *p;
97 
98     if (strcmp(name, "file") == 0) {
99         if (strcmp(value, "") == 0) {
100             error_setg(errp, "requires a non-empty argument");
101             return 1;
102         }
103         p = plugin_find_desc(arg->head, value);
104         if (p == NULL) {
105             p = g_new0(struct qemu_plugin_desc, 1);
106             p->path = g_strdup(value);
107             QTAILQ_INSERT_TAIL(arg->head, p, entry);
108         }
109         arg->curr = p;
110     } else if (strcmp(name, "arg") == 0) {
111         if (arg->curr == NULL) {
112             error_setg(errp, "missing earlier '-plugin file=' option");
113             return 1;
114         }
115         p = arg->curr;
116         p->argc++;
117         p->argv = g_realloc_n(p->argv, p->argc, sizeof(char *));
118         p->argv[p->argc - 1] = g_strdup(value);
119     } else {
120         error_setg(errp, "-plugin: unexpected parameter '%s'; ignored", name);
121     }
122     return 0;
123 }
124 
125 void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head)
126 {
127     struct qemu_plugin_parse_arg arg;
128     QemuOpts *opts;
129 
130     opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optarg, true);
131     if (opts == NULL) {
132         exit(1);
133     }
134     arg.head = head;
135     arg.curr = NULL;
136     qemu_opt_foreach(opts, plugin_add, &arg, &error_fatal);
137     qemu_opts_del(opts);
138 }
139 
140 /*
141  * From: https://en.wikipedia.org/wiki/Xorshift
142  * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
143  * guaranteed to be >= INT_MAX).
144  */
145 static uint64_t xorshift64star(uint64_t x)
146 {
147     x ^= x >> 12; /* a */
148     x ^= x << 25; /* b */
149     x ^= x >> 27; /* c */
150     return x * UINT64_C(2685821657736338717);
151 }
152 
153 /*
154  * Disable CFI checks.
155  * The install and version functions have been loaded from an external library
156  * so we do not have type information
157  */
158 QEMU_DISABLE_CFI
159 static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, Error **errp)
160 {
161     qemu_plugin_install_func_t install;
162     struct qemu_plugin_ctx *ctx;
163     gpointer sym;
164     int rc;
165 
166     ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));
167     memset(ctx, 0, sizeof(*ctx));
168     ctx->desc = desc;
169 
170     ctx->handle = g_module_open(desc->path, G_MODULE_BIND_LOCAL);
171     if (ctx->handle == NULL) {
172         error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
173         goto err_dlopen;
174     }
175 
176     if (!g_module_symbol(ctx->handle, "qemu_plugin_install", &sym)) {
177         error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error());
178         goto err_symbol;
179     }
180     install = (qemu_plugin_install_func_t) sym;
181     /* symbol was found; it could be NULL though */
182     if (install == NULL) {
183         error_setg(errp, "Could not load plugin %s: qemu_plugin_install is NULL",
184                    desc->path);
185         goto err_symbol;
186     }
187 
188     if (!g_module_symbol(ctx->handle, "qemu_plugin_version", &sym)) {
189         error_setg(errp, "Could not load plugin %s: plugin does not declare API version %s",
190                    desc->path, g_module_error());
191         goto err_symbol;
192     } else {
193         int version = *(int *)sym;
194         if (version < QEMU_PLUGIN_MIN_VERSION) {
195             error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
196                        "this QEMU supports only a minimum version of %d",
197                        desc->path, version, QEMU_PLUGIN_MIN_VERSION);
198             goto err_symbol;
199         } else if (version > QEMU_PLUGIN_VERSION) {
200             error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but "
201                        "this QEMU supports only up to version %d",
202                        desc->path, version, QEMU_PLUGIN_VERSION);
203             goto err_symbol;
204         }
205     }
206 
207     qemu_rec_mutex_lock(&plugin.lock);
208 
209     /* find an unused random id with &ctx as the seed */
210     ctx->id = (uint64_t)(uintptr_t)ctx;
211     for (;;) {
212         void *existing;
213 
214         ctx->id = xorshift64star(ctx->id);
215         existing = g_hash_table_lookup(plugin.id_ht, &ctx->id);
216         if (likely(existing == NULL)) {
217             bool success;
218 
219             success = g_hash_table_insert(plugin.id_ht, &ctx->id, &ctx->id);
220             g_assert(success);
221             break;
222         }
223     }
224     QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);
225     ctx->installing = true;
226     rc = install(ctx->id, info, desc->argc, desc->argv);
227     ctx->installing = false;
228     if (rc) {
229         error_setg(errp, "Could not load plugin %s: qemu_plugin_install returned error code %d",
230                    desc->path, rc);
231         /*
232          * we cannot rely on the plugin doing its own cleanup, so
233          * call a full uninstall if the plugin did not yet call it.
234          */
235         if (!ctx->uninstalling) {
236             plugin_reset_uninstall(ctx->id, NULL, false);
237         }
238     }
239 
240     qemu_rec_mutex_unlock(&plugin.lock);
241     return rc;
242 
243  err_symbol:
244     g_module_close(ctx->handle);
245  err_dlopen:
246     qemu_vfree(ctx);
247     return 1;
248 }
249 
250 /* call after having removed @desc from the list */
251 static void plugin_desc_free(struct qemu_plugin_desc *desc)
252 {
253     int i;
254 
255     for (i = 0; i < desc->argc; i++) {
256         g_free(desc->argv[i]);
257     }
258     g_free(desc->argv);
259     g_free(desc->path);
260     g_free(desc);
261 }
262 
263 /**
264  * qemu_plugin_load_list - load a list of plugins
265  * @head: head of the list of descriptors of the plugins to be loaded
266  *
267  * Returns 0 if all plugins in the list are installed, !0 otherwise.
268  *
269  * Note: the descriptor of each successfully installed plugin is removed
270  * from the list given by @head.
271  */
272 int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
273 {
274     struct qemu_plugin_desc *desc, *next;
275     g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1);
276 
277     info->target_name = TARGET_NAME;
278     info->version.min = QEMU_PLUGIN_MIN_VERSION;
279     info->version.cur = QEMU_PLUGIN_VERSION;
280 #ifndef CONFIG_USER_ONLY
281     MachineState *ms = MACHINE(qdev_get_machine());
282     info->system_emulation = true;
283     info->system.smp_vcpus = ms->smp.cpus;
284     info->system.max_vcpus = ms->smp.max_cpus;
285 #else
286     info->system_emulation = false;
287 #endif
288 
289     QTAILQ_FOREACH_SAFE(desc, head, entry, next) {
290         int err;
291 
292         err = plugin_load(desc, info, errp);
293         if (err) {
294             return err;
295         }
296         QTAILQ_REMOVE(head, desc, entry);
297     }
298     return 0;
299 }
300 
301 struct qemu_plugin_reset_data {
302     struct qemu_plugin_ctx *ctx;
303     qemu_plugin_simple_cb_t cb;
304     bool reset;
305 };
306 
307 static void plugin_reset_destroy__locked(struct qemu_plugin_reset_data *data)
308 {
309     struct qemu_plugin_ctx *ctx = data->ctx;
310     enum qemu_plugin_event ev;
311     bool success;
312 
313     /*
314      * After updating the subscription lists there is no need to wait for an RCU
315      * grace period to elapse, because right now we either are in a "safe async"
316      * work environment (i.e. all vCPUs are asleep), or no vCPUs have yet been
317      * created.
318      */
319     for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
320         plugin_unregister_cb__locked(ctx, ev);
321     }
322 
323     if (data->reset) {
324         g_assert(ctx->resetting);
325         if (data->cb) {
326             data->cb(ctx->id);
327         }
328         ctx->resetting = false;
329         g_free(data);
330         return;
331     }
332 
333     g_assert(ctx->uninstalling);
334     /* we cannot dlclose if we are going to return to plugin code */
335     if (ctx->installing) {
336         error_report("Calling qemu_plugin_uninstall from the install function "
337                      "is a bug. Instead, return !0 from the install function.");
338         abort();
339     }
340 
341     success = g_hash_table_remove(plugin.id_ht, &ctx->id);
342     g_assert(success);
343     QTAILQ_REMOVE(&plugin.ctxs, ctx, entry);
344     if (data->cb) {
345         data->cb(ctx->id);
346     }
347     if (!g_module_close(ctx->handle)) {
348         warn_report("%s: %s", __func__, g_module_error());
349     }
350     plugin_desc_free(ctx->desc);
351     qemu_vfree(ctx);
352     g_free(data);
353 }
354 
355 static void plugin_reset_destroy(struct qemu_plugin_reset_data *data)
356 {
357     qemu_rec_mutex_lock(&plugin.lock);
358     plugin_reset_destroy__locked(data);
359     qemu_rec_mutex_lock(&plugin.lock);
360 }
361 
362 static void plugin_flush_destroy(CPUState *cpu, run_on_cpu_data arg)
363 {
364     struct qemu_plugin_reset_data *data = arg.host_ptr;
365 
366     g_assert(cpu_in_exclusive_context(cpu));
367     tb_flush(cpu);
368     plugin_reset_destroy(data);
369 }
370 
371 void plugin_reset_uninstall(qemu_plugin_id_t id,
372                             qemu_plugin_simple_cb_t cb,
373                             bool reset)
374 {
375     struct qemu_plugin_reset_data *data;
376     struct qemu_plugin_ctx *ctx;
377 
378     WITH_QEMU_LOCK_GUARD(&plugin.lock) {
379         ctx = plugin_id_to_ctx_locked(id);
380         if (ctx->uninstalling || (reset && ctx->resetting)) {
381             return;
382         }
383         ctx->resetting = reset;
384         ctx->uninstalling = !reset;
385     }
386 
387     data = g_new(struct qemu_plugin_reset_data, 1);
388     data->ctx = ctx;
389     data->cb = cb;
390     data->reset = reset;
391     /*
392      * Only flush the code cache if the vCPUs have been created. If so,
393      * current_cpu must be non-NULL.
394      */
395     if (current_cpu) {
396         async_safe_run_on_cpu(current_cpu, plugin_flush_destroy,
397                               RUN_ON_CPU_HOST_PTR(data));
398     } else {
399         /*
400          * If current_cpu isn't set, then we don't have yet any vCPU threads
401          * and we therefore can remove the callbacks synchronously.
402          */
403         plugin_reset_destroy(data);
404     }
405 }
406