From 2464d0d6115e1794468ff455e3acdb98e0d71a31 Mon Sep 17 00:00:00 2001 From: Salil Mehta Date: Tue, 16 Jul 2024 12:14:56 +0100 Subject: [PATCH 62/78] accel/kvm: Extract common KVM vCPU {creation,parking} code KVM vCPU creation is done once during the vCPU realization when Qemu vCPU thread is spawned. This is common to all the architectures as of now. Hot-unplug of vCPU results in destruction of the vCPU object in QOM but the corresponding KVM vCPU object in the Host KVM is not destroyed as KVM doesn't support vCPU removal. Therefore, its representative KVM vCPU object/context in Qemu is parked. Refactor architecture common logic so that some APIs could be reused by vCPU Hotplug code of some architectures likes ARM, Loongson etc. Update new/old APIs with trace events. New APIs qemu_{create,park,unpark}_vcpu() can be externally called. No functional change is intended here. Signed-off-by: Salil Mehta Reviewed-by: Gavin Shan Tested-by: Vishnu Pajjuri Reviewed-by: Jonathan Cameron Tested-by: Xianglai Li Tested-by: Miguel Luis Reviewed-by: Shaoqin Huang Reviewed-by: Vishnu Pajjuri Reviewed-by: Nicholas Piggin Tested-by: Zhao Liu Reviewed-by: Zhao Liu Reviewed-by: Harsh Prateek Bora Reviewed-by: Igor Mammedov Message-Id: <20240716111502.202344-2-salil.mehta@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Signed-off-by: Xianglai Li --- accel/kvm/kvm-all.c | 71 +++++++++++++++++++++--------------------- accel/kvm/trace-events | 11 +++++++ include/sysemu/kvm.h | 27 ++++++++++++++-- 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 8077630825..8dea8f98bb 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -141,7 +141,6 @@ static QemuMutex kml_slots_lock; #define kvm_slots_unlock() qemu_mutex_unlock(&kml_slots_lock) static void kvm_slot_init_dirty_bitmap(KVMSlot *mem); -static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id); static inline void kvm_resample_fd_remove(int gsi) { @@ -334,39 +333,57 @@ void kvm_park_vcpu(CPUState *cpu) { struct KVMParkedVcpu *vcpu; + trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); + vcpu = g_malloc0(sizeof(*vcpu)); vcpu->vcpu_id = kvm_arch_vcpu_id(cpu); vcpu->kvm_fd = cpu->kvm_fd; QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); } +int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) +{ + struct KVMParkedVcpu *cpu; + int kvm_fd = -ENOENT; + + QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { + if (cpu->vcpu_id == vcpu_id) { + QLIST_REMOVE(cpu, node); + kvm_fd = cpu->kvm_fd; + g_free(cpu); + } + } + + trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked"); + + return kvm_fd; +} + int kvm_create_vcpu(CPUState *cpu) { - unsigned long vcpu_id = cpu->cpu_index; + unsigned long vcpu_id = kvm_arch_vcpu_id(cpu); KVMState *s = kvm_state; - int ret; - - DPRINTF("kvm_create_vcpu\n"); + int kvm_fd; /* check if the KVM vCPU already exist but is parked */ - ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu)); - if (ret > 0) { - goto found; - } - - /* create a new KVM vcpu */ - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); - if (ret < 0) { - return ret; + kvm_fd = kvm_unpark_vcpu(s, vcpu_id); + if (kvm_fd < 0) { + /* vCPU not parked: create a new KVM vCPU */ + kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id); + if (kvm_fd < 0) { + error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id); + return kvm_fd; + } } -found: - cpu->vcpu_dirty = true; - cpu->kvm_fd = ret; + cpu->kvm_fd = kvm_fd; cpu->kvm_state = s; + cpu->vcpu_dirty = true; cpu->dirty_pages = 0; cpu->throttle_us_per_full = 0; + trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd); + return 0; } @@ -376,7 +393,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu) long mmap_size; int ret = 0; - DPRINTF("kvm_destroy_vcpu\n"); + trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); ret = kvm_arch_destroy_vcpu(cpu); if (ret < 0) { @@ -415,24 +432,6 @@ void kvm_destroy_vcpu(CPUState *cpu) } } -static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) -{ - struct KVMParkedVcpu *cpu; - - QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { - if (cpu->vcpu_id == vcpu_id) { - int kvm_fd; - - QLIST_REMOVE(cpu, node); - kvm_fd = cpu->kvm_fd; - g_free(cpu); - return kvm_fd; - } - } - - return -1; -} - int kvm_init_vcpu(CPUState *cpu, Error **errp) { KVMState *s = kvm_state; diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events index 399aaeb0ec..9c880fdcf4 100644 --- a/accel/kvm/trace-events +++ b/accel/kvm/trace-events @@ -9,6 +9,10 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p" kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" +kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d" +kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" +kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu" +kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s" kvm_irqchip_commit_routes(void) "" kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d" kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d" @@ -26,3 +30,10 @@ kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"P kvm_dirty_ring_reaper_kick(const char *reason) "%s" kvm_dirty_ring_flush(int finished) "%d" +kvm_failed_get_vcpu_mmap_size(void) "" +kvm_cpu_exec(void) "" +kvm_interrupt_exit_request(void) "" +kvm_io_window_exit(void) "" +kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32 +kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s" +kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64 diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 31af5f0e24..7ffb5e4992 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -319,6 +319,31 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test); */ bool kvm_device_supported(int vmfd, uint64_t type); +/** + * kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU + * @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created. + * + * @returns: 0 when success, errno (<0) when failed. + */ +int kvm_create_vcpu(CPUState *cpu); + +/** + * kvm_park_vcpu - Park QEMU KVM vCPU context + * @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked. + * + * @returns: none + */ +void kvm_park_vcpu(CPUState *cpu); + +/** + * kvm_unpark_vcpu - unpark QEMU KVM vCPU context + * @s: KVM State + * @vcpu_id: Architecture vCPU ID of the parked vCPU + * + * @returns: KVM fd + */ +int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id); + /* Arch specific hooks */ extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; @@ -440,8 +465,6 @@ void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len); int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, hwaddr *phys_addr); -int kvm_create_vcpu(CPUState *cpu); -void kvm_park_vcpu(CPUState *cpu); #endif /* NEED_CPU_H */ -- 2.39.1