The plugin API allows registration of callbacks for a variety of VCPU
related events, such as VCPU reset, idle and resume. In addition to
those events, we recently defined discontinuity events, which include
traps.
This change introduces a function to register callbacks for these
events. We define one distinct plugin event type for each type of
discontinuity, granting fine control to plugins in term of which events
they receive.
---
include/qemu/plugin-event.h | 3 +++
include/qemu/qemu-plugin.h | 15 +++++++++++++++
plugins/core.c | 15 +++++++++++++++
3 files changed, 33 insertions(+)
diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
index 7056d8427b..1100dae212 100644
--- a/include/qemu/plugin-event.h
+++ b/include/qemu/plugin-event.h
@@ -20,6 +20,9 @@ enum qemu_plugin_event {
QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
QEMU_PLUGIN_EV_FLUSH,
QEMU_PLUGIN_EV_ATEXIT,
+ QEMU_PLUGIN_EV_VCPU_INTERRUPT,
+ QEMU_PLUGIN_EV_VCPU_EXCEPTION,
+ QEMU_PLUGIN_EV_VCPU_HOSTCALL,
QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
};
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 9c67374b7e..f998a465e5 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -273,6 +273,21 @@ QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
+/**
+ * qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU receives a discontinuity event
+ * of the specified type(s), after the vCPU was prepared to handle the event.
+ * Preparation usually entails updating the PC to some interrupt handler or trap
+ * vector entry.
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
+ enum qemu_plugin_discon_type type,
+ qemu_plugin_vcpu_discon_cb_t cb);
+
/** struct qemu_plugin_tb - Opaque handle for a translation block */
struct qemu_plugin_tb;
/** struct qemu_plugin_insn - Opaque handle for a translated instruction */
diff --git a/plugins/core.c b/plugins/core.c
index bb105e8e68..a89a4a0315 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -559,6 +559,21 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
}
+void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
+ enum qemu_plugin_discon_type type,
+ qemu_plugin_vcpu_discon_cb_t cb)
+{
+ if (type & QEMU_PLUGIN_DISCON_INTERRUPT) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
+ }
+ if (type & QEMU_PLUGIN_DISCON_EXCEPTION) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
+ }
+ if (type & QEMU_PLUGIN_DISCON_HOSTCALL) {
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_HOSTCALL, cb);
+ }
+}
+
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
qemu_plugin_simple_cb_t cb)
{
--
2.45.2
Julian Ganz <neither@nut.email> writes:
> The plugin API allows registration of callbacks for a variety of VCPU
> related events, such as VCPU reset, idle and resume. In addition to
> those events, we recently defined discontinuity events, which include
> traps.
>
> This change introduces a function to register callbacks for these
> events. We define one distinct plugin event type for each type of
> discontinuity, granting fine control to plugins in term of which events
> they receive.
> ---
> include/qemu/plugin-event.h | 3 +++
> include/qemu/qemu-plugin.h | 15 +++++++++++++++
> plugins/core.c | 15 +++++++++++++++
> 3 files changed, 33 insertions(+)
>
> diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
> index 7056d8427b..1100dae212 100644
> --- a/include/qemu/plugin-event.h
> +++ b/include/qemu/plugin-event.h
> @@ -20,6 +20,9 @@ enum qemu_plugin_event {
> QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
> QEMU_PLUGIN_EV_FLUSH,
> QEMU_PLUGIN_EV_ATEXIT,
> + QEMU_PLUGIN_EV_VCPU_INTERRUPT,
> + QEMU_PLUGIN_EV_VCPU_EXCEPTION,
> + QEMU_PLUGIN_EV_VCPU_HOSTCALL,
> QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
> };
>
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index 9c67374b7e..f998a465e5 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -273,6 +273,21 @@ QEMU_PLUGIN_API
> void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
> qemu_plugin_vcpu_simple_cb_t cb);
>
> +/**
> + * qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback
> + * @id: plugin ID
> + * @cb: callback function
> + *
> + * The @cb function is called every time a vCPU receives a discontinuity event
> + * of the specified type(s), after the vCPU was prepared to handle the event.
> + * Preparation usually entails updating the PC to some interrupt handler or trap
> + * vector entry.
The "usually" here is a bit of a weasel word. We should be clear what
the contract is with the plugin. Can we say the PC will be updated to
the next instruction that will execute after the callback?
> + */
> +QEMU_PLUGIN_API
> +void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
> + enum qemu_plugin_discon_type type,
> + qemu_plugin_vcpu_discon_cb_t cb);
> +
> /** struct qemu_plugin_tb - Opaque handle for a translation block */
> struct qemu_plugin_tb;
> /** struct qemu_plugin_insn - Opaque handle for a translated instruction */
> diff --git a/plugins/core.c b/plugins/core.c
> index bb105e8e68..a89a4a0315 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -559,6 +559,21 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
> plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
> }
>
> +void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
> + enum qemu_plugin_discon_type type,
> + qemu_plugin_vcpu_discon_cb_t cb)
> +{
> + if (type & QEMU_PLUGIN_DISCON_INTERRUPT) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
> + }
> + if (type & QEMU_PLUGIN_DISCON_EXCEPTION) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
> + }
> + if (type & QEMU_PLUGIN_DISCON_HOSTCALL) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_HOSTCALL, cb);
> + }
> +}
> +
> void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
> qemu_plugin_simple_cb_t cb)
> {
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
Hi Alex, January 9, 2025 at 2:57 PM, "Alex Bennée" wrote: > Julian Ganz <neither@nut.email> writes: > > diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h > > index 9c67374b7e..f998a465e5 100644 > > --- a/include/qemu/qemu-plugin.h > > +++ b/include/qemu/qemu-plugin.h > > @@ -273,6 +273,21 @@ QEMU_PLUGIN_API > > void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id, > > qemu_plugin_vcpu_simple_cb_t cb); > > > > +/** > > + * qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback > > + * @id: plugin ID > > + * @cb: callback function > > + * > > + * The @cb function is called every time a vCPU receives a discontinuity event > > + * of the specified type(s), after the vCPU was prepared to handle the event. > > + * Preparation usually entails updating the PC to some interrupt handler or trap > > + * vector entry. > > > The "usually" here is a bit of a weasel word. We should be clear what > the contract is with the plugin. Can we say the PC will be updated to > the next instruction that will execute after the callback? The contract is indeed clear: the PC will always be updated to the instruction that will be executed next, at least if we don't have a second discontinuity (e.g. jump to an unmapped page). The "usually" refers to the discontinuity itself: in the case of host calls, we don't observe a "jump" and the next instruction executed will just be the instruction following the call. I could have phrased this better, and will make this more clear in the next update. Regards, Julian
On 12/2/24 11:26, Julian Ganz wrote:
> The plugin API allows registration of callbacks for a variety of VCPU
> related events, such as VCPU reset, idle and resume. In addition to
> those events, we recently defined discontinuity events, which include
> traps.
>
> This change introduces a function to register callbacks for these
> events. We define one distinct plugin event type for each type of
> discontinuity, granting fine control to plugins in term of which events
> they receive.
> ---
> include/qemu/plugin-event.h | 3 +++
> include/qemu/qemu-plugin.h | 15 +++++++++++++++
> plugins/core.c | 15 +++++++++++++++
> 3 files changed, 33 insertions(+)
>
> diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
> index 7056d8427b..1100dae212 100644
> --- a/include/qemu/plugin-event.h
> +++ b/include/qemu/plugin-event.h
> @@ -20,6 +20,9 @@ enum qemu_plugin_event {
> QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
> QEMU_PLUGIN_EV_FLUSH,
> QEMU_PLUGIN_EV_ATEXIT,
> + QEMU_PLUGIN_EV_VCPU_INTERRUPT,
> + QEMU_PLUGIN_EV_VCPU_EXCEPTION,
> + QEMU_PLUGIN_EV_VCPU_HOSTCALL,
> QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
> };
>
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index 9c67374b7e..f998a465e5 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -273,6 +273,21 @@ QEMU_PLUGIN_API
> void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
> qemu_plugin_vcpu_simple_cb_t cb);
>
> +/**
> + * qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback
> + * @id: plugin ID
> + * @cb: callback function
> + *
> + * The @cb function is called every time a vCPU receives a discontinuity event
> + * of the specified type(s), after the vCPU was prepared to handle the event.
> + * Preparation usually entails updating the PC to some interrupt handler or trap
> + * vector entry.
> + */
> +QEMU_PLUGIN_API
> +void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
> + enum qemu_plugin_discon_type type,
> + qemu_plugin_vcpu_discon_cb_t cb);
> +
> /** struct qemu_plugin_tb - Opaque handle for a translation block */
> struct qemu_plugin_tb;
> /** struct qemu_plugin_insn - Opaque handle for a translated instruction */
> diff --git a/plugins/core.c b/plugins/core.c
> index bb105e8e68..a89a4a0315 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -559,6 +559,21 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
> plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
> }
>
> +void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
> + enum qemu_plugin_discon_type type,
> + qemu_plugin_vcpu_discon_cb_t cb)
> +{
> + if (type & QEMU_PLUGIN_DISCON_INTERRUPT) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
> + }
> + if (type & QEMU_PLUGIN_DISCON_EXCEPTION) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
> + }
> + if (type & QEMU_PLUGIN_DISCON_HOSTCALL) {
> + plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_HOSTCALL, cb);
> + }
> +}
> +
> void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
> qemu_plugin_simple_cb_t cb)
> {
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
© 2016 - 2025 Red Hat, Inc.