@samitouri / QOSamiQemu / commits / d16ffa4244

plugins: add flag to specify whether PC is rw

In addition to the flags specifying whether general-purpose registers are read-write (rw) during a plugin callback, we add an additional flag explicitly stating whether the PC is writable. This is in preparation of a patch that allows to explicitly set the PC to divert control flow from within a plugin callback, which is currently not possible. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Florian Hofhammer <florian.hofhammer@epfl.ch> Link: https://lore.kernel.org/qemu-devel/20260305-setpc-v5-v7-2-4c3adba52403@epfl.ch Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>

Florian Hofhammer committed Mar 5, 2026 at 11:06 UTC d16ffa424482a2ac39d60b775f60062b491eb761
3 files changed +22 -14
include/plugins/qemu-plugin.h
+3
@@ -325,11 +325,14 @@ typedef struct {
325 * @QEMU_PLUGIN_CB_NO_REGS: callback does not access the CPU's regs
326 * @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
327 * @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
328 + * @QEMU_PLUGIN_CB_RW_REGS_PC: callback reads and writes the CPU's
329 + * regs and updates the PC
330 */
331 enum qemu_plugin_cb_flags {
332 QEMU_PLUGIN_CB_NO_REGS,
333 QEMU_PLUGIN_CB_R_REGS,
334 QEMU_PLUGIN_CB_RW_REGS,
335 + QEMU_PLUGIN_CB_RW_REGS_PC,
336 };
337
338 enum qemu_plugin_mem_rw {
plugins/api.c
+3 -1
@@ -458,7 +458,9 @@ bool qemu_plugin_write_register(struct qemu_plugin_register *reg,
458 {
459 g_assert(current_cpu);
460
461 - if (buf->len == 0 || qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS) {
461 + if (buf->len == 0 ||
462 + (qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS &&
463 + qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS_PC)) {
464 return false;
465 }
466
plugins/core.c
+16 -13
@@ -119,7 +119,7 @@ static void plugin_vcpu_cb__discon(CPUState *cpu,
119 struct qemu_plugin_cb *cb, *next;
120 uint64_t to = cpu->cc->get_pc(cpu);
121
122 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
122 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
123 if (cpu->cpu_index < plugin.num_vcpus) {
124 /* iterate safely; plugins might uninstall themselves at any time */
125 QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
@@ -395,15 +395,16 @@ void plugin_register_dyn_cb__udata(GArray **arr,
395 enum qemu_plugin_cb_flags flags,
396 void *udata)
397 {
398 - static TCGHelperInfo info[3] = {
398 + static TCGHelperInfo info[4] = {
399 [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
400 [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
401 [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
402 + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0,
403 /*
404 * Match qemu_plugin_vcpu_udata_cb_t:
405 * void (*)(uint32_t, void *)
406 */
406 - [0 ... 2].typemask = (dh_typemask(void, 0) |
407 + [0 ... 3].typemask = (dh_typemask(void, 0) |
408 dh_typemask(i32, 1) |
409 dh_typemask(ptr, 2))
410 };
@@ -425,15 +426,16 @@ void plugin_register_dyn_cond_cb__udata(GArray **arr,
426 uint64_t imm,
427 void *udata)
428 {
428 - static TCGHelperInfo info[3] = {
429 + static TCGHelperInfo info[4] = {
430 [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
431 [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
432 [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
433 + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0,
434 /*
435 * Match qemu_plugin_vcpu_udata_cb_t:
436 * void (*)(uint32_t, void *)
437 */
436 - [0 ... 2].typemask = (dh_typemask(void, 0) |
438 + [0 ... 3].typemask = (dh_typemask(void, 0) |
439 dh_typemask(i32, 1) |
440 dh_typemask(ptr, 2))
441 };
@@ -464,15 +466,16 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
466 !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) &&
467 !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
468
467 - static TCGHelperInfo info[3] = {
469 + static TCGHelperInfo info[4] = {
470 [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
471 [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
472 [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
473 + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0,
474 /*
475 * Match qemu_plugin_vcpu_mem_cb_t:
476 * void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
477 */
475 - [0 ... 2].typemask =
478 + [0 ... 3].typemask =
479 (dh_typemask(void, 0) |
480 dh_typemask(i32, 1) |
481 (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t)
@@ -553,7 +556,7 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
556 QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
557 qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall;
558
556 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
559 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
560 func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8);
561 qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
562 }
@@ -577,7 +580,7 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
580 QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
581 qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret;
582
580 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
583 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
584 func(cb->ctx->id, cpu->cpu_index, num, ret);
585 qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
586 }
@@ -605,7 +608,7 @@ qemu_plugin_vcpu_syscall_filter(CPUState *cpu, int64_t num, uint64_t a1,
608
609 clamp_syscall_arguments(&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8);
610
608 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
611 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
612
613 QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
614 qemu_plugin_vcpu_syscall_filter_cb_t func = cb->f.vcpu_syscall_filter;
@@ -626,7 +629,7 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
629 {
630 /* idle and resume cb may be called before init, ignore in this case */
631 if (cpu->cpu_index < plugin.num_vcpus) {
629 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
632 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
633 plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE);
634 qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
635 }
@@ -635,7 +638,7 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
638 void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
639 {
640 if (cpu->cpu_index < plugin.num_vcpus) {
638 - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
641 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC);
642 plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
643 qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
644 }
@@ -906,6 +909,6 @@ enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags)
909 } else if (flags & TCG_CALL_NO_WG) {
910 return QEMU_PLUGIN_CB_R_REGS;
911 } else {
909 - return QEMU_PLUGIN_CB_RW_REGS;
912 + return QEMU_PLUGIN_CB_RW_REGS_PC;
913 }
914 }