@@ -13,6 +13,7 @@
#include "instrument/load.h"
#include "instrument/qemu-instr/control.h"
#include "qemu/compiler.h"
+#include "qemu/main-loop.h"
#include "qom/cpu.h"
@@ -40,6 +41,71 @@ void instr_cpu_remove(CPUState *vcpu)
}
+static void instr_cpu_stop_all__cb(CPUState *cpu, run_on_cpu_data data)
+{
+ InstrCPUStop *info = data.host_ptr;
+ /* run posted function */
+ if (info->fun) {
+ info->fun(cpu, info->data);
+ }
+#if !defined(CONFIG_USER_ONLY)
+ /* signal we're out of the main vCPU loop */
+ unsigned int count = atomic_load_acquire(&info->count);
+ atomic_store_release(&info->count, count + 1);
+ atomic_store_release(&info->stopped, true);
+ /* wait until we're good to go again */
+ qemu_cond_wait(&info->cond, &info->mutex);
+ count = atomic_load_acquire(&info->count);
+ atomic_store_release(&info->count, count - 1);
+ qemu_mutex_unlock(&info->mutex);
+#endif
+}
+
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+ instr_cpu_stop_fun fun, void *data)
+{
+ CPUState *cpu;
+
+ info->fun = fun;
+ info->data = data;
+
+#if !defined(CONFIG_USER_ONLY)
+ info->count = 0;
+ qemu_cond_init(&info->cond);
+ qemu_mutex_init(&info->mutex);
+
+ /* main dispatch loop and run_on_cpu() lock the BQL */
+ qemu_mutex_unlock_iothread();
+#endif
+
+ CPU_FOREACH(cpu) {
+#if !defined(CONFIG_USER_ONLY)
+ atomic_store_release(&info->stopped, false);
+ qemu_mutex_lock(&info->mutex);
+ async_run_on_cpu(cpu, instr_cpu_stop_all__cb, RUN_ON_CPU_HOST_PTR(info));
+ while (!atomic_load_acquire(&info->stopped)) {
+ /* wait for vCPU to signal it's stopped */
+ }
+#else
+ instr_cpu_stop_all__cb(cpu, RUN_ON_CPU_HOST_PTR(info));
+#endif
+ }
+}
+
+void instr_cpu_stop_all_end(InstrCPUStop *info)
+{
+#if !defined(CONFIG_USER_ONLY)
+ qemu_cond_broadcast(&info->cond);
+ while (atomic_load_acquire(&info->count)) {
+ /* wait for all vCPUs to continue before we can destroy info */
+ }
+ qemu_cond_destroy(&info->cond);
+ qemu_mutex_destroy(&info->mutex);
+ qemu_mutex_lock_iothread();
+#endif
+}
+
+
qi_fini_fn instr_event__fini_fn;
void *instr_event__fini_data;
@@ -46,6 +46,32 @@ static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
*/
static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
+typedef struct InstrCPUStop InstrCPUStop;
+typedef void (*instr_cpu_stop_fun)(CPUState *cpu, void *data);
+
+/**
+ * instr_cpu_stop_all_begin:
+ * @info: Opaque structure describing the operation.
+ * @fun: Function to run on the context of each vCPU once stopped.
+ * @data: Pointer to pass to @fun.
+ *
+ * Ensure all vCPUs stop executing guest code, and execute @fun on their context
+ * in turn. Returns with all vCPUs still stopped.
+ *
+ * Assumes cpu_list_lock() and that the QBL is locked before calling.
+ */
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+ instr_cpu_stop_fun fun, void *data);
+
+/**
+ * instr_cpu_stop_all_end:
+ * @info: Opaque structure passed to a previous instr_cpu_stop_all_begin()
+ * call.
+ *
+ * Resume execution on all vCPUs stopped by instr_cpu_stop_all_begin().
+ */
+void instr_cpu_stop_all_end(InstrCPUStop *info);
+
/**
* InstrState:
@@ -15,6 +15,17 @@
#include <stdint.h>
+struct InstrCPUStop {
+ instr_cpu_stop_fun fun;
+ void *data;
+#if !defined(CONFIG_USER_ONLY)
+ bool stopped;
+ unsigned int count;
+ QemuCond cond;
+ QemuMutex mutex;
+#endif
+};
+
extern unsigned int instr_cpus_count;
extern CPUState **instr_cpus;
Stops all vCPUs to allow performing management operations like TB invalidations. These are later necessary to ensure translated code does not reference unloaded instrumentation libraries. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- instrument/control.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ instrument/control.h | 26 ++++++++++++++++++ instrument/control.inc.h | 11 ++++++++ 3 files changed, 103 insertions(+)