cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

plugin.h (7885B)


      1/*
      2 * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
      3 *
      4 * License: GNU GPL, version 2 or later.
      5 *   See the COPYING file in the top-level directory.
      6 */
      7#ifndef QEMU_PLUGIN_H
      8#define QEMU_PLUGIN_H
      9
     10#include "qemu/config-file.h"
     11#include "qemu/qemu-plugin.h"
     12#include "qemu/error-report.h"
     13#include "qemu/queue.h"
     14#include "qemu/option.h"
     15#include "exec/memopidx.h"
     16
     17/*
     18 * Events that plugins can subscribe to.
     19 */
     20enum qemu_plugin_event {
     21    QEMU_PLUGIN_EV_VCPU_INIT,
     22    QEMU_PLUGIN_EV_VCPU_EXIT,
     23    QEMU_PLUGIN_EV_VCPU_TB_TRANS,
     24    QEMU_PLUGIN_EV_VCPU_IDLE,
     25    QEMU_PLUGIN_EV_VCPU_RESUME,
     26    QEMU_PLUGIN_EV_VCPU_SYSCALL,
     27    QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
     28    QEMU_PLUGIN_EV_FLUSH,
     29    QEMU_PLUGIN_EV_ATEXIT,
     30    QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
     31};
     32
     33/*
     34 * Option parsing/processing.
     35 * Note that we can load an arbitrary number of plugins.
     36 */
     37struct qemu_plugin_desc;
     38typedef QTAILQ_HEAD(, qemu_plugin_desc) QemuPluginList;
     39
     40/*
     41 * Construct a qemu_plugin_meminfo_t.
     42 */
     43static inline qemu_plugin_meminfo_t
     44make_plugin_meminfo(MemOpIdx oi, enum qemu_plugin_mem_rw rw)
     45{
     46    return oi | (rw << 16);
     47}
     48
     49/*
     50 * Extract the memory operation direction from a qemu_plugin_meminfo_t.
     51 * Other portions may be extracted via get_memop and get_mmuidx.
     52 */
     53static inline enum qemu_plugin_mem_rw
     54get_plugin_meminfo_rw(qemu_plugin_meminfo_t i)
     55{
     56    return i >> 16;
     57}
     58
     59#ifdef CONFIG_PLUGIN
     60extern QemuOptsList qemu_plugin_opts;
     61
     62static inline void qemu_plugin_add_opts(void)
     63{
     64    qemu_add_opts(&qemu_plugin_opts);
     65}
     66
     67void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head);
     68int qemu_plugin_load_list(QemuPluginList *head, Error **errp);
     69
     70union qemu_plugin_cb_sig {
     71    qemu_plugin_simple_cb_t          simple;
     72    qemu_plugin_udata_cb_t           udata;
     73    qemu_plugin_vcpu_simple_cb_t     vcpu_simple;
     74    qemu_plugin_vcpu_udata_cb_t      vcpu_udata;
     75    qemu_plugin_vcpu_tb_trans_cb_t   vcpu_tb_trans;
     76    qemu_plugin_vcpu_mem_cb_t        vcpu_mem;
     77    qemu_plugin_vcpu_syscall_cb_t    vcpu_syscall;
     78    qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret;
     79    void *generic;
     80};
     81
     82enum plugin_dyn_cb_type {
     83    PLUGIN_CB_INSN,
     84    PLUGIN_CB_MEM,
     85    PLUGIN_N_CB_TYPES,
     86};
     87
     88enum plugin_dyn_cb_subtype {
     89    PLUGIN_CB_REGULAR,
     90    PLUGIN_CB_INLINE,
     91    PLUGIN_N_CB_SUBTYPES,
     92};
     93
     94/*
     95 * A dynamic callback has an insertion point that is determined at run-time.
     96 * Usually the insertion point is somewhere in the code cache; think for
     97 * instance of a callback to be called upon the execution of a particular TB.
     98 */
     99struct qemu_plugin_dyn_cb {
    100    union qemu_plugin_cb_sig f;
    101    void *userp;
    102    enum plugin_dyn_cb_subtype type;
    103    /* @rw applies to mem callbacks only (both regular and inline) */
    104    enum qemu_plugin_mem_rw rw;
    105    /* fields specific to each dyn_cb type go here */
    106    union {
    107        struct {
    108            enum qemu_plugin_op op;
    109            uint64_t imm;
    110        } inline_insn;
    111    };
    112};
    113
    114/* Internal context for instrumenting an instruction */
    115struct qemu_plugin_insn {
    116    GByteArray *data;
    117    uint64_t vaddr;
    118    void *haddr;
    119    GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
    120    bool calls_helpers;
    121    bool mem_helper;
    122    bool mem_only;
    123};
    124
    125/*
    126 * qemu_plugin_insn allocate and cleanup functions. We don't expect to
    127 * cleanup many of these structures. They are reused for each fresh
    128 * translation.
    129 */
    130
    131static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
    132{
    133    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
    134    g_byte_array_free(insn->data, true);
    135}
    136
    137static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
    138{
    139    int i, j;
    140    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
    141    insn->data = g_byte_array_sized_new(4);
    142
    143    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
    144        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
    145            insn->cbs[i][j] = g_array_new(false, false,
    146                                          sizeof(struct qemu_plugin_dyn_cb));
    147        }
    148    }
    149    return insn;
    150}
    151
    152/* Internal context for this TranslationBlock */
    153struct qemu_plugin_tb {
    154    GPtrArray *insns;
    155    size_t n;
    156    uint64_t vaddr;
    157    uint64_t vaddr2;
    158    void *haddr1;
    159    void *haddr2;
    160    bool mem_only;
    161    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
    162};
    163
    164/**
    165 * qemu_plugin_tb_insn_get(): get next plugin record for translation.
    166 *
    167 */
    168static inline
    169struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb)
    170{
    171    struct qemu_plugin_insn *insn;
    172    int i, j;
    173
    174    if (unlikely(tb->n == tb->insns->len)) {
    175        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
    176        g_ptr_array_add(tb->insns, new_insn);
    177    }
    178    insn = g_ptr_array_index(tb->insns, tb->n++);
    179    g_byte_array_set_size(insn->data, 0);
    180    insn->calls_helpers = false;
    181    insn->mem_helper = false;
    182
    183    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
    184        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
    185            g_array_set_size(insn->cbs[i][j], 0);
    186        }
    187    }
    188
    189    return insn;
    190}
    191
    192void qemu_plugin_vcpu_init_hook(CPUState *cpu);
    193void qemu_plugin_vcpu_exit_hook(CPUState *cpu);
    194void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
    195void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
    196void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
    197void
    198qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
    199                         uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
    200                         uint64_t a6, uint64_t a7, uint64_t a8);
    201void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret);
    202
    203void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
    204                             MemOpIdx oi, enum qemu_plugin_mem_rw rw);
    205
    206void qemu_plugin_flush_cb(void);
    207
    208void qemu_plugin_atexit_cb(void);
    209
    210void qemu_plugin_add_dyn_cb_arr(GArray *arr);
    211
    212void qemu_plugin_disable_mem_helpers(CPUState *cpu);
    213
    214/**
    215 * qemu_plugin_user_exit(): clean-up callbacks before calling exit callbacks
    216 *
    217 * This is a user-mode only helper that ensure we have fully cleared
    218 * callbacks from all threads before calling the exit callbacks. This
    219 * is so the plugins themselves don't have to jump through hoops to
    220 * guard against race conditions.
    221 */
    222void qemu_plugin_user_exit(void);
    223
    224#else /* !CONFIG_PLUGIN */
    225
    226static inline void qemu_plugin_add_opts(void)
    227{ }
    228
    229static inline void qemu_plugin_opt_parse(const char *optarg,
    230                                         QemuPluginList *head)
    231{
    232    error_report("plugin interface not enabled in this build");
    233    exit(1);
    234}
    235
    236static inline int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
    237{
    238    return 0;
    239}
    240
    241static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu)
    242{ }
    243
    244static inline void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
    245{ }
    246
    247static inline void qemu_plugin_tb_trans_cb(CPUState *cpu,
    248                                           struct qemu_plugin_tb *tb)
    249{ }
    250
    251static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
    252{ }
    253
    254static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
    255{ }
    256
    257static inline void
    258qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
    259                         uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
    260                         uint64_t a7, uint64_t a8)
    261{ }
    262
    263static inline
    264void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
    265{ }
    266
    267static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
    268                                           MemOpIdx oi,
    269                                           enum qemu_plugin_mem_rw rw)
    270{ }
    271
    272static inline void qemu_plugin_flush_cb(void)
    273{ }
    274
    275static inline void qemu_plugin_atexit_cb(void)
    276{ }
    277
    278static inline
    279void qemu_plugin_add_dyn_cb_arr(GArray *arr)
    280{ }
    281
    282static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
    283{ }
    284
    285static inline void qemu_plugin_user_exit(void)
    286{ }
    287#endif /* !CONFIG_PLUGIN */
    288
    289#endif /* QEMU_PLUGIN_H */