cpus: prepare new CpusAccel cpu accelerator interface
The new interface starts unused, will start being used by the next patches. It provides methods for each accelerator to start a vcpu, kick a vcpu, synchronize state, get cpu virtual clock and elapsed ticks. In qemu_wait_io_event, make it clear that APC is used only for HAX on Windows. Signed-off-by: Claudio Fontana <cfontana@suse.de> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8191d36841
commit
430065dab0
|
@ -33,6 +33,7 @@
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "trace/trace-root.h"
|
#include "trace/trace-root.h"
|
||||||
#include "qemu/plugin.h"
|
#include "qemu/plugin.h"
|
||||||
|
#include "sysemu/hw_accel.h"
|
||||||
|
|
||||||
CPUInterruptHandler cpu_interrupt_handler;
|
CPUInterruptHandler cpu_interrupt_handler;
|
||||||
|
|
||||||
|
|
|
@ -522,7 +522,7 @@ static long get_file_size(FILE *f)
|
||||||
/* TSC handling */
|
/* TSC handling */
|
||||||
uint64_t cpu_get_tsc(CPUX86State *env)
|
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||||
{
|
{
|
||||||
return cpu_get_ticks();
|
return cpus_get_elapsed_ticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IRQ handling */
|
/* IRQ handling */
|
||||||
|
|
|
@ -70,9 +70,8 @@ void cpu_enable_ticks(void);
|
||||||
void cpu_disable_ticks(void);
|
void cpu_disable_ticks(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return the time elapsed in VM between vm_start and vm_stop. Unless
|
* return the time elapsed in VM between vm_start and vm_stop.
|
||||||
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
|
* cpu_get_ticks() uses units of the host CPU cycle counter.
|
||||||
* counter.
|
|
||||||
*/
|
*/
|
||||||
int64_t cpu_get_ticks(void);
|
int64_t cpu_get_ticks(void);
|
||||||
|
|
||||||
|
@ -84,4 +83,8 @@ int64_t cpu_get_clock(void);
|
||||||
|
|
||||||
void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
|
void qemu_timer_notify_cb(void *opaque, QEMUClockType type);
|
||||||
|
|
||||||
|
/* get the VIRTUAL clock and VM elapsed ticks via the cpus accel interface */
|
||||||
|
int64_t cpus_get_virtual_clock(void);
|
||||||
|
int64_t cpus_get_elapsed_ticks(void);
|
||||||
|
|
||||||
#endif /* SYSEMU_CPU_TIMERS_H */
|
#endif /* SYSEMU_CPU_TIMERS_H */
|
||||||
|
|
|
@ -4,7 +4,43 @@
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
|
|
||||||
/* cpus.c */
|
/* cpus.c */
|
||||||
|
|
||||||
|
/* CPU execution threads */
|
||||||
|
|
||||||
|
typedef struct CpusAccel {
|
||||||
|
void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY */
|
||||||
|
void (*kick_vcpu_thread)(CPUState *cpu);
|
||||||
|
|
||||||
|
void (*synchronize_post_reset)(CPUState *cpu);
|
||||||
|
void (*synchronize_post_init)(CPUState *cpu);
|
||||||
|
void (*synchronize_state)(CPUState *cpu);
|
||||||
|
void (*synchronize_pre_loadvm)(CPUState *cpu);
|
||||||
|
|
||||||
|
int64_t (*get_virtual_clock)(void);
|
||||||
|
int64_t (*get_elapsed_ticks)(void);
|
||||||
|
} CpusAccel;
|
||||||
|
|
||||||
|
/* register accel-specific cpus interface implementation */
|
||||||
|
void cpus_register_accel(const CpusAccel *i);
|
||||||
|
|
||||||
|
/* interface available for cpus accelerator threads */
|
||||||
|
|
||||||
|
/* For temporary buffers for forming a name */
|
||||||
|
#define VCPU_THREAD_NAME_SIZE 16
|
||||||
|
|
||||||
|
void cpus_kick_thread(CPUState *cpu);
|
||||||
|
bool cpu_work_list_empty(CPUState *cpu);
|
||||||
|
bool cpu_thread_is_idle(CPUState *cpu);
|
||||||
bool all_cpu_threads_idle(void);
|
bool all_cpu_threads_idle(void);
|
||||||
|
bool cpu_can_run(CPUState *cpu);
|
||||||
|
void qemu_wait_io_event_common(CPUState *cpu);
|
||||||
|
void qemu_wait_io_event(CPUState *cpu);
|
||||||
|
void cpu_thread_signal_created(CPUState *cpu);
|
||||||
|
void cpu_thread_signal_destroyed(CPUState *cpu);
|
||||||
|
void cpu_handle_guest_debug(CPUState *cpu);
|
||||||
|
|
||||||
|
/* end interface for cpus accelerator threads */
|
||||||
|
|
||||||
bool qemu_in_vcpu_thread(void);
|
bool qemu_in_vcpu_thread(void);
|
||||||
void qemu_init_cpu_loop(void);
|
void qemu_init_cpu_loop(void);
|
||||||
void resume_all_vcpus(void);
|
void resume_all_vcpus(void);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* QEMU Hardware accelertors support
|
* QEMU Hardware accelerators support
|
||||||
*
|
*
|
||||||
* Copyright 2016 Google, Inc.
|
* Copyright 2016 Google, Inc.
|
||||||
*
|
*
|
||||||
|
@ -17,68 +17,9 @@
|
||||||
#include "sysemu/hvf.h"
|
#include "sysemu/hvf.h"
|
||||||
#include "sysemu/whpx.h"
|
#include "sysemu/whpx.h"
|
||||||
|
|
||||||
static inline void cpu_synchronize_state(CPUState *cpu)
|
void cpu_synchronize_state(CPUState *cpu);
|
||||||
{
|
void cpu_synchronize_post_reset(CPUState *cpu);
|
||||||
if (kvm_enabled()) {
|
void cpu_synchronize_post_init(CPUState *cpu);
|
||||||
kvm_cpu_synchronize_state(cpu);
|
void cpu_synchronize_pre_loadvm(CPUState *cpu);
|
||||||
}
|
|
||||||
if (hax_enabled()) {
|
|
||||||
hax_cpu_synchronize_state(cpu);
|
|
||||||
}
|
|
||||||
if (hvf_enabled()) {
|
|
||||||
hvf_cpu_synchronize_state(cpu);
|
|
||||||
}
|
|
||||||
if (whpx_enabled()) {
|
|
||||||
whpx_cpu_synchronize_state(cpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cpu_synchronize_post_reset(CPUState *cpu)
|
|
||||||
{
|
|
||||||
if (kvm_enabled()) {
|
|
||||||
kvm_cpu_synchronize_post_reset(cpu);
|
|
||||||
}
|
|
||||||
if (hax_enabled()) {
|
|
||||||
hax_cpu_synchronize_post_reset(cpu);
|
|
||||||
}
|
|
||||||
if (hvf_enabled()) {
|
|
||||||
hvf_cpu_synchronize_post_reset(cpu);
|
|
||||||
}
|
|
||||||
if (whpx_enabled()) {
|
|
||||||
whpx_cpu_synchronize_post_reset(cpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cpu_synchronize_post_init(CPUState *cpu)
|
|
||||||
{
|
|
||||||
if (kvm_enabled()) {
|
|
||||||
kvm_cpu_synchronize_post_init(cpu);
|
|
||||||
}
|
|
||||||
if (hax_enabled()) {
|
|
||||||
hax_cpu_synchronize_post_init(cpu);
|
|
||||||
}
|
|
||||||
if (hvf_enabled()) {
|
|
||||||
hvf_cpu_synchronize_post_init(cpu);
|
|
||||||
}
|
|
||||||
if (whpx_enabled()) {
|
|
||||||
whpx_cpu_synchronize_post_init(cpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cpu_synchronize_pre_loadvm(CPUState *cpu)
|
|
||||||
{
|
|
||||||
if (kvm_enabled()) {
|
|
||||||
kvm_cpu_synchronize_pre_loadvm(cpu);
|
|
||||||
}
|
|
||||||
if (hax_enabled()) {
|
|
||||||
hax_cpu_synchronize_pre_loadvm(cpu);
|
|
||||||
}
|
|
||||||
if (hvf_enabled()) {
|
|
||||||
hvf_cpu_synchronize_pre_loadvm(cpu);
|
|
||||||
}
|
|
||||||
if (whpx_enabled()) {
|
|
||||||
whpx_cpu_synchronize_pre_loadvm(cpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* QEMU_HW_ACCEL_H */
|
#endif /* QEMU_HW_ACCEL_H */
|
||||||
|
|
|
@ -61,18 +61,13 @@ static int64_t cpu_get_ticks_locked(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return the time elapsed in VM between vm_start and vm_stop. Unless
|
* return the time elapsed in VM between vm_start and vm_stop.
|
||||||
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
|
* cpu_get_ticks() uses units of the host CPU cycle counter.
|
||||||
* counter.
|
|
||||||
*/
|
*/
|
||||||
int64_t cpu_get_ticks(void)
|
int64_t cpu_get_ticks(void)
|
||||||
{
|
{
|
||||||
int64_t ticks;
|
int64_t ticks;
|
||||||
|
|
||||||
if (icount_enabled()) {
|
|
||||||
return icount_get();
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_spin_lock(&timers_state.vm_clock_lock);
|
qemu_spin_lock(&timers_state.vm_clock_lock);
|
||||||
ticks = cpu_get_ticks_locked();
|
ticks = cpu_get_ticks_locked();
|
||||||
qemu_spin_unlock(&timers_state.vm_clock_lock);
|
qemu_spin_unlock(&timers_state.vm_clock_lock);
|
||||||
|
|
195
softmmu/cpus.c
195
softmmu/cpus.c
|
@ -87,7 +87,7 @@ bool cpu_is_stopped(CPUState *cpu)
|
||||||
return cpu->stopped || !runstate_is_running();
|
return cpu->stopped || !runstate_is_running();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool cpu_work_list_empty(CPUState *cpu)
|
bool cpu_work_list_empty(CPUState *cpu)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ static inline bool cpu_work_list_empty(CPUState *cpu)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cpu_thread_is_idle(CPUState *cpu)
|
bool cpu_thread_is_idle(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (cpu->stop || !cpu_work_list_empty(cpu)) {
|
if (cpu->stop || !cpu_work_list_empty(cpu)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -215,6 +215,11 @@ void hw_error(const char *fmt, ...)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The chosen accelerator is supposed to register this.
|
||||||
|
*/
|
||||||
|
static const CpusAccel *cpus_accel;
|
||||||
|
|
||||||
void cpu_synchronize_all_states(void)
|
void cpu_synchronize_all_states(void)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
@ -251,6 +256,102 @@ void cpu_synchronize_all_pre_loadvm(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_synchronize_state(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->synchronize_state) {
|
||||||
|
cpus_accel->synchronize_state(cpu);
|
||||||
|
}
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_cpu_synchronize_state(cpu);
|
||||||
|
}
|
||||||
|
if (hax_enabled()) {
|
||||||
|
hax_cpu_synchronize_state(cpu);
|
||||||
|
}
|
||||||
|
if (whpx_enabled()) {
|
||||||
|
whpx_cpu_synchronize_state(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_synchronize_post_reset(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->synchronize_post_reset) {
|
||||||
|
cpus_accel->synchronize_post_reset(cpu);
|
||||||
|
}
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_cpu_synchronize_post_reset(cpu);
|
||||||
|
}
|
||||||
|
if (hax_enabled()) {
|
||||||
|
hax_cpu_synchronize_post_reset(cpu);
|
||||||
|
}
|
||||||
|
if (whpx_enabled()) {
|
||||||
|
whpx_cpu_synchronize_post_reset(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_synchronize_post_init(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->synchronize_post_init) {
|
||||||
|
cpus_accel->synchronize_post_init(cpu);
|
||||||
|
}
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_cpu_synchronize_post_init(cpu);
|
||||||
|
}
|
||||||
|
if (hax_enabled()) {
|
||||||
|
hax_cpu_synchronize_post_init(cpu);
|
||||||
|
}
|
||||||
|
if (whpx_enabled()) {
|
||||||
|
whpx_cpu_synchronize_post_init(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_synchronize_pre_loadvm(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->synchronize_pre_loadvm) {
|
||||||
|
cpus_accel->synchronize_pre_loadvm(cpu);
|
||||||
|
}
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_cpu_synchronize_pre_loadvm(cpu);
|
||||||
|
}
|
||||||
|
if (hax_enabled()) {
|
||||||
|
hax_cpu_synchronize_pre_loadvm(cpu);
|
||||||
|
}
|
||||||
|
if (hvf_enabled()) {
|
||||||
|
hvf_cpu_synchronize_pre_loadvm(cpu);
|
||||||
|
}
|
||||||
|
if (whpx_enabled()) {
|
||||||
|
whpx_cpu_synchronize_pre_loadvm(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t cpus_get_virtual_clock(void)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->get_virtual_clock) {
|
||||||
|
return cpus_accel->get_virtual_clock();
|
||||||
|
}
|
||||||
|
if (icount_enabled()) {
|
||||||
|
return icount_get();
|
||||||
|
} else if (qtest_enabled()) { /* for qtest_clock_warp */
|
||||||
|
return qtest_get_virtual_clock();
|
||||||
|
}
|
||||||
|
return cpu_get_clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return the time elapsed in VM between vm_start and vm_stop. Unless
|
||||||
|
* icount is active, cpus_get_elapsed_ticks() uses units of the host CPU cycle
|
||||||
|
* counter.
|
||||||
|
*/
|
||||||
|
int64_t cpus_get_elapsed_ticks(void)
|
||||||
|
{
|
||||||
|
if (cpus_accel && cpus_accel->get_elapsed_ticks) {
|
||||||
|
return cpus_accel->get_elapsed_ticks();
|
||||||
|
}
|
||||||
|
if (icount_enabled()) {
|
||||||
|
return icount_get();
|
||||||
|
}
|
||||||
|
return cpu_get_ticks();
|
||||||
|
}
|
||||||
|
|
||||||
static int do_vm_stop(RunState state, bool send_stop)
|
static int do_vm_stop(RunState state, bool send_stop)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -279,7 +380,7 @@ int vm_shutdown(void)
|
||||||
return do_vm_stop(RUN_STATE_SHUTDOWN, false);
|
return do_vm_stop(RUN_STATE_SHUTDOWN, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cpu_can_run(CPUState *cpu)
|
bool cpu_can_run(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (cpu->stop) {
|
if (cpu->stop) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -290,7 +391,7 @@ static bool cpu_can_run(CPUState *cpu)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_handle_guest_debug(CPUState *cpu)
|
void cpu_handle_guest_debug(CPUState *cpu)
|
||||||
{
|
{
|
||||||
gdb_set_stop_cpu(cpu);
|
gdb_set_stop_cpu(cpu);
|
||||||
qemu_system_debug_request();
|
qemu_system_debug_request();
|
||||||
|
@ -396,7 +497,7 @@ static void qemu_cpu_stop(CPUState *cpu, bool exit)
|
||||||
qemu_cond_broadcast(&qemu_pause_cond);
|
qemu_cond_broadcast(&qemu_pause_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_wait_io_event_common(CPUState *cpu)
|
void qemu_wait_io_event_common(CPUState *cpu)
|
||||||
{
|
{
|
||||||
qatomic_mb_set(&cpu->thread_kicked, false);
|
qatomic_mb_set(&cpu->thread_kicked, false);
|
||||||
if (cpu->stop) {
|
if (cpu->stop) {
|
||||||
|
@ -421,7 +522,7 @@ static void qemu_tcg_rr_wait_io_event(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_wait_io_event(CPUState *cpu)
|
void qemu_wait_io_event(CPUState *cpu)
|
||||||
{
|
{
|
||||||
bool slept = false;
|
bool slept = false;
|
||||||
|
|
||||||
|
@ -437,8 +538,8 @@ static void qemu_wait_io_event(CPUState *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Eat dummy APC queued by qemu_cpu_kick_thread. */
|
/* Eat dummy APC queued by cpus_kick_thread. */
|
||||||
if (!tcg_enabled()) {
|
if (hax_enabled()) {
|
||||||
SleepEx(0, TRUE);
|
SleepEx(0, TRUE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -467,8 +568,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
||||||
kvm_init_cpu_signals(cpu);
|
kvm_init_cpu_signals(cpu);
|
||||||
|
|
||||||
/* signal CPU creation */
|
/* signal CPU creation */
|
||||||
cpu->created = true;
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -482,8 +582,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
||||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||||
|
|
||||||
qemu_kvm_destroy_vcpu(cpu);
|
qemu_kvm_destroy_vcpu(cpu);
|
||||||
cpu->created = false;
|
cpu_thread_signal_destroyed(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
rcu_unregister_thread();
|
rcu_unregister_thread();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -511,8 +610,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
||||||
sigaddset(&waitset, SIG_IPI);
|
sigaddset(&waitset, SIG_IPI);
|
||||||
|
|
||||||
/* signal CPU creation */
|
/* signal CPU creation */
|
||||||
cpu->created = true;
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -660,8 +758,7 @@ static void deal_with_unplugged_cpus(void)
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
if (cpu->unplug && !cpu_can_run(cpu)) {
|
if (cpu->unplug && !cpu_can_run(cpu)) {
|
||||||
qemu_tcg_destroy_vcpu(cpu);
|
qemu_tcg_destroy_vcpu(cpu);
|
||||||
cpu->created = false;
|
cpu_thread_signal_destroyed(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -688,9 +785,8 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
|
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->created = true;
|
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
/* wait for initial kick-off after machine start */
|
/* wait for initial kick-off after machine start */
|
||||||
|
@ -800,11 +896,9 @@ static void *qemu_hax_cpu_thread_fn(void *arg)
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
|
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->created = true;
|
|
||||||
current_cpu = cpu;
|
current_cpu = cpu;
|
||||||
|
|
||||||
hax_init_vcpu(cpu);
|
hax_init_vcpu(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -843,8 +937,7 @@ static void *qemu_hvf_cpu_thread_fn(void *arg)
|
||||||
hvf_init_vcpu(cpu);
|
hvf_init_vcpu(cpu);
|
||||||
|
|
||||||
/* signal CPU creation */
|
/* signal CPU creation */
|
||||||
cpu->created = true;
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -858,8 +951,7 @@ static void *qemu_hvf_cpu_thread_fn(void *arg)
|
||||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||||
|
|
||||||
hvf_vcpu_destroy(cpu);
|
hvf_vcpu_destroy(cpu);
|
||||||
cpu->created = false;
|
cpu_thread_signal_destroyed(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
rcu_unregister_thread();
|
rcu_unregister_thread();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -884,8 +976,7 @@ static void *qemu_whpx_cpu_thread_fn(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* signal CPU creation */
|
/* signal CPU creation */
|
||||||
cpu->created = true;
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -902,8 +993,7 @@ static void *qemu_whpx_cpu_thread_fn(void *arg)
|
||||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||||
|
|
||||||
whpx_destroy_vcpu(cpu);
|
whpx_destroy_vcpu(cpu);
|
||||||
cpu->created = false;
|
cpu_thread_signal_destroyed(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
rcu_unregister_thread();
|
rcu_unregister_thread();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -936,10 +1026,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
|
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->created = true;
|
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
current_cpu = cpu;
|
current_cpu = cpu;
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
cpu_thread_signal_created(cpu);
|
||||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||||
|
|
||||||
/* process any pending work */
|
/* process any pending work */
|
||||||
|
@ -980,14 +1069,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||||
|
|
||||||
qemu_tcg_destroy_vcpu(cpu);
|
qemu_tcg_destroy_vcpu(cpu);
|
||||||
cpu->created = false;
|
cpu_thread_signal_destroyed(cpu);
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
rcu_unregister_thread();
|
rcu_unregister_thread();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_cpu_kick_thread(CPUState *cpu)
|
void cpus_kick_thread(CPUState *cpu)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int err;
|
int err;
|
||||||
|
@ -1017,7 +1105,10 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
|
||||||
void qemu_cpu_kick(CPUState *cpu)
|
void qemu_cpu_kick(CPUState *cpu)
|
||||||
{
|
{
|
||||||
qemu_cond_broadcast(cpu->halt_cond);
|
qemu_cond_broadcast(cpu->halt_cond);
|
||||||
if (tcg_enabled()) {
|
|
||||||
|
if (cpus_accel && cpus_accel->kick_vcpu_thread) {
|
||||||
|
cpus_accel->kick_vcpu_thread(cpu);
|
||||||
|
} else if (tcg_enabled()) {
|
||||||
if (qemu_tcg_mttcg_enabled()) {
|
if (qemu_tcg_mttcg_enabled()) {
|
||||||
cpu_exit(cpu);
|
cpu_exit(cpu);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1031,14 +1122,14 @@ void qemu_cpu_kick(CPUState *cpu)
|
||||||
*/
|
*/
|
||||||
cpu->exit_request = 1;
|
cpu->exit_request = 1;
|
||||||
}
|
}
|
||||||
qemu_cpu_kick_thread(cpu);
|
cpus_kick_thread(cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_cpu_kick_self(void)
|
void qemu_cpu_kick_self(void)
|
||||||
{
|
{
|
||||||
assert(current_cpu);
|
assert(current_cpu);
|
||||||
qemu_cpu_kick_thread(current_cpu);
|
cpus_kick_thread(current_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool qemu_cpu_is_self(CPUState *cpu)
|
bool qemu_cpu_is_self(CPUState *cpu)
|
||||||
|
@ -1088,6 +1179,21 @@ void qemu_cond_timedwait_iothread(QemuCond *cond, int ms)
|
||||||
qemu_cond_timedwait(cond, &qemu_global_mutex, ms);
|
qemu_cond_timedwait(cond, &qemu_global_mutex, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* signal CPU creation */
|
||||||
|
void cpu_thread_signal_created(CPUState *cpu)
|
||||||
|
{
|
||||||
|
cpu->created = true;
|
||||||
|
qemu_cond_signal(&qemu_cpu_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* signal CPU destruction */
|
||||||
|
void cpu_thread_signal_destroyed(CPUState *cpu)
|
||||||
|
{
|
||||||
|
cpu->created = false;
|
||||||
|
qemu_cond_signal(&qemu_cpu_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool all_vcpus_paused(void)
|
static bool all_vcpus_paused(void)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
@ -1163,9 +1269,6 @@ void cpu_remove_sync(CPUState *cpu)
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For temporary buffers for forming a name */
|
|
||||||
#define VCPU_THREAD_NAME_SIZE 16
|
|
||||||
|
|
||||||
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
||||||
{
|
{
|
||||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||||
|
@ -1295,6 +1398,13 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpus_register_accel(const CpusAccel *ca)
|
||||||
|
{
|
||||||
|
assert(ca != NULL);
|
||||||
|
assert(ca->create_vcpu_thread != NULL); /* mandatory */
|
||||||
|
cpus_accel = ca;
|
||||||
|
}
|
||||||
|
|
||||||
static void qemu_dummy_start_vcpu(CPUState *cpu)
|
static void qemu_dummy_start_vcpu(CPUState *cpu)
|
||||||
{
|
{
|
||||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||||
|
@ -1325,7 +1435,10 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||||
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
|
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (cpus_accel) {
|
||||||
|
/* accelerator already implements the CpusAccel interface */
|
||||||
|
cpus_accel->create_vcpu_thread(cpu);
|
||||||
|
} else if (kvm_enabled()) {
|
||||||
qemu_kvm_start_vcpu(cpu);
|
qemu_kvm_start_vcpu(cpu);
|
||||||
} else if (hax_enabled()) {
|
} else if (hax_enabled()) {
|
||||||
qemu_hax_start_vcpu(cpu);
|
qemu_hax_start_vcpu(cpu);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/hw_accel.h"
|
||||||
|
|
||||||
|
void cpu_synchronize_state(CPUState *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void cpu_synchronize_post_init(CPUState *cpu)
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/cpu-timers.h"
|
||||||
|
#include "qemu/main-loop.h"
|
||||||
|
|
||||||
|
int64_t cpus_get_virtual_clock(void)
|
||||||
|
{
|
||||||
|
return cpu_get_clock();
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ stub_ss.add(files('blockdev-close-all-bdrv-states.c'))
|
||||||
stub_ss.add(files('change-state-handler.c'))
|
stub_ss.add(files('change-state-handler.c'))
|
||||||
stub_ss.add(files('cmos.c'))
|
stub_ss.add(files('cmos.c'))
|
||||||
stub_ss.add(files('cpu-get-clock.c'))
|
stub_ss.add(files('cpu-get-clock.c'))
|
||||||
|
stub_ss.add(files('cpus-get-virtual-clock.c'))
|
||||||
stub_ss.add(files('qemu-timer-notify-cb.c'))
|
stub_ss.add(files('qemu-timer-notify-cb.c'))
|
||||||
stub_ss.add(files('icount.c'))
|
stub_ss.add(files('icount.c'))
|
||||||
stub_ss.add(files('dump.c'))
|
stub_ss.add(files('dump.c'))
|
||||||
|
@ -44,6 +45,7 @@ stub_ss.add(files('vmgenid.c'))
|
||||||
stub_ss.add(files('vmstate.c'))
|
stub_ss.add(files('vmstate.c'))
|
||||||
stub_ss.add(files('vm-stop.c'))
|
stub_ss.add(files('vm-stop.c'))
|
||||||
stub_ss.add(files('win32-kbd-hook.c'))
|
stub_ss.add(files('win32-kbd-hook.c'))
|
||||||
|
stub_ss.add(files('cpu-synchronize-state.c'))
|
||||||
if have_system
|
if have_system
|
||||||
stub_ss.add(files('semihost.c'))
|
stub_ss.add(files('semihost.c'))
|
||||||
stub_ss.add(files('xen-hw-stub.c'))
|
stub_ss.add(files('xen-hw-stub.c'))
|
||||||
|
|
|
@ -635,13 +635,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
|
||||||
return get_clock();
|
return get_clock();
|
||||||
default:
|
default:
|
||||||
case QEMU_CLOCK_VIRTUAL:
|
case QEMU_CLOCK_VIRTUAL:
|
||||||
if (icount_enabled()) {
|
return cpus_get_virtual_clock();
|
||||||
return icount_get();
|
|
||||||
} else if (qtest_enabled()) { /* for qtest_clock_warp */
|
|
||||||
return qtest_get_virtual_clock();
|
|
||||||
} else {
|
|
||||||
return cpu_get_clock();
|
|
||||||
}
|
|
||||||
case QEMU_CLOCK_HOST:
|
case QEMU_CLOCK_HOST:
|
||||||
return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
|
return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
|
||||||
case QEMU_CLOCK_VIRTUAL_RT:
|
case QEMU_CLOCK_VIRTUAL_RT:
|
||||||
|
|
Loading…
Reference in New Issue