|  | /* | 
|  | * QEMU KVM support | 
|  | * | 
|  | * Copyright IBM, Corp. 2008 | 
|  | *           Red Hat, Inc. 2008 | 
|  | * | 
|  | * Authors: | 
|  | *  Anthony Liguori   <aliguori@us.ibm.com> | 
|  | *  Glauber Costa     <gcosta@redhat.com> | 
|  | * | 
|  | * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
|  | * See the COPYING file in the top-level directory. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "qemu/error-report.h" | 
|  | #include "qemu/main-loop.h" | 
|  | #include "sysemu/kvm.h" | 
|  | #include "sysemu/kvm_int.h" | 
|  | #include "sysemu/runstate.h" | 
|  | #include "sysemu/cpus.h" | 
|  | #include "qemu/guest-random.h" | 
|  | #include "qapi/error.h" | 
|  |  | 
|  | #include <linux/kvm.h> | 
|  | #include "kvm-cpus.h" | 
|  |  | 
|  | static void *kvm_vcpu_thread_fn(void *arg) | 
|  | { | 
|  | CPUState *cpu = arg; | 
|  | int r; | 
|  |  | 
|  | rcu_register_thread(); | 
|  |  | 
|  | qemu_mutex_lock_iothread(); | 
|  | qemu_thread_get_self(cpu->thread); | 
|  | cpu->thread_id = qemu_get_thread_id(); | 
|  | cpu->neg.can_do_io = true; | 
|  | current_cpu = cpu; | 
|  |  | 
|  | r = kvm_init_vcpu(cpu, &error_fatal); | 
|  | kvm_init_cpu_signals(cpu); | 
|  |  | 
|  | /* signal CPU creation */ | 
|  | cpu_thread_signal_created(cpu); | 
|  | qemu_guest_random_seed_thread_part2(cpu->random_seed); | 
|  |  | 
|  | do { | 
|  | if (cpu_can_run(cpu)) { | 
|  | r = kvm_cpu_exec(cpu); | 
|  | if (r == EXCP_DEBUG) { | 
|  | cpu_handle_guest_debug(cpu); | 
|  | } | 
|  | } | 
|  | qemu_wait_io_event(cpu); | 
|  | } while (!cpu->unplug || cpu_can_run(cpu)); | 
|  |  | 
|  | kvm_destroy_vcpu(cpu); | 
|  | cpu_thread_signal_destroyed(cpu); | 
|  | qemu_mutex_unlock_iothread(); | 
|  | rcu_unregister_thread(); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void kvm_start_vcpu_thread(CPUState *cpu) | 
|  | { | 
|  | char thread_name[VCPU_THREAD_NAME_SIZE]; | 
|  |  | 
|  | cpu->thread = g_malloc0(sizeof(QemuThread)); | 
|  | cpu->halt_cond = g_malloc0(sizeof(QemuCond)); | 
|  | qemu_cond_init(cpu->halt_cond); | 
|  | snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM", | 
|  | cpu->cpu_index); | 
|  | qemu_thread_create(cpu->thread, thread_name, kvm_vcpu_thread_fn, | 
|  | cpu, QEMU_THREAD_JOINABLE); | 
|  | } | 
|  |  | 
|  | static bool kvm_vcpu_thread_is_idle(CPUState *cpu) | 
|  | { | 
|  | return !kvm_halt_in_kernel(); | 
|  | } | 
|  |  | 
|  | static bool kvm_cpus_are_resettable(void) | 
|  | { | 
|  | return !kvm_enabled() || kvm_cpu_check_are_resettable(); | 
|  | } | 
|  |  | 
|  | #ifdef KVM_CAP_SET_GUEST_DEBUG | 
|  | static int kvm_update_guest_debug_ops(CPUState *cpu) | 
|  | { | 
|  | return kvm_update_guest_debug(cpu, 0); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) | 
|  | { | 
|  | AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); | 
|  |  | 
|  | ops->create_vcpu_thread = kvm_start_vcpu_thread; | 
|  | ops->cpu_thread_is_idle = kvm_vcpu_thread_is_idle; | 
|  | ops->cpus_are_resettable = kvm_cpus_are_resettable; | 
|  | ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset; | 
|  | ops->synchronize_post_init = kvm_cpu_synchronize_post_init; | 
|  | ops->synchronize_state = kvm_cpu_synchronize_state; | 
|  | ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm; | 
|  |  | 
|  | #ifdef KVM_CAP_SET_GUEST_DEBUG | 
|  | ops->update_guest_debug = kvm_update_guest_debug_ops; | 
|  | ops->supports_guest_debug = kvm_supports_guest_debug; | 
|  | ops->insert_breakpoint = kvm_insert_breakpoint; | 
|  | ops->remove_breakpoint = kvm_remove_breakpoint; | 
|  | ops->remove_all_breakpoints = kvm_remove_all_breakpoints; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static const TypeInfo kvm_accel_ops_type = { | 
|  | .name = ACCEL_OPS_NAME("kvm"), | 
|  |  | 
|  | .parent = TYPE_ACCEL_OPS, | 
|  | .class_init = kvm_accel_ops_class_init, | 
|  | .abstract = true, | 
|  | }; | 
|  |  | 
|  | static void kvm_accel_ops_register_types(void) | 
|  | { | 
|  | type_register_static(&kvm_accel_ops_type); | 
|  | } | 
|  | type_init(kvm_accel_ops_register_types); |