xref: /openbmc/qemu/plugins/api.c (revision a5dd9ee060b0ad65239889a62e93a33276055981)
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