15c5d69b0SAlex Bennée /*
25c5d69b0SAlex Bennée * QEMU Plugin API
35c5d69b0SAlex Bennée *
45c5d69b0SAlex Bennée * This provides the API that is available to the plugins to interact
55c5d69b0SAlex Bennée * with QEMU. We have to be careful not to expose internal details of
65c5d69b0SAlex Bennée * how QEMU works so we abstract out things like translation and
75c5d69b0SAlex Bennée * instructions to anonymous data types:
85c5d69b0SAlex Bennée *
95c5d69b0SAlex Bennée * qemu_plugin_tb
105c5d69b0SAlex Bennée * qemu_plugin_insn
118df5e27cSAlex Bennée * qemu_plugin_register
125c5d69b0SAlex Bennée *
135c5d69b0SAlex Bennée * Which can then be passed back into the API to do additional things.
145c5d69b0SAlex Bennée * As such all the public functions in here are exported in
155c5d69b0SAlex Bennée * qemu-plugin.h.
165c5d69b0SAlex Bennée *
175c5d69b0SAlex Bennée * The general life-cycle of a plugin is:
185c5d69b0SAlex Bennée *
195c5d69b0SAlex Bennée * - plugin is loaded, public qemu_plugin_install called
205c5d69b0SAlex Bennée * - the install func registers callbacks for events
215c5d69b0SAlex Bennée * - usually an atexit_cb is registered to dump info at the end
225c5d69b0SAlex Bennée * - when a registered event occurs the plugin is called
235c5d69b0SAlex Bennée * - some events pass additional info
245c5d69b0SAlex Bennée * - during translation the plugin can decide to instrument any
255c5d69b0SAlex Bennée * instruction
265c5d69b0SAlex Bennée * - when QEMU exits all the registered atexit callbacks are called
275c5d69b0SAlex Bennée *
285c5d69b0SAlex Bennée * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
295c5d69b0SAlex Bennée * Copyright (C) 2019, Linaro
305c5d69b0SAlex Bennée *
315c5d69b0SAlex Bennée * License: GNU GPL, version 2 or later.
325c5d69b0SAlex Bennée * See the COPYING file in the top-level directory.
335c5d69b0SAlex Bennée *
345c5d69b0SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later
355c5d69b0SAlex Bennée *
365c5d69b0SAlex Bennée */
375c5d69b0SAlex Bennée
385c5d69b0SAlex Bennée #include "qemu/osdep.h"
398df5e27cSAlex Bennée #include "qemu/main-loop.h"
405c5d69b0SAlex Bennée #include "qemu/plugin.h"
41cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
42847a65ddSAlex Bennée #include "qemu/timer.h"
435c5d69b0SAlex Bennée #include "tcg/tcg.h"
44cbafa236SAlex Bennée #include "exec/exec-all.h"
458df5e27cSAlex Bennée #include "exec/gdbstub.h"
4636bc99bcSRichard Henderson #include "exec/translator.h"
47cbafa236SAlex Bennée #include "disas/disas.h"
485c5d69b0SAlex Bennée #include "plugin.h"
495c5d69b0SAlex Bennée #ifndef CONFIG_USER_ONLY
5050803653SAlex Bennée #include "qapi/error.h"
5150803653SAlex Bennée #include "migration/blocker.h"
52155fb465SPhilippe Mathieu-Daudé #include "exec/ram_addr.h"
53235537faSAlex Bennée #include "qemu/plugin-memory.h"
545c5d69b0SAlex Bennée #include "hw/boards.h"
5591d40327SIvanov Arkady #else
5691d40327SIvanov Arkady #include "qemu.h"
5791d40327SIvanov Arkady #ifdef CONFIG_LINUX
5891d40327SIvanov Arkady #include "loader.h"
5991d40327SIvanov Arkady #endif
605c5d69b0SAlex Bennée #endif
615c5d69b0SAlex Bennée
625c5d69b0SAlex Bennée /* Uninstall and Reset handlers */
635c5d69b0SAlex Bennée
qemu_plugin_uninstall(qemu_plugin_id_t id,qemu_plugin_simple_cb_t cb)645c5d69b0SAlex Bennée void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
655c5d69b0SAlex Bennée {
665c5d69b0SAlex Bennée plugin_reset_uninstall(id, cb, false);
675c5d69b0SAlex Bennée }
685c5d69b0SAlex Bennée
qemu_plugin_reset(qemu_plugin_id_t id,qemu_plugin_simple_cb_t cb)695c5d69b0SAlex Bennée void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
705c5d69b0SAlex Bennée {
715c5d69b0SAlex Bennée plugin_reset_uninstall(id, cb, true);
725c5d69b0SAlex Bennée }
735c5d69b0SAlex Bennée
745c5d69b0SAlex Bennée /*
755c5d69b0SAlex Bennée * Plugin Register Functions
765c5d69b0SAlex Bennée *
775c5d69b0SAlex Bennée * This allows the plugin to register callbacks for various events
785c5d69b0SAlex Bennée * during the translation.
795c5d69b0SAlex Bennée */
805c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)815c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
825c5d69b0SAlex Bennée qemu_plugin_vcpu_simple_cb_t cb)
835c5d69b0SAlex Bennée {
845c5d69b0SAlex Bennée plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
855c5d69b0SAlex Bennée }
865c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_simple_cb_t cb)875c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
885c5d69b0SAlex Bennée qemu_plugin_vcpu_simple_cb_t cb)
895c5d69b0SAlex Bennée {
905c5d69b0SAlex Bennée plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
915c5d69b0SAlex Bennée }
925c5d69b0SAlex Bennée
tb_is_mem_only(void)93e5013259SRichard Henderson static bool tb_is_mem_only(void)
94e5013259SRichard Henderson {
95e5013259SRichard Henderson return tb_cflags(tcg_ctx->gen_tb) & CF_MEMI_ONLY;
96e5013259SRichard Henderson }
97e5013259SRichard Henderson
qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb * tb,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,void * udata)985c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
995c5d69b0SAlex Bennée qemu_plugin_vcpu_udata_cb_t cb,
1005c5d69b0SAlex Bennée enum qemu_plugin_cb_flags flags,
1015c5d69b0SAlex Bennée void *udata)
1025c5d69b0SAlex Bennée {
103e5013259SRichard Henderson if (!tb_is_mem_only()) {
104db409c01SRichard Henderson plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
1055c5d69b0SAlex Bennée }
106cfd405eaSAlex Bennée }
1075c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_tb_exec_cond_cb(struct qemu_plugin_tb * tb,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_cond cond,qemu_plugin_u64 entry,uint64_t imm,void * udata)1087de77d37SPierrick Bouvier void qemu_plugin_register_vcpu_tb_exec_cond_cb(struct qemu_plugin_tb *tb,
1097de77d37SPierrick Bouvier qemu_plugin_vcpu_udata_cb_t cb,
1107de77d37SPierrick Bouvier enum qemu_plugin_cb_flags flags,
1117de77d37SPierrick Bouvier enum qemu_plugin_cond cond,
1127de77d37SPierrick Bouvier qemu_plugin_u64 entry,
1137de77d37SPierrick Bouvier uint64_t imm,
1147de77d37SPierrick Bouvier void *udata)
1157de77d37SPierrick Bouvier {
1167de77d37SPierrick Bouvier if (cond == QEMU_PLUGIN_COND_NEVER || tb_is_mem_only()) {
1177de77d37SPierrick Bouvier return;
1187de77d37SPierrick Bouvier }
1197de77d37SPierrick Bouvier if (cond == QEMU_PLUGIN_COND_ALWAYS) {
1207de77d37SPierrick Bouvier qemu_plugin_register_vcpu_tb_exec_cb(tb, cb, flags, udata);
1217de77d37SPierrick Bouvier return;
1227de77d37SPierrick Bouvier }
1237de77d37SPierrick Bouvier plugin_register_dyn_cond_cb__udata(&tb->cbs, cb, flags,
1247de77d37SPierrick Bouvier cond, entry, imm, udata);
1257de77d37SPierrick Bouvier }
1267de77d37SPierrick Bouvier
qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(struct qemu_plugin_tb * tb,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)1270bcebabaSPierrick Bouvier void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
1280bcebabaSPierrick Bouvier struct qemu_plugin_tb *tb,
1290bcebabaSPierrick Bouvier enum qemu_plugin_op op,
1300bcebabaSPierrick Bouvier qemu_plugin_u64 entry,
1310bcebabaSPierrick Bouvier uint64_t imm)
1320bcebabaSPierrick Bouvier {
133e5013259SRichard Henderson if (!tb_is_mem_only()) {
134db409c01SRichard Henderson plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
1350bcebabaSPierrick Bouvier }
1360bcebabaSPierrick Bouvier }
1370bcebabaSPierrick Bouvier
qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn * insn,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,void * udata)1385c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
1395c5d69b0SAlex Bennée qemu_plugin_vcpu_udata_cb_t cb,
1405c5d69b0SAlex Bennée enum qemu_plugin_cb_flags flags,
1415c5d69b0SAlex Bennée void *udata)
1425c5d69b0SAlex Bennée {
143e5013259SRichard Henderson if (!tb_is_mem_only()) {
144db409c01SRichard Henderson plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
1455c5d69b0SAlex Bennée }
146cfd405eaSAlex Bennée }
1475c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_insn_exec_cond_cb(struct qemu_plugin_insn * insn,qemu_plugin_vcpu_udata_cb_t cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_cond cond,qemu_plugin_u64 entry,uint64_t imm,void * udata)1487de77d37SPierrick Bouvier void qemu_plugin_register_vcpu_insn_exec_cond_cb(
1497de77d37SPierrick Bouvier struct qemu_plugin_insn *insn,
1507de77d37SPierrick Bouvier qemu_plugin_vcpu_udata_cb_t cb,
1517de77d37SPierrick Bouvier enum qemu_plugin_cb_flags flags,
1527de77d37SPierrick Bouvier enum qemu_plugin_cond cond,
1537de77d37SPierrick Bouvier qemu_plugin_u64 entry,
1547de77d37SPierrick Bouvier uint64_t imm,
1557de77d37SPierrick Bouvier void *udata)
1567de77d37SPierrick Bouvier {
1577de77d37SPierrick Bouvier if (cond == QEMU_PLUGIN_COND_NEVER || tb_is_mem_only()) {
1587de77d37SPierrick Bouvier return;
1597de77d37SPierrick Bouvier }
1607de77d37SPierrick Bouvier if (cond == QEMU_PLUGIN_COND_ALWAYS) {
1617de77d37SPierrick Bouvier qemu_plugin_register_vcpu_insn_exec_cb(insn, cb, flags, udata);
1627de77d37SPierrick Bouvier return;
1637de77d37SPierrick Bouvier }
1647de77d37SPierrick Bouvier plugin_register_dyn_cond_cb__udata(&insn->insn_cbs, cb, flags,
1657de77d37SPierrick Bouvier cond, entry, imm, udata);
1667de77d37SPierrick Bouvier }
1677de77d37SPierrick Bouvier
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(struct qemu_plugin_insn * insn,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)1680bcebabaSPierrick Bouvier void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
1690bcebabaSPierrick Bouvier struct qemu_plugin_insn *insn,
1700bcebabaSPierrick Bouvier enum qemu_plugin_op op,
1710bcebabaSPierrick Bouvier qemu_plugin_u64 entry,
1720bcebabaSPierrick Bouvier uint64_t imm)
1730bcebabaSPierrick Bouvier {
174e5013259SRichard Henderson if (!tb_is_mem_only()) {
175db409c01SRichard Henderson plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
1760bcebabaSPierrick Bouvier }
1770bcebabaSPierrick Bouvier }
1780bcebabaSPierrick Bouvier
1795c5d69b0SAlex Bennée
180cfd405eaSAlex Bennée /*
181cfd405eaSAlex Bennée * We always plant memory instrumentation because they don't finalise until
182cfd405eaSAlex Bennée * after the operation has complete.
183cfd405eaSAlex Bennée */
qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn * insn,qemu_plugin_vcpu_mem_cb_t cb,enum qemu_plugin_cb_flags flags,enum qemu_plugin_mem_rw rw,void * udata)1845c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
1855c5d69b0SAlex Bennée qemu_plugin_vcpu_mem_cb_t cb,
1865c5d69b0SAlex Bennée enum qemu_plugin_cb_flags flags,
1875c5d69b0SAlex Bennée enum qemu_plugin_mem_rw rw,
1885c5d69b0SAlex Bennée void *udata)
1895c5d69b0SAlex Bennée {
190db409c01SRichard Henderson plugin_register_vcpu_mem_cb(&insn->mem_cbs, cb, flags, rw, udata);
1915c5d69b0SAlex Bennée }
1925c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_mem_inline_per_vcpu(struct qemu_plugin_insn * insn,enum qemu_plugin_mem_rw rw,enum qemu_plugin_op op,qemu_plugin_u64 entry,uint64_t imm)1930bcebabaSPierrick Bouvier void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
1940bcebabaSPierrick Bouvier struct qemu_plugin_insn *insn,
1950bcebabaSPierrick Bouvier enum qemu_plugin_mem_rw rw,
1960bcebabaSPierrick Bouvier enum qemu_plugin_op op,
1970bcebabaSPierrick Bouvier qemu_plugin_u64 entry,
1980bcebabaSPierrick Bouvier uint64_t imm)
1990bcebabaSPierrick Bouvier {
200db409c01SRichard Henderson plugin_register_inline_op_on_entry(&insn->mem_cbs, rw, op, entry, imm);
2010bcebabaSPierrick Bouvier }
2020bcebabaSPierrick Bouvier
qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_tb_trans_cb_t cb)2035c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
2045c5d69b0SAlex Bennée qemu_plugin_vcpu_tb_trans_cb_t cb)
2055c5d69b0SAlex Bennée {
2065c5d69b0SAlex Bennée plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
2075c5d69b0SAlex Bennée }
2085c5d69b0SAlex Bennée
qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_syscall_cb_t cb)2095c5d69b0SAlex Bennée void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
2105c5d69b0SAlex Bennée qemu_plugin_vcpu_syscall_cb_t cb)
2115c5d69b0SAlex Bennée {
2125c5d69b0SAlex Bennée plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
2135c5d69b0SAlex Bennée }
2145c5d69b0SAlex Bennée
2155c5d69b0SAlex Bennée void
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,qemu_plugin_vcpu_syscall_ret_cb_t cb)2165c5d69b0SAlex Bennée qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
2175c5d69b0SAlex Bennée qemu_plugin_vcpu_syscall_ret_cb_t cb)
2185c5d69b0SAlex Bennée {
2195c5d69b0SAlex Bennée plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
2205c5d69b0SAlex Bennée }
2215c5d69b0SAlex Bennée
2225c5d69b0SAlex Bennée /*
2235c5d69b0SAlex Bennée * Plugin Queries
2245c5d69b0SAlex Bennée *
2255c5d69b0SAlex Bennée * These are queries that the plugin can make to gauge information
2265c5d69b0SAlex Bennée * from our opaque data types. We do not want to leak internal details
2275c5d69b0SAlex Bennée * here just information useful to the plugin.
2285c5d69b0SAlex Bennée */
2295c5d69b0SAlex Bennée
2305c5d69b0SAlex Bennée /*
2315c5d69b0SAlex Bennée * Translation block information:
2325c5d69b0SAlex Bennée *
2335c5d69b0SAlex Bennée * A plugin can query the virtual address of the start of the block
2345c5d69b0SAlex Bennée * and the number of instructions in it. It can also get access to
2355c5d69b0SAlex Bennée * each translated instruction.
2365c5d69b0SAlex Bennée */
2375c5d69b0SAlex Bennée
qemu_plugin_tb_n_insns(const struct qemu_plugin_tb * tb)2385c5d69b0SAlex Bennée size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
2395c5d69b0SAlex Bennée {
2405c5d69b0SAlex Bennée return tb->n;
2415c5d69b0SAlex Bennée }
2425c5d69b0SAlex Bennée
qemu_plugin_tb_vaddr(const struct qemu_plugin_tb * tb)2435c5d69b0SAlex Bennée uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
2445c5d69b0SAlex Bennée {
245e763953aSRichard Henderson const DisasContextBase *db = tcg_ctx->plugin_db;
246e763953aSRichard Henderson return db->pc_first;
2475c5d69b0SAlex Bennée }
2485c5d69b0SAlex Bennée
2495c5d69b0SAlex Bennée struct qemu_plugin_insn *
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb * tb,size_t idx)2505c5d69b0SAlex Bennée qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
2515c5d69b0SAlex Bennée {
252cfd405eaSAlex Bennée struct qemu_plugin_insn *insn;
2535c5d69b0SAlex Bennée if (unlikely(idx >= tb->n)) {
2545c5d69b0SAlex Bennée return NULL;
2555c5d69b0SAlex Bennée }
256cfd405eaSAlex Bennée insn = g_ptr_array_index(tb->insns, idx);
257cfd405eaSAlex Bennée return insn;
2585c5d69b0SAlex Bennée }
2595c5d69b0SAlex Bennée
2605c5d69b0SAlex Bennée /*
2615c5d69b0SAlex Bennée * Instruction information
2625c5d69b0SAlex Bennée *
2635c5d69b0SAlex Bennée * These queries allow the plugin to retrieve information about each
2645c5d69b0SAlex Bennée * instruction being translated.
2655c5d69b0SAlex Bennée */
2665c5d69b0SAlex Bennée
qemu_plugin_insn_data(const struct qemu_plugin_insn * insn,void * dest,size_t len)2674abc8923SRichard Henderson size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
2684abc8923SRichard Henderson void *dest, size_t len)
2695c5d69b0SAlex Bennée {
27036bc99bcSRichard Henderson const DisasContextBase *db = tcg_ctx->plugin_db;
27136bc99bcSRichard Henderson
27236bc99bcSRichard Henderson len = MIN(len, insn->len);
27336bc99bcSRichard Henderson return translator_st(db, dest, insn->vaddr, len) ? len : 0;
2745c5d69b0SAlex Bennée }
2755c5d69b0SAlex Bennée
qemu_plugin_insn_size(const struct qemu_plugin_insn * insn)2765c5d69b0SAlex Bennée size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
2775c5d69b0SAlex Bennée {
27836bc99bcSRichard Henderson return insn->len;
2795c5d69b0SAlex Bennée }
2805c5d69b0SAlex Bennée
qemu_plugin_insn_vaddr(const struct qemu_plugin_insn * insn)2815c5d69b0SAlex Bennée uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
2825c5d69b0SAlex Bennée {
2835c5d69b0SAlex Bennée return insn->vaddr;
2845c5d69b0SAlex Bennée }
2855c5d69b0SAlex Bennée
qemu_plugin_insn_haddr(const struct qemu_plugin_insn * insn)2865c5d69b0SAlex Bennée void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
2875c5d69b0SAlex Bennée {
288d3ace105SRichard Henderson const DisasContextBase *db = tcg_ctx->plugin_db;
289d3ace105SRichard Henderson vaddr page0_last = db->pc_first | ~TARGET_PAGE_MASK;
290d3ace105SRichard Henderson
291d3ace105SRichard Henderson if (db->fake_insn) {
292d3ace105SRichard Henderson return NULL;
293d3ace105SRichard Henderson }
294d3ace105SRichard Henderson
295d3ace105SRichard Henderson /*
296d3ace105SRichard Henderson * ??? The return value is not intended for use of host memory,
297d3ace105SRichard Henderson * but as a proxy for address space and physical address.
298d3ace105SRichard Henderson * Thus we are only interested in the first byte and do not
299d3ace105SRichard Henderson * care about spanning pages.
300d3ace105SRichard Henderson */
301d3ace105SRichard Henderson if (insn->vaddr <= page0_last) {
302d3ace105SRichard Henderson if (db->host_addr[0] == NULL) {
303d3ace105SRichard Henderson return NULL;
304d3ace105SRichard Henderson }
305d3ace105SRichard Henderson return db->host_addr[0] + insn->vaddr - db->pc_first;
306d3ace105SRichard Henderson } else {
307d3ace105SRichard Henderson if (db->host_addr[1] == NULL) {
308d3ace105SRichard Henderson return NULL;
309d3ace105SRichard Henderson }
310d3ace105SRichard Henderson return db->host_addr[1] + insn->vaddr - (page0_last + 1);
311d3ace105SRichard Henderson }
3125c5d69b0SAlex Bennée }
3135c5d69b0SAlex Bennée
qemu_plugin_insn_disas(const struct qemu_plugin_insn * insn)314cbafa236SAlex Bennée char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
315cbafa236SAlex Bennée {
3164c833c60SRichard Henderson return plugin_disas(tcg_ctx->cpu, tcg_ctx->plugin_db,
3174c833c60SRichard Henderson insn->vaddr, insn->len);
318cbafa236SAlex Bennée }
319cbafa236SAlex Bennée
qemu_plugin_insn_symbol(const struct qemu_plugin_insn * insn)3207c4ab60fSAlex Bennée const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
3217c4ab60fSAlex Bennée {
3227c4ab60fSAlex Bennée const char *sym = lookup_symbol(insn->vaddr);
3237c4ab60fSAlex Bennée return sym[0] != 0 ? sym : NULL;
3247c4ab60fSAlex Bennée }
3257c4ab60fSAlex Bennée
3265c5d69b0SAlex Bennée /*
3275c5d69b0SAlex Bennée * The memory queries allow the plugin to query information about a
3285c5d69b0SAlex Bennée * memory access.
3295c5d69b0SAlex Bennée */
3305c5d69b0SAlex Bennée
qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)3315c5d69b0SAlex Bennée unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
3325c5d69b0SAlex Bennée {
33337aff087SRichard Henderson MemOp op = get_memop(info);
33437aff087SRichard Henderson return op & MO_SIZE;
3355c5d69b0SAlex Bennée }
3365c5d69b0SAlex Bennée
qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)3375c5d69b0SAlex Bennée bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
3385c5d69b0SAlex Bennée {
33937aff087SRichard Henderson MemOp op = get_memop(info);
34037aff087SRichard Henderson return op & MO_SIGN;
3415c5d69b0SAlex Bennée }
3425c5d69b0SAlex Bennée
qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)3435c5d69b0SAlex Bennée bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
3445c5d69b0SAlex Bennée {
34537aff087SRichard Henderson MemOp op = get_memop(info);
34637aff087SRichard Henderson return (op & MO_BSWAP) == MO_BE;
3475c5d69b0SAlex Bennée }
3485c5d69b0SAlex Bennée
qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)3495c5d69b0SAlex Bennée bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
3505c5d69b0SAlex Bennée {
35137aff087SRichard Henderson return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
3525c5d69b0SAlex Bennée }
3535c5d69b0SAlex Bennée
qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info)3549505f85eSPierrick Bouvier qemu_plugin_mem_value qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info)
3559505f85eSPierrick Bouvier {
3569505f85eSPierrick Bouvier uint64_t low = current_cpu->neg.plugin_mem_value_low;
3579505f85eSPierrick Bouvier qemu_plugin_mem_value value;
3589505f85eSPierrick Bouvier
3599505f85eSPierrick Bouvier switch (qemu_plugin_mem_size_shift(info)) {
3609505f85eSPierrick Bouvier case 0:
3619505f85eSPierrick Bouvier value.type = QEMU_PLUGIN_MEM_VALUE_U8;
3629505f85eSPierrick Bouvier value.data.u8 = (uint8_t)low;
3639505f85eSPierrick Bouvier break;
3649505f85eSPierrick Bouvier case 1:
3659505f85eSPierrick Bouvier value.type = QEMU_PLUGIN_MEM_VALUE_U16;
3669505f85eSPierrick Bouvier value.data.u16 = (uint16_t)low;
3679505f85eSPierrick Bouvier break;
3689505f85eSPierrick Bouvier case 2:
3699505f85eSPierrick Bouvier value.type = QEMU_PLUGIN_MEM_VALUE_U32;
3709505f85eSPierrick Bouvier value.data.u32 = (uint32_t)low;
3719505f85eSPierrick Bouvier break;
3729505f85eSPierrick Bouvier case 3:
3739505f85eSPierrick Bouvier value.type = QEMU_PLUGIN_MEM_VALUE_U64;
3749505f85eSPierrick Bouvier value.data.u64 = low;
3759505f85eSPierrick Bouvier break;
3769505f85eSPierrick Bouvier case 4:
3779505f85eSPierrick Bouvier value.type = QEMU_PLUGIN_MEM_VALUE_U128;
3789505f85eSPierrick Bouvier value.data.u128.low = low;
3799505f85eSPierrick Bouvier value.data.u128.high = current_cpu->neg.plugin_mem_value_high;
3809505f85eSPierrick Bouvier break;
3819505f85eSPierrick Bouvier default:
3829505f85eSPierrick Bouvier g_assert_not_reached();
3839505f85eSPierrick Bouvier }
3849505f85eSPierrick Bouvier return value;
3859505f85eSPierrick Bouvier }
3869505f85eSPierrick Bouvier
3875c5d69b0SAlex Bennée /*
3885c5d69b0SAlex Bennée * Virtual Memory queries
3895c5d69b0SAlex Bennée */
3905c5d69b0SAlex Bennée
391235537faSAlex Bennée #ifdef CONFIG_SOFTMMU
392235537faSAlex Bennée static __thread struct qemu_plugin_hwaddr hwaddr_info;
393a2b88169SYonggang Luo #endif
394235537faSAlex Bennée
qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,uint64_t vaddr)395235537faSAlex Bennée struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
396235537faSAlex Bennée uint64_t vaddr)
397235537faSAlex Bennée {
398a2b88169SYonggang Luo #ifdef CONFIG_SOFTMMU
399235537faSAlex Bennée CPUState *cpu = current_cpu;
40037aff087SRichard Henderson unsigned int mmu_idx = get_mmuidx(info);
40137aff087SRichard Henderson enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
40237aff087SRichard Henderson hwaddr_info.is_store = (rw & QEMU_PLUGIN_MEM_W) != 0;
403235537faSAlex Bennée
4045413c37fSRichard Henderson assert(mmu_idx < NB_MMU_MODES);
4055413c37fSRichard Henderson
406235537faSAlex Bennée if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
40737aff087SRichard Henderson hwaddr_info.is_store, &hwaddr_info)) {
408235537faSAlex Bennée error_report("invalid use of qemu_plugin_get_hwaddr");
409235537faSAlex Bennée return NULL;
410235537faSAlex Bennée }
411235537faSAlex Bennée
412235537faSAlex Bennée return &hwaddr_info;
413235537faSAlex Bennée #else
4145c5d69b0SAlex Bennée return NULL;
415235537faSAlex Bennée #endif
416a2b88169SYonggang Luo }
417235537faSAlex Bennée
qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr * haddr)418308e7549SPhilippe Mathieu-Daudé bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr)
419235537faSAlex Bennée {
420235537faSAlex Bennée #ifdef CONFIG_SOFTMMU
421308e7549SPhilippe Mathieu-Daudé return haddr->is_io;
422235537faSAlex Bennée #else
423235537faSAlex Bennée return false;
424235537faSAlex Bennée #endif
425235537faSAlex Bennée }
426235537faSAlex Bennée
qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr * haddr)427787148bfSAaron Lindsay uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr)
428235537faSAlex Bennée {
429235537faSAlex Bennée #ifdef CONFIG_SOFTMMU
430235537faSAlex Bennée if (haddr) {
431405c02d8SRichard Henderson return haddr->phys_addr;
432235537faSAlex Bennée }
433235537faSAlex Bennée #endif
434235537faSAlex Bennée return 0;
435235537faSAlex Bennée }
4365c5d69b0SAlex Bennée
qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr * h)437b853a79fSAlex Bennée const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h)
438b853a79fSAlex Bennée {
439b853a79fSAlex Bennée #ifdef CONFIG_SOFTMMU
440b853a79fSAlex Bennée if (h && h->is_io) {
441405c02d8SRichard Henderson MemoryRegion *mr = h->mr;
442405c02d8SRichard Henderson if (!mr->name) {
443405c02d8SRichard Henderson unsigned maddr = (uintptr_t)mr;
444405c02d8SRichard Henderson g_autofree char *temp = g_strdup_printf("anon%08x", maddr);
445b853a79fSAlex Bennée return g_intern_string(temp);
446b853a79fSAlex Bennée } else {
447405c02d8SRichard Henderson return g_intern_string(mr->name);
448b853a79fSAlex Bennée }
449b853a79fSAlex Bennée } else {
450b853a79fSAlex Bennée return g_intern_static_string("RAM");
451b853a79fSAlex Bennée }
452b853a79fSAlex Bennée #else
453b853a79fSAlex Bennée return g_intern_static_string("Invalid");
454b853a79fSAlex Bennée #endif
455b853a79fSAlex Bennée }
456b853a79fSAlex Bennée
qemu_plugin_num_vcpus(void)4574a448b14SPierrick Bouvier int qemu_plugin_num_vcpus(void)
4584a448b14SPierrick Bouvier {
4594a448b14SPierrick Bouvier return plugin_num_vcpus();
4604a448b14SPierrick Bouvier }
4614a448b14SPierrick Bouvier
4625c5d69b0SAlex Bennée /*
463ca76a669SAlex Bennée * Plugin output
464ca76a669SAlex Bennée */
qemu_plugin_outs(const char * string)465ca76a669SAlex Bennée void qemu_plugin_outs(const char *string)
466ca76a669SAlex Bennée {
467ca76a669SAlex Bennée qemu_log_mask(CPU_LOG_PLUGIN, "%s", string);
468ca76a669SAlex Bennée }
4696a9e8a08SMahmoud Mandour
qemu_plugin_bool_parse(const char * name,const char * value,bool * ret)4706a9e8a08SMahmoud Mandour bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret)
4716a9e8a08SMahmoud Mandour {
4726a9e8a08SMahmoud Mandour return name && value && qapi_bool_parse(name, value, ret, NULL);
4736a9e8a08SMahmoud Mandour }
47491d40327SIvanov Arkady
47591d40327SIvanov Arkady /*
47691d40327SIvanov Arkady * Binary path, start and end locations
47791d40327SIvanov Arkady */
qemu_plugin_path_to_binary(void)47891d40327SIvanov Arkady const char *qemu_plugin_path_to_binary(void)
47991d40327SIvanov Arkady {
48091d40327SIvanov Arkady char *path = NULL;
48191d40327SIvanov Arkady #ifdef CONFIG_USER_ONLY
482e4e5cb4aSIlya Leoshkevich TaskState *ts = get_task_state(current_cpu);
48391d40327SIvanov Arkady path = g_strdup(ts->bprm->filename);
48491d40327SIvanov Arkady #endif
48591d40327SIvanov Arkady return path;
48691d40327SIvanov Arkady }
48791d40327SIvanov Arkady
qemu_plugin_start_code(void)48891d40327SIvanov Arkady uint64_t qemu_plugin_start_code(void)
48991d40327SIvanov Arkady {
49091d40327SIvanov Arkady uint64_t start = 0;
49191d40327SIvanov Arkady #ifdef CONFIG_USER_ONLY
492e4e5cb4aSIlya Leoshkevich TaskState *ts = get_task_state(current_cpu);
49391d40327SIvanov Arkady start = ts->info->start_code;
49491d40327SIvanov Arkady #endif
49591d40327SIvanov Arkady return start;
49691d40327SIvanov Arkady }
49791d40327SIvanov Arkady
qemu_plugin_end_code(void)49891d40327SIvanov Arkady uint64_t qemu_plugin_end_code(void)
49991d40327SIvanov Arkady {
50091d40327SIvanov Arkady uint64_t end = 0;
50191d40327SIvanov Arkady #ifdef CONFIG_USER_ONLY
502e4e5cb4aSIlya Leoshkevich TaskState *ts = get_task_state(current_cpu);
50391d40327SIvanov Arkady end = ts->info->end_code;
50491d40327SIvanov Arkady #endif
50591d40327SIvanov Arkady return end;
50691d40327SIvanov Arkady }
50791d40327SIvanov Arkady
qemu_plugin_entry_code(void)50891d40327SIvanov Arkady uint64_t qemu_plugin_entry_code(void)
50991d40327SIvanov Arkady {
51091d40327SIvanov Arkady uint64_t entry = 0;
51191d40327SIvanov Arkady #ifdef CONFIG_USER_ONLY
512e4e5cb4aSIlya Leoshkevich TaskState *ts = get_task_state(current_cpu);
51391d40327SIvanov Arkady entry = ts->info->entry;
51491d40327SIvanov Arkady #endif
51591d40327SIvanov Arkady return entry;
51691d40327SIvanov Arkady }
5178df5e27cSAlex Bennée
5188df5e27cSAlex Bennée /*
5198df5e27cSAlex Bennée * Create register handles.
5208df5e27cSAlex Bennée *
5218df5e27cSAlex Bennée * We need to create a handle for each register so the plugin
5228df5e27cSAlex Bennée * infrastructure can call gdbstub to read a register. They are
5238df5e27cSAlex Bennée * currently just a pointer encapsulation of the gdb_reg but in
5248df5e27cSAlex Bennée * future may hold internal plugin state so its important plugin
5258df5e27cSAlex Bennée * authors are not tempted to treat them as numbers.
5268df5e27cSAlex Bennée *
5278df5e27cSAlex Bennée * We also construct a result array with those handles and some
5288df5e27cSAlex Bennée * ancillary data the plugin might find useful.
5298df5e27cSAlex Bennée */
5308df5e27cSAlex Bennée
create_register_handles(GArray * gdbstub_regs)5318df5e27cSAlex Bennée static GArray *create_register_handles(GArray *gdbstub_regs)
5328df5e27cSAlex Bennée {
5338df5e27cSAlex Bennée GArray *find_data = g_array_new(true, true,
5348df5e27cSAlex Bennée sizeof(qemu_plugin_reg_descriptor));
5358df5e27cSAlex Bennée
5368df5e27cSAlex Bennée for (int i = 0; i < gdbstub_regs->len; i++) {
5378df5e27cSAlex Bennée GDBRegDesc *grd = &g_array_index(gdbstub_regs, GDBRegDesc, i);
5388df5e27cSAlex Bennée qemu_plugin_reg_descriptor desc;
5398df5e27cSAlex Bennée
5408df5e27cSAlex Bennée /* skip "un-named" regs */
5418df5e27cSAlex Bennée if (!grd->name) {
5428df5e27cSAlex Bennée continue;
5438df5e27cSAlex Bennée }
5448df5e27cSAlex Bennée
5458df5e27cSAlex Bennée /* Create a record for the plugin */
546ad59d5caSAkihiko Odaki desc.handle = GINT_TO_POINTER(grd->gdb_reg + 1);
5478df5e27cSAlex Bennée desc.name = g_intern_string(grd->name);
5488df5e27cSAlex Bennée desc.feature = g_intern_string(grd->feature_name);
5498df5e27cSAlex Bennée g_array_append_val(find_data, desc);
5508df5e27cSAlex Bennée }
5518df5e27cSAlex Bennée
5528df5e27cSAlex Bennée return find_data;
5538df5e27cSAlex Bennée }
5548df5e27cSAlex Bennée
qemu_plugin_get_registers(void)5558df5e27cSAlex Bennée GArray *qemu_plugin_get_registers(void)
5568df5e27cSAlex Bennée {
5578df5e27cSAlex Bennée g_assert(current_cpu);
5588df5e27cSAlex Bennée
5598df5e27cSAlex Bennée g_autoptr(GArray) regs = gdb_get_register_list(current_cpu);
5608df5e27cSAlex Bennée return create_register_handles(regs);
5618df5e27cSAlex Bennée }
5628df5e27cSAlex Bennée
qemu_plugin_read_memory_vaddr(vaddr addr,GByteArray * data,size_t len)563*595cd9ceSRowan Hart bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
564*595cd9ceSRowan Hart {
565*595cd9ceSRowan Hart g_assert(current_cpu);
566*595cd9ceSRowan Hart
567*595cd9ceSRowan Hart if (len == 0) {
568*595cd9ceSRowan Hart return false;
569*595cd9ceSRowan Hart }
570*595cd9ceSRowan Hart
571*595cd9ceSRowan Hart g_byte_array_set_size(data, len);
572*595cd9ceSRowan Hart
573*595cd9ceSRowan Hart int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
574*595cd9ceSRowan Hart data->len, false);
575*595cd9ceSRowan Hart
576*595cd9ceSRowan Hart if (result < 0) {
577*595cd9ceSRowan Hart return false;
578*595cd9ceSRowan Hart }
579*595cd9ceSRowan Hart
580*595cd9ceSRowan Hart return true;
581*595cd9ceSRowan Hart }
582*595cd9ceSRowan Hart
qemu_plugin_read_register(struct qemu_plugin_register * reg,GByteArray * buf)5838df5e27cSAlex Bennée int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
5848df5e27cSAlex Bennée {
5858df5e27cSAlex Bennée g_assert(current_cpu);
5868df5e27cSAlex Bennée
587ad59d5caSAkihiko Odaki return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
5888df5e27cSAlex Bennée }
589a3c2cf0bSPierrick Bouvier
qemu_plugin_scoreboard_new(size_t element_size)590a3c2cf0bSPierrick Bouvier struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
591a3c2cf0bSPierrick Bouvier {
592a3c2cf0bSPierrick Bouvier return plugin_scoreboard_new(element_size);
593a3c2cf0bSPierrick Bouvier }
594a3c2cf0bSPierrick Bouvier
qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard * score)595a3c2cf0bSPierrick Bouvier void qemu_plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
596a3c2cf0bSPierrick Bouvier {
597a3c2cf0bSPierrick Bouvier plugin_scoreboard_free(score);
598a3c2cf0bSPierrick Bouvier }
599a3c2cf0bSPierrick Bouvier
qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard * score,unsigned int vcpu_index)600a3c2cf0bSPierrick Bouvier void *qemu_plugin_scoreboard_find(struct qemu_plugin_scoreboard *score,
601a3c2cf0bSPierrick Bouvier unsigned int vcpu_index)
602a3c2cf0bSPierrick Bouvier {
603a3c2cf0bSPierrick Bouvier g_assert(vcpu_index < qemu_plugin_num_vcpus());
604a3c2cf0bSPierrick Bouvier /* we can't use g_array_index since entry size is not statically known */
605a3c2cf0bSPierrick Bouvier char *base_ptr = score->data->data;
606a3c2cf0bSPierrick Bouvier return base_ptr + vcpu_index * g_array_get_element_size(score->data);
607a3c2cf0bSPierrick Bouvier }
6088042e2eaSPierrick Bouvier
plugin_u64_address(qemu_plugin_u64 entry,unsigned int vcpu_index)6098042e2eaSPierrick Bouvier static uint64_t *plugin_u64_address(qemu_plugin_u64 entry,
6108042e2eaSPierrick Bouvier unsigned int vcpu_index)
6118042e2eaSPierrick Bouvier {
6128042e2eaSPierrick Bouvier char *ptr = qemu_plugin_scoreboard_find(entry.score, vcpu_index);
6138042e2eaSPierrick Bouvier return (uint64_t *)(ptr + entry.offset);
6148042e2eaSPierrick Bouvier }
6158042e2eaSPierrick Bouvier
qemu_plugin_u64_add(qemu_plugin_u64 entry,unsigned int vcpu_index,uint64_t added)6168042e2eaSPierrick Bouvier void qemu_plugin_u64_add(qemu_plugin_u64 entry, unsigned int vcpu_index,
6178042e2eaSPierrick Bouvier uint64_t added)
6188042e2eaSPierrick Bouvier {
6198042e2eaSPierrick Bouvier *plugin_u64_address(entry, vcpu_index) += added;
6208042e2eaSPierrick Bouvier }
6218042e2eaSPierrick Bouvier
qemu_plugin_u64_get(qemu_plugin_u64 entry,unsigned int vcpu_index)6228042e2eaSPierrick Bouvier uint64_t qemu_plugin_u64_get(qemu_plugin_u64 entry,
6238042e2eaSPierrick Bouvier unsigned int vcpu_index)
6248042e2eaSPierrick Bouvier {
6258042e2eaSPierrick Bouvier return *plugin_u64_address(entry, vcpu_index);
6268042e2eaSPierrick Bouvier }
6278042e2eaSPierrick Bouvier
qemu_plugin_u64_set(qemu_plugin_u64 entry,unsigned int vcpu_index,uint64_t val)6288042e2eaSPierrick Bouvier void qemu_plugin_u64_set(qemu_plugin_u64 entry, unsigned int vcpu_index,
6298042e2eaSPierrick Bouvier uint64_t val)
6308042e2eaSPierrick Bouvier {
6318042e2eaSPierrick Bouvier *plugin_u64_address(entry, vcpu_index) = val;
6328042e2eaSPierrick Bouvier }
6338042e2eaSPierrick Bouvier
qemu_plugin_u64_sum(qemu_plugin_u64 entry)6348042e2eaSPierrick Bouvier uint64_t qemu_plugin_u64_sum(qemu_plugin_u64 entry)
6358042e2eaSPierrick Bouvier {
6368042e2eaSPierrick Bouvier uint64_t total = 0;
6378042e2eaSPierrick Bouvier for (int i = 0, n = qemu_plugin_num_vcpus(); i < n; ++i) {
6388042e2eaSPierrick Bouvier total += qemu_plugin_u64_get(entry, i);
6398042e2eaSPierrick Bouvier }
6408042e2eaSPierrick Bouvier return total;
6418042e2eaSPierrick Bouvier }
642847a65ddSAlex Bennée
643847a65ddSAlex Bennée /*
644847a65ddSAlex Bennée * Time control
645847a65ddSAlex Bennée */
646847a65ddSAlex Bennée static bool has_control;
64750803653SAlex Bennée #ifdef CONFIG_SOFTMMU
64850803653SAlex Bennée static Error *migration_blocker;
64950803653SAlex Bennée #endif
650847a65ddSAlex Bennée
qemu_plugin_request_time_control(void)651847a65ddSAlex Bennée const void *qemu_plugin_request_time_control(void)
652847a65ddSAlex Bennée {
653847a65ddSAlex Bennée if (!has_control) {
654847a65ddSAlex Bennée has_control = true;
65550803653SAlex Bennée #ifdef CONFIG_SOFTMMU
65650803653SAlex Bennée error_setg(&migration_blocker,
65750803653SAlex Bennée "TCG plugin time control does not support migration");
65850803653SAlex Bennée migrate_add_blocker(&migration_blocker, NULL);
65950803653SAlex Bennée #endif
660847a65ddSAlex Bennée return &has_control;
661847a65ddSAlex Bennée }
662847a65ddSAlex Bennée return NULL;
663847a65ddSAlex Bennée }
664847a65ddSAlex Bennée
665847a65ddSAlex Bennée #ifdef CONFIG_SOFTMMU
advance_virtual_time__async(CPUState * cpu,run_on_cpu_data data)666847a65ddSAlex Bennée static void advance_virtual_time__async(CPUState *cpu, run_on_cpu_data data)
667847a65ddSAlex Bennée {
668847a65ddSAlex Bennée int64_t new_time = data.host_ulong;
669847a65ddSAlex Bennée qemu_clock_advance_virtual_time(new_time);
670847a65ddSAlex Bennée }
671847a65ddSAlex Bennée #endif
672847a65ddSAlex Bennée
qemu_plugin_update_ns(const void * handle,int64_t new_time)673847a65ddSAlex Bennée void qemu_plugin_update_ns(const void *handle, int64_t new_time)
674847a65ddSAlex Bennée {
675847a65ddSAlex Bennée #ifdef CONFIG_SOFTMMU
676847a65ddSAlex Bennée if (handle == &has_control) {
677847a65ddSAlex Bennée /* Need to execute out of cpu_exec, so bql can be locked. */
678847a65ddSAlex Bennée async_run_on_cpu(current_cpu,
679847a65ddSAlex Bennée advance_virtual_time__async,
680847a65ddSAlex Bennée RUN_ON_CPU_HOST_ULONG(new_time));
681847a65ddSAlex Bennée }
682847a65ddSAlex Bennée #endif
683847a65ddSAlex Bennée }
684