Merge remote branch 'qemu-kvm/uq/master' into staging
This commit is contained in:
commit
7ac9f9be20
@ -821,6 +821,8 @@ void cpu_watchpoint_remove_all(CPUState *env, int mask);
|
||||
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
void cpu_reset(CPUState *s);
|
||||
int cpu_is_stopped(CPUState *env);
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data);
|
||||
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||
|
@ -132,6 +132,7 @@ typedef struct icount_decr_u16 {
|
||||
|
||||
struct kvm_run;
|
||||
struct KVMState;
|
||||
struct qemu_work_item;
|
||||
|
||||
typedef struct CPUBreakpoint {
|
||||
target_ulong pc;
|
||||
@ -158,8 +159,6 @@ typedef struct CPUWatchpoint {
|
||||
target_ulong mem_io_vaddr; /* target virtual addr at which the \
|
||||
memory was accessed */ \
|
||||
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
|
||||
uint32_t stop; /* Stop request */ \
|
||||
uint32_t stopped; /* Artificially stopped */ \
|
||||
uint32_t interrupt_request; \
|
||||
volatile sig_atomic_t exit_request; \
|
||||
CPU_COMMON_TLB \
|
||||
@ -202,8 +201,11 @@ typedef struct CPUWatchpoint {
|
||||
void *opaque; \
|
||||
\
|
||||
uint32_t created; \
|
||||
uint32_t stop; /* Stop request */ \
|
||||
uint32_t stopped; /* Artificially stopped */ \
|
||||
struct QemuThread *thread; \
|
||||
struct QemuCond *halt_cond; \
|
||||
struct qemu_work_item *queued_work_first, *queued_work_last; \
|
||||
const char *cpu_model_str; \
|
||||
struct KVMState *kvm_state; \
|
||||
struct kvm_run *kvm_run; \
|
||||
|
@ -213,6 +213,8 @@ static void cpu_handle_debug_exception(CPUState *env)
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
volatile sig_atomic_t exit_request;
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
volatile host_reg_t saved_env_reg;
|
||||
@ -234,6 +236,11 @@ int cpu_exec(CPUState *env1)
|
||||
asm("");
|
||||
env = env1;
|
||||
|
||||
if (exit_request) {
|
||||
env->exit_request = 1;
|
||||
exit_request = 0;
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
if (!kvm_enabled()) {
|
||||
/* put eflags in CPU temporary format */
|
||||
|
88
cpus.c
88
cpus.c
@ -91,6 +91,11 @@ void cpu_synchronize_all_post_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_is_stopped(CPUState *env)
|
||||
{
|
||||
return !vm_running || env->stopped;
|
||||
}
|
||||
|
||||
static void do_vm_stop(int reason)
|
||||
{
|
||||
if (vm_running) {
|
||||
@ -115,6 +120,8 @@ static int cpu_has_work(CPUState *env)
|
||||
{
|
||||
if (env->stop)
|
||||
return 1;
|
||||
if (env->queued_work_first)
|
||||
return 1;
|
||||
if (env->stopped || !vm_running)
|
||||
return 0;
|
||||
if (!env->halted)
|
||||
@ -252,6 +259,11 @@ int qemu_cpu_self(void *env)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
|
||||
{
|
||||
func(data);
|
||||
}
|
||||
|
||||
void resume_all_vcpus(void)
|
||||
{
|
||||
}
|
||||
@ -304,6 +316,7 @@ static QemuCond qemu_cpu_cond;
|
||||
/* system init */
|
||||
static QemuCond qemu_system_cond;
|
||||
static QemuCond qemu_pause_cond;
|
||||
static QemuCond qemu_work_cond;
|
||||
|
||||
static void tcg_block_io_signals(void);
|
||||
static void kvm_block_io_signals(CPUState *env);
|
||||
@ -334,6 +347,50 @@ void qemu_main_loop_start(void)
|
||||
qemu_cond_broadcast(&qemu_system_cond);
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
|
||||
{
|
||||
struct qemu_work_item wi;
|
||||
|
||||
if (qemu_cpu_self(env)) {
|
||||
func(data);
|
||||
return;
|
||||
}
|
||||
|
||||
wi.func = func;
|
||||
wi.data = data;
|
||||
if (!env->queued_work_first)
|
||||
env->queued_work_first = &wi;
|
||||
else
|
||||
env->queued_work_last->next = &wi;
|
||||
env->queued_work_last = &wi;
|
||||
wi.next = NULL;
|
||||
wi.done = false;
|
||||
|
||||
qemu_cpu_kick(env);
|
||||
while (!wi.done) {
|
||||
CPUState *self_env = cpu_single_env;
|
||||
|
||||
qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
|
||||
cpu_single_env = self_env;
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_queued_work(CPUState *env)
|
||||
{
|
||||
struct qemu_work_item *wi;
|
||||
|
||||
if (!env->queued_work_first)
|
||||
return;
|
||||
|
||||
while ((wi = env->queued_work_first)) {
|
||||
env->queued_work_first = wi->next;
|
||||
wi->func(wi->data);
|
||||
wi->done = true;
|
||||
}
|
||||
env->queued_work_last = NULL;
|
||||
qemu_cond_broadcast(&qemu_work_cond);
|
||||
}
|
||||
|
||||
static void qemu_wait_io_event_common(CPUState *env)
|
||||
{
|
||||
if (env->stop) {
|
||||
@ -341,6 +398,7 @@ static void qemu_wait_io_event_common(CPUState *env)
|
||||
env->stopped = 1;
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
}
|
||||
flush_queued_work(env);
|
||||
}
|
||||
|
||||
static void qemu_wait_io_event(CPUState *env)
|
||||
@ -454,8 +512,7 @@ void qemu_cpu_kick(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
qemu_cond_broadcast(env->halt_cond);
|
||||
if (kvm_enabled())
|
||||
qemu_thread_signal(env->thread, SIG_IPI);
|
||||
qemu_thread_signal(env->thread, SIG_IPI);
|
||||
}
|
||||
|
||||
int qemu_cpu_self(void *_env)
|
||||
@ -472,6 +529,7 @@ static void cpu_signal(int sig)
|
||||
{
|
||||
if (cpu_single_env)
|
||||
cpu_exit(cpu_single_env);
|
||||
exit_request = 1;
|
||||
}
|
||||
|
||||
static void tcg_block_io_signals(void)
|
||||
@ -542,26 +600,20 @@ static void unblock_io_signals(void)
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
}
|
||||
|
||||
static void qemu_signal_lock(unsigned int msecs)
|
||||
{
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
|
||||
while (qemu_mutex_trylock(&qemu_global_mutex)) {
|
||||
qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
|
||||
if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
|
||||
break;
|
||||
}
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock_iothread(void)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
} else
|
||||
qemu_signal_lock(100);
|
||||
} else {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
if (qemu_mutex_trylock(&qemu_global_mutex)) {
|
||||
qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
}
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock_iothread(void)
|
||||
@ -588,7 +640,6 @@ void pause_all_vcpus(void)
|
||||
|
||||
while (penv) {
|
||||
penv->stop = 1;
|
||||
qemu_thread_signal(penv->thread, SIG_IPI);
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
@ -597,7 +648,7 @@ void pause_all_vcpus(void)
|
||||
qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
|
||||
penv = first_cpu;
|
||||
while (penv) {
|
||||
qemu_thread_signal(penv->thread, SIG_IPI);
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
}
|
||||
@ -610,7 +661,6 @@ void resume_all_vcpus(void)
|
||||
while (penv) {
|
||||
penv->stop = 0;
|
||||
penv->stopped = 0;
|
||||
qemu_thread_signal(penv->thread, SIG_IPI);
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
|
@ -351,4 +351,7 @@ CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
|
||||
/* vl.c */
|
||||
extern int singlestep;
|
||||
|
||||
/* cpu-exec.c */
|
||||
extern volatile sig_atomic_t exit_request;
|
||||
|
||||
#endif
|
||||
|
8
exec.c
8
exec.c
@ -2775,8 +2775,12 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
|
||||
if (mem_path) {
|
||||
#if defined (__linux__) && !defined(TARGET_S390X)
|
||||
new_block->host = file_ram_alloc(size, mem_path);
|
||||
if (!new_block->host)
|
||||
exit(1);
|
||||
if (!new_block->host) {
|
||||
new_block->host = qemu_vmalloc(size);
|
||||
#ifdef MADV_MERGEABLE
|
||||
madvise(new_block->host, size, MADV_MERGEABLE);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "-mem-path option unsupported\n");
|
||||
exit(1);
|
||||
|
24
kvm-all.c
24
kvm-all.c
@ -593,11 +593,6 @@ int kvm_init(int smp_cpus)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (smp_cpus > 1) {
|
||||
fprintf(stderr, "No SMP KVM support, use '-smp 1'\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = qemu_mallocz(sizeof(KVMState));
|
||||
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
@ -769,6 +764,8 @@ static void kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
|
||||
cpu_dump_state(env, stderr, fprintf, 0);
|
||||
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
|
||||
fprintf(stderr, "emulation failure\n");
|
||||
if (!kvm_arch_stop_on_emulation_error(env))
|
||||
return;
|
||||
}
|
||||
/* FIXME: Should trigger a qmp message to let management know
|
||||
* something went wrong.
|
||||
@ -796,14 +793,22 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_state(CPUState *env)
|
||||
static void do_kvm_cpu_synchronize_state(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
|
||||
if (!env->kvm_vcpu_dirty) {
|
||||
kvm_arch_get_registers(env);
|
||||
env->kvm_vcpu_dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_state(CPUState *env)
|
||||
{
|
||||
if (!env->kvm_vcpu_dirty)
|
||||
run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_post_reset(CPUState *env)
|
||||
{
|
||||
kvm_arch_put_registers(env, KVM_PUT_RESET_STATE);
|
||||
@ -832,15 +837,22 @@ int kvm_cpu_exec(CPUState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (kvm_arch_process_irqchip_events(env)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (env->kvm_vcpu_dirty) {
|
||||
kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
|
||||
env->kvm_vcpu_dirty = 0;
|
||||
}
|
||||
|
||||
kvm_arch_pre_run(env, run);
|
||||
cpu_single_env = NULL;
|
||||
qemu_mutex_unlock_iothread();
|
||||
ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
|
||||
qemu_mutex_lock_iothread();
|
||||
cpu_single_env = env;
|
||||
kvm_arch_post_run(env, run);
|
||||
|
||||
if (ret == -EINTR || ret == -EAGAIN) {
|
||||
|
4
kvm.h
4
kvm.h
@ -90,6 +90,8 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
|
||||
|
||||
int kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
|
||||
|
||||
int kvm_arch_process_irqchip_events(CPUState *env);
|
||||
|
||||
int kvm_arch_get_registers(CPUState *env);
|
||||
|
||||
/* state subset only touched by the VCPU itself during runtime */
|
||||
@ -138,6 +140,8 @@ void kvm_arch_remove_all_hw_breakpoints(void);
|
||||
|
||||
void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUState *env);
|
||||
|
||||
int kvm_check_extension(KVMState *s, unsigned int extension);
|
||||
|
||||
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
|
||||
|
@ -249,6 +249,14 @@ void qemu_notify_event(void);
|
||||
void qemu_cpu_kick(void *env);
|
||||
int qemu_cpu_self(void *env);
|
||||
|
||||
/* work queue */
|
||||
struct qemu_work_item {
|
||||
struct qemu_work_item *next;
|
||||
void (*func)(void *data);
|
||||
void *data;
|
||||
int done;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define qemu_init_vcpu(env) do { } while (0)
|
||||
#else
|
||||
|
@ -111,7 +111,7 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
|
||||
* so add missing bits according to the AMD spec:
|
||||
*/
|
||||
cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, R_EDX);
|
||||
ret |= cpuid_1_edx & 0xdfeff7ff;
|
||||
ret |= cpuid_1_edx & 0x183f7ff;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -949,6 +949,8 @@ int kvm_arch_put_registers(CPUState *env, int level)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(cpu_is_stopped(env) || qemu_cpu_self(env));
|
||||
|
||||
ret = kvm_getput_regs(env, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -991,6 +993,8 @@ int kvm_arch_get_registers(CPUState *env)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(cpu_is_stopped(env) || qemu_cpu_self(env));
|
||||
|
||||
ret = kvm_getput_regs(env, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1069,6 +1073,22 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_process_irqchip_events(CPUState *env)
|
||||
{
|
||||
if (env->interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
kvm_cpu_synchronize_state(env);
|
||||
do_cpu_init(env);
|
||||
env->exception_index = EXCP_HALTED;
|
||||
}
|
||||
|
||||
if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||
kvm_cpu_synchronize_state(env);
|
||||
do_cpu_sipi(env);
|
||||
}
|
||||
|
||||
return env->halted;
|
||||
}
|
||||
|
||||
static int kvm_handle_halt(CPUState *env)
|
||||
{
|
||||
if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
@ -1269,3 +1289,10 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
|
||||
}
|
||||
}
|
||||
#endif /* KVM_CAP_SET_GUEST_DEBUG */
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUState *env)
|
||||
{
|
||||
return !(env->cr[0] & CR0_PE_MASK) ||
|
||||
((env->segs[R_CS].selector & 3) != 3);
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,11 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_process_irqchip_events(CPUState *env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvmppc_handle_halt(CPUState *env)
|
||||
{
|
||||
if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
|
||||
@ -321,3 +326,8 @@ uint32_t kvmppc_get_tbfreq(void)
|
||||
retval = atoi(ns);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUState *env)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -175,6 +175,11 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_process_irqchip_events(CPUState *env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
|
||||
uint64_t parm64, int vm)
|
||||
{
|
||||
@ -480,3 +485,8 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUState *env)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user