]>
Commit | Line | Data |
---|---|---|
54cb65d8 EC |
1 | /* |
2 | * Copyright (C) 2017, Emilio G. Cota <[email protected]> | |
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 | ||
d2f6dc07 PMD |
16 | /* |
17 | * Events that plugins can subscribe to. | |
18 | */ | |
19 | enum qemu_plugin_event { | |
20 | QEMU_PLUGIN_EV_VCPU_INIT, | |
21 | QEMU_PLUGIN_EV_VCPU_EXIT, | |
22 | QEMU_PLUGIN_EV_VCPU_TB_TRANS, | |
23 | QEMU_PLUGIN_EV_VCPU_IDLE, | |
24 | QEMU_PLUGIN_EV_VCPU_RESUME, | |
25 | QEMU_PLUGIN_EV_VCPU_SYSCALL, | |
26 | QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, | |
27 | QEMU_PLUGIN_EV_FLUSH, | |
28 | QEMU_PLUGIN_EV_ATEXIT, | |
29 | QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */ | |
30 | }; | |
31 | ||
54cb65d8 EC |
32 | /* |
33 | * Option parsing/processing. | |
34 | * Note that we can load an arbitrary number of plugins. | |
35 | */ | |
36 | struct qemu_plugin_desc; | |
37 | typedef QTAILQ_HEAD(, qemu_plugin_desc) QemuPluginList; | |
38 | ||
39 | #ifdef CONFIG_PLUGIN | |
40 | extern QemuOptsList qemu_plugin_opts; | |
41 | ||
42 | static inline void qemu_plugin_add_opts(void) | |
43 | { | |
44 | qemu_add_opts(&qemu_plugin_opts); | |
45 | } | |
46 | ||
47 | void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head); | |
48 | int qemu_plugin_load_list(QemuPluginList *head); | |
54cb65d8 | 49 | |
54cb65d8 EC |
50 | union qemu_plugin_cb_sig { |
51 | qemu_plugin_simple_cb_t simple; | |
52 | qemu_plugin_udata_cb_t udata; | |
53 | qemu_plugin_vcpu_simple_cb_t vcpu_simple; | |
54 | qemu_plugin_vcpu_udata_cb_t vcpu_udata; | |
55 | qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans; | |
56 | qemu_plugin_vcpu_mem_cb_t vcpu_mem; | |
57 | qemu_plugin_vcpu_syscall_cb_t vcpu_syscall; | |
58 | qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret; | |
59 | void *generic; | |
60 | }; | |
61 | ||
62 | enum plugin_dyn_cb_type { | |
63 | PLUGIN_CB_INSN, | |
64 | PLUGIN_CB_MEM, | |
65 | PLUGIN_N_CB_TYPES, | |
66 | }; | |
67 | ||
68 | enum plugin_dyn_cb_subtype { | |
69 | PLUGIN_CB_REGULAR, | |
70 | PLUGIN_CB_INLINE, | |
71 | PLUGIN_N_CB_SUBTYPES, | |
72 | }; | |
73 | ||
74 | /* | |
75 | * A dynamic callback has an insertion point that is determined at run-time. | |
76 | * Usually the insertion point is somewhere in the code cache; think for | |
77 | * instance of a callback to be called upon the execution of a particular TB. | |
78 | */ | |
79 | struct qemu_plugin_dyn_cb { | |
80 | union qemu_plugin_cb_sig f; | |
81 | void *userp; | |
82 | unsigned tcg_flags; | |
83 | enum plugin_dyn_cb_subtype type; | |
84 | /* @rw applies to mem callbacks only (both regular and inline) */ | |
85 | enum qemu_plugin_mem_rw rw; | |
86 | /* fields specific to each dyn_cb type go here */ | |
87 | union { | |
88 | struct { | |
89 | enum qemu_plugin_op op; | |
90 | uint64_t imm; | |
91 | } inline_insn; | |
92 | }; | |
93 | }; | |
94 | ||
95 | struct qemu_plugin_insn { | |
96 | GByteArray *data; | |
97 | uint64_t vaddr; | |
98 | void *haddr; | |
99 | GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES]; | |
100 | bool calls_helpers; | |
101 | bool mem_helper; | |
102 | }; | |
103 | ||
104 | /* | |
105 | * qemu_plugin_insn allocate and cleanup functions. We don't expect to | |
106 | * cleanup many of these structures. They are reused for each fresh | |
107 | * translation. | |
108 | */ | |
109 | ||
110 | static inline void qemu_plugin_insn_cleanup_fn(gpointer data) | |
111 | { | |
112 | struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data; | |
113 | g_byte_array_free(insn->data, true); | |
114 | } | |
115 | ||
116 | static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void) | |
117 | { | |
118 | int i, j; | |
119 | struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1); | |
120 | insn->data = g_byte_array_sized_new(4); | |
121 | ||
122 | for (i = 0; i < PLUGIN_N_CB_TYPES; i++) { | |
123 | for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) { | |
124 | insn->cbs[i][j] = g_array_new(false, false, | |
125 | sizeof(struct qemu_plugin_dyn_cb)); | |
126 | } | |
127 | } | |
128 | return insn; | |
129 | } | |
130 | ||
131 | struct qemu_plugin_tb { | |
132 | GPtrArray *insns; | |
133 | size_t n; | |
134 | uint64_t vaddr; | |
135 | uint64_t vaddr2; | |
136 | void *haddr1; | |
137 | void *haddr2; | |
138 | GArray *cbs[PLUGIN_N_CB_SUBTYPES]; | |
139 | }; | |
140 | ||
141 | /** | |
142 | * qemu_plugin_tb_insn_get(): get next plugin record for translation. | |
143 | * | |
144 | */ | |
145 | static inline | |
146 | struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb) | |
147 | { | |
148 | struct qemu_plugin_insn *insn; | |
149 | int i, j; | |
150 | ||
151 | if (unlikely(tb->n == tb->insns->len)) { | |
152 | struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc(); | |
153 | g_ptr_array_add(tb->insns, new_insn); | |
154 | } | |
155 | insn = g_ptr_array_index(tb->insns, tb->n++); | |
156 | g_byte_array_set_size(insn->data, 0); | |
157 | insn->calls_helpers = false; | |
158 | insn->mem_helper = false; | |
159 | ||
160 | for (i = 0; i < PLUGIN_N_CB_TYPES; i++) { | |
161 | for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) { | |
162 | g_array_set_size(insn->cbs[i][j], 0); | |
163 | } | |
164 | } | |
165 | ||
166 | return insn; | |
167 | } | |
168 | ||
54cb65d8 EC |
169 | void qemu_plugin_vcpu_init_hook(CPUState *cpu); |
170 | void qemu_plugin_vcpu_exit_hook(CPUState *cpu); | |
171 | void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb); | |
172 | void qemu_plugin_vcpu_idle_cb(CPUState *cpu); | |
173 | void qemu_plugin_vcpu_resume_cb(CPUState *cpu); | |
174 | void | |
175 | qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, | |
176 | uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, | |
177 | uint64_t a6, uint64_t a7, uint64_t a8); | |
178 | void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret); | |
179 | ||
180 | void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, uint32_t meminfo); | |
181 | ||
182 | void qemu_plugin_flush_cb(void); | |
183 | ||
184 | void qemu_plugin_atexit_cb(void); | |
185 | ||
186 | void qemu_plugin_add_dyn_cb_arr(GArray *arr); | |
187 | ||
188 | void qemu_plugin_disable_mem_helpers(CPUState *cpu); | |
189 | ||
190 | #else /* !CONFIG_PLUGIN */ | |
191 | ||
1b9905ca PMD |
192 | static inline void qemu_plugin_add_opts(void) |
193 | { } | |
194 | ||
195 | static inline void qemu_plugin_opt_parse(const char *optarg, | |
196 | QemuPluginList *head) | |
197 | { | |
198 | error_report("plugin interface not enabled in this build"); | |
199 | exit(1); | |
200 | } | |
201 | ||
202 | static inline int qemu_plugin_load_list(QemuPluginList *head) | |
203 | { | |
204 | return 0; | |
205 | } | |
206 | ||
54cb65d8 EC |
207 | static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu) |
208 | { } | |
209 | ||
210 | static inline void qemu_plugin_vcpu_exit_hook(CPUState *cpu) | |
211 | { } | |
212 | ||
213 | static inline void qemu_plugin_tb_trans_cb(CPUState *cpu, | |
214 | struct qemu_plugin_tb *tb) | |
215 | { } | |
216 | ||
217 | static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu) | |
218 | { } | |
219 | ||
220 | static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu) | |
221 | { } | |
222 | ||
223 | static inline void | |
224 | qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2, | |
225 | uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6, | |
226 | uint64_t a7, uint64_t a8) | |
227 | { } | |
228 | ||
229 | static inline | |
230 | void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret) | |
231 | { } | |
232 | ||
233 | static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, | |
234 | uint32_t meminfo) | |
235 | { } | |
236 | ||
237 | static inline void qemu_plugin_flush_cb(void) | |
238 | { } | |
239 | ||
240 | static inline void qemu_plugin_atexit_cb(void) | |
241 | { } | |
242 | ||
243 | static inline | |
244 | void qemu_plugin_add_dyn_cb_arr(GArray *arr) | |
245 | { } | |
246 | ||
247 | static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu) | |
248 | { } | |
249 | ||
250 | #endif /* !CONFIG_PLUGIN */ | |
251 | ||
252 | #endif /* QEMU_PLUGIN_H */ |