| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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"
 | 
					
						
							| 
									
										
										
										
											2022-09-29 12:42:24 +01:00
										 |  |  | #include "sysemu/kvm.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | #include "sysemu/kvm_int.h"
 | 
					
						
							|  |  |  | #include "sysemu/runstate.h"
 | 
					
						
							|  |  |  | #include "sysemu/cpus.h"
 | 
					
						
							|  |  |  | #include "qemu/guest-random.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-23 17:09:15 +01:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-29 12:42:24 +01:00
										 |  |  | #include <linux/kvm.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | #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->can_do_io = 1; | 
					
						
							|  |  |  |     current_cpu = cpu; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 17:09:15 +01:00
										 |  |  |     r = kvm_init_vcpu(cpu, &error_fatal); | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  |     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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-03 01:58:55 +01:00
										 |  |  | static bool kvm_vcpu_thread_is_idle(CPUState *cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return !kvm_halt_in_kernel(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-03 02:03:57 +01:00
										 |  |  | static bool kvm_cpus_are_resettable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return !kvm_enabled() || kvm_cpu_check_are_resettable(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-02 18:58:05 -08:00
										 |  |  | #ifdef KVM_CAP_SET_GUEST_DEBUG
 | 
					
						
							|  |  |  | static int kvm_update_guest_debug_ops(CPUState *cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return kvm_update_guest_debug(cpu, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 17:39:25 +01:00
										 |  |  | 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; | 
					
						
							| 
									
										
										
										
											2022-02-03 01:58:55 +01:00
										 |  |  |     ops->cpu_thread_is_idle = kvm_vcpu_thread_is_idle; | 
					
						
							| 
									
										
										
										
											2022-02-03 02:03:57 +01:00
										 |  |  |     ops->cpus_are_resettable = kvm_cpus_are_resettable; | 
					
						
							| 
									
										
										
										
											2021-02-04 17:39:25 +01:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2022-09-29 12:42:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef KVM_CAP_SET_GUEST_DEBUG
 | 
					
						
							| 
									
										
										
										
											2023-03-02 18:58:05 -08:00
										 |  |  |     ops->update_guest_debug = kvm_update_guest_debug_ops; | 
					
						
							| 
									
										
										
										
											2022-09-29 12:42:25 +01:00
										 |  |  |     ops->supports_guest_debug = kvm_supports_guest_debug; | 
					
						
							| 
									
										
										
										
											2022-09-29 12:42:24 +01:00
										 |  |  |     ops->insert_breakpoint = kvm_insert_breakpoint; | 
					
						
							|  |  |  |     ops->remove_breakpoint = kvm_remove_breakpoint; | 
					
						
							|  |  |  |     ops->remove_all_breakpoints = kvm_remove_all_breakpoints; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-04 17:39:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo kvm_accel_ops_type = { | 
					
						
							|  |  |  |     .name = ACCEL_OPS_NAME("kvm"), | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 17:39:25 +01:00
										 |  |  |     .parent = TYPE_ACCEL_OPS, | 
					
						
							|  |  |  |     .class_init = kvm_accel_ops_class_init, | 
					
						
							|  |  |  |     .abstract = true, | 
					
						
							| 
									
										
										
										
											2020-07-07 10:54:37 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-02-04 17:39:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void kvm_accel_ops_register_types(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     type_register_static(&kvm_accel_ops_type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | type_init(kvm_accel_ops_register_types); |