Reviewed-by: Alwalid Salama <quic_asalama@qualcomm.com>
On 6/20/2024 5:22 PM, Alex Bennée wrote:
> Expose the ability to control time through the plugin API. Only one
> plugin can control time so it has to request control when loaded.
> There are probably more corner cases to catch here.
>
> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
> [AJB: tweaked user-mode handling, merged QEMU_PLUGIN_API fix]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Message-Id: <20240530220610.1245424-6-pierrick.bouvier@linaro.org>
>
> ---
> plugins/next
> - make qemu_plugin_update_ns a NOP in user-mode
> v2
> - remove From: header
> - merged in plugins: missing QEMU_PLUGIN_API for time control
> ---
> include/qemu/qemu-plugin.h | 27 +++++++++++++++++++++++++++
> plugins/api.c | 35 +++++++++++++++++++++++++++++++++++
> plugins/qemu-plugins.symbols | 2 ++
> 3 files changed, 64 insertions(+)
>
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index 95703d8fec..c71c705b69 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -661,6 +661,33 @@ void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
> qemu_plugin_u64 entry,
> uint64_t imm);
>
> +/**
> + * qemu_plugin_request_time_control() - request the ability to control time
> + *
> + * This grants the plugin the ability to control system time. Only one
> + * plugin can control time so if multiple plugins request the ability
> + * all but the first will fail.
> + *
> + * Returns an opaque handle or NULL if fails
> + */
> +QEMU_PLUGIN_API
> +const void *qemu_plugin_request_time_control(void);
> +
> +/**
> + * qemu_plugin_update_ns() - update system emulation time
> + * @handle: opaque handle returned by qemu_plugin_request_time_control()
> + * @time: time in nanoseconds
> + *
> + * This allows an appropriately authorised plugin (i.e. holding the
> + * time control handle) to move system time forward to @time. For
> + * user-mode emulation the time is not changed by this as all reported
> + * time comes from the host kernel.
> + *
> + * Start time is 0.
> + */
> +QEMU_PLUGIN_API
> +void qemu_plugin_update_ns(const void *handle, int64_t time);
> +
> typedef void
> (*qemu_plugin_vcpu_syscall_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_index,
> int64_t num, uint64_t a1, uint64_t a2,
> diff --git a/plugins/api.c b/plugins/api.c
> index 6bdb26bbe3..4431a0ea7e 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -39,6 +39,7 @@
> #include "qemu/main-loop.h"
> #include "qemu/plugin.h"
> #include "qemu/log.h"
> +#include "qemu/timer.h"
> #include "tcg/tcg.h"
> #include "exec/exec-all.h"
> #include "exec/gdbstub.h"
> @@ -583,3 +584,37 @@ uint64_t qemu_plugin_u64_sum(qemu_plugin_u64 entry)
> }
> return total;
> }
> +
> +/*
> + * Time control
> + */
> +static bool has_control;
> +
> +const void *qemu_plugin_request_time_control(void)
> +{
> + if (!has_control) {
> + has_control = true;
> + return &has_control;
> + }
> + return NULL;
> +}
> +
> +#ifdef CONFIG_SOFTMMU
> +static void advance_virtual_time__async(CPUState *cpu, run_on_cpu_data data)
> +{
> + int64_t new_time = data.host_ulong;
> + qemu_clock_advance_virtual_time(new_time);
> +}
> +#endif
> +
> +void qemu_plugin_update_ns(const void *handle, int64_t new_time)
> +{
> +#ifdef CONFIG_SOFTMMU
> + if (handle == &has_control) {
> + /* Need to execute out of cpu_exec, so bql can be locked. */
> + async_run_on_cpu(current_cpu,
> + advance_virtual_time__async,
> + RUN_ON_CPU_HOST_ULONG(new_time));
> + }
> +#endif
> +}
> diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
> index aa0a77a319..ca773d8d9f 100644
> --- a/plugins/qemu-plugins.symbols
> +++ b/plugins/qemu-plugins.symbols
> @@ -38,6 +38,7 @@
> qemu_plugin_register_vcpu_tb_exec_cond_cb;
> qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu;
> qemu_plugin_register_vcpu_tb_trans_cb;
> + qemu_plugin_request_time_control;
> qemu_plugin_reset;
> qemu_plugin_scoreboard_free;
> qemu_plugin_scoreboard_find;
> @@ -51,5 +52,6 @@
> qemu_plugin_u64_set;
> qemu_plugin_u64_sum;
> qemu_plugin_uninstall;
> + qemu_plugin_update_ns;
> qemu_plugin_vcpu_for_each;
> };