From patchwork Fri May 20 17:12:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 804342 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p4KHD62r019863 for ; Fri, 20 May 2011 17:13:07 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934277Ab1ETRND (ORCPT ); Fri, 20 May 2011 13:13:03 -0400 Received: from david.siemens.de ([192.35.17.14]:20085 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933553Ab1ETRMt (ORCPT ); Fri, 20 May 2011 13:12:49 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.13.6/8.13.6) with ESMTP id p4KHChc8007269; Fri, 20 May 2011 19:12:43 +0200 Received: from mchn199C.mchp.siemens.de ([139.25.109.49]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p4KHCeFD023636; Fri, 20 May 2011 19:12:43 +0200 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org Subject: [PATCH 09/10] qemu-kvm: Use upstream kvm_cpu_exec Date: Fri, 20 May 2011 19:12:39 +0200 Message-Id: <5a3fe9039c17ca20fdc5538a84283c9d75da28ce.1305911554.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 20 May 2011 17:13:07 +0000 (UTC) Upstream's and qemu-kvm's kvm_cpu_exec are not logically equivalent so that we can safely switch the implementations. A bit refactoring of kvm_main_loop_cpu is required as upstream's cpu loop already contains the asynchronous event processing which ran outside so far. Signed-off-by: Jan Kiszka --- kvm-all.c | 3 - qemu-kvm-x86.c | 101 +----------------------- qemu-kvm.c | 225 ++++------------------------------------------------- qemu-kvm.h | 44 +---------- target-i386/kvm.c | 2 - 5 files changed, 17 insertions(+), 358 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 5ac177f..88d0785 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -958,8 +958,6 @@ void kvm_cpu_synchronize_post_init(CPUState *env) env->kvm_vcpu_dirty = 0; } -#ifdef OBSOLETE_KVM_IMPL - int kvm_cpu_exec(CPUState *env) { struct kvm_run *run = env->kvm_run; @@ -1065,7 +1063,6 @@ int kvm_cpu_exec(CPUState *env) return ret; } -#endif int kvm_ioctl(KVMState *s, int type, ...) { int ret; diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 18f7c3a..89bb692 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -49,13 +49,13 @@ static int kvm_create_pit(KVMState *s) #ifdef KVM_EXIT_TPR_ACCESS -static int kvm_handle_tpr_access(CPUState *env) +int kvm_handle_tpr_access(CPUState *env) { struct kvm_run *run = env->kvm_run; kvm_tpr_access_report(env, run->tpr_access.rip, run->tpr_access.is_write); - return 0; + return 1; } @@ -70,41 +70,6 @@ int kvm_enable_vapic(CPUState *env, uint64_t vapic) #endif -extern CPUState *kvm_debug_cpu_requested; - -int kvm_arch_run(CPUState *env) -{ - int r = 0; - struct kvm_run *run = env->kvm_run; - - switch (run->exit_reason) { -#ifdef KVM_EXIT_SET_TPR - case KVM_EXIT_SET_TPR: - break; -#endif -#ifdef KVM_EXIT_TPR_ACCESS - case KVM_EXIT_TPR_ACCESS: - r = kvm_handle_tpr_access(env); - break; -#endif -#ifdef KVM_CAP_SET_GUEST_DEBUG - case KVM_EXIT_DEBUG: - DPRINTF("kvm_exit_debug\n"); - r = kvm_handle_debug(&run->debug.arch); - if (r == EXCP_DEBUG) { - kvm_debug_cpu_requested = env; - env->stopped = 1; - } - break; -#endif /* KVM_CAP_SET_GUEST_DEBUG */ - default: - r = -1; - break; - } - - return r; -} - #ifdef KVM_CAP_IRQCHIP int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s) @@ -178,11 +143,6 @@ int kvm_set_pit2(KVMState *s, struct kvm_pit_state2 *ps2) #endif #endif -static void kvm_set_cr8(CPUState *env, uint64_t cr8) -{ - env->kvm_run->cr8 = cr8; -} - #ifdef KVM_CAP_VAPIC static int kvm_enable_tpr_access_reporting(CPUState *env) { @@ -207,63 +167,6 @@ static int _kvm_arch_init_vcpu(CPUState *env) return 0; } -int kvm_arch_halt(CPUState *env) -{ - - if (!((env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) && - !(env->interrupt_request & CPU_INTERRUPT_NMI)) { - env->halted = 1; - } - return 1; -} - -void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) -{ - if (!kvm_irqchip_in_kernel()) { - kvm_set_cr8(env, cpu_get_apic_tpr(env->apic_state)); - } -} - -int kvm_arch_try_push_interrupts(void *opaque) -{ - CPUState *env = cpu_single_env; - int r, irq; - - if (kvm_is_ready_for_interrupt_injection(env) && - (env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - irq = cpu_get_pic_interrupt(env); - if (irq >= 0) { - r = kvm_inject_irq(env, irq); - if (r < 0) { - printf("cpu %d fail inject %x\n", env->cpu_index, irq); - } - } - } - - return (env->interrupt_request & CPU_INTERRUPT_HARD) != 0; -} - -#ifdef KVM_CAP_USER_NMI -void kvm_arch_push_nmi(void) -{ - CPUState *env = cpu_single_env; - int r; - - if (likely(!(env->interrupt_request & CPU_INTERRUPT_NMI))) { - return; - } - - env->interrupt_request &= ~CPU_INTERRUPT_NMI; - r = kvm_inject_nmi(env); - if (r < 0) { - printf("cpu %d fail inject NMI\n", env->cpu_index); - } -} -#endif /* KVM_CAP_USER_NMI */ - #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT void kvm_arch_do_ioperm(void *_data) { diff --git a/qemu-kvm.c b/qemu-kvm.c index 41c4219..b2387df 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -73,31 +73,6 @@ static QLIST_HEAD(, ioperm_data) ioperm_head; #define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1)) -static int handle_unhandled(uint64_t reason) -{ - fprintf(stderr, "kvm: unhandled exit %" PRIx64 "\n", reason); - return -EINVAL; -} - -#define VMX_INVALID_GUEST_STATE 0x80000021 - -static int handle_failed_vmentry(uint64_t reason) -{ - fprintf(stderr, "kvm: vm entry failed with error 0x%" PRIx64 "\n\n", reason); - - /* Perhaps we will need to check if this machine is intel since exit reason 0x21 - has a different interpretation on SVM */ - if (reason == VMX_INVALID_GUEST_STATE) { - fprintf(stderr, "If you're runnning a guest on an Intel machine without\n"); - fprintf(stderr, "unrestricted mode support, the failure can be most likely\n"); - fprintf(stderr, "due to the guest entering an invalid state for Intel VT.\n"); - fprintf(stderr, "For example, the guest maybe running in big real mode\n"); - fprintf(stderr, "which is not supported on less recent Intel processors.\n\n"); - } - - return -EINVAL; -} - static inline void set_gsi(KVMState *s, unsigned int gsi) { uint32_t *bitmap = s->used_gsi_bitmap; @@ -244,169 +219,6 @@ int kvm_set_irqchip(KVMState *s, struct kvm_irqchip *chip) #endif -static int handle_mmio(CPUState *env) -{ - unsigned long addr = env->kvm_run->mmio.phys_addr; - struct kvm_run *kvm_run = env->kvm_run; - void *data = kvm_run->mmio.data; - - /* hack: Red Hat 7.1 generates these weird accesses. */ - if ((addr > 0xa0000 - 4 && addr <= 0xa0000) && kvm_run->mmio.len == 3) { - return 0; - } - - cpu_physical_memory_rw(addr, data, kvm_run->mmio.len, kvm_run->mmio.is_write); - return 0; -} - -static int handle_shutdown(CPUState *env) -{ - /* stop the current vcpu from going back to guest mode */ - env->stopped = 1; - - qemu_system_reset_request(); - return 1; -} - -static inline void push_nmi(void) -{ -#ifdef KVM_CAP_USER_NMI - kvm_arch_push_nmi(); -#endif /* KVM_CAP_USER_NMI */ -} - -static void post_kvm_run(CPUState *env) -{ - pthread_mutex_lock(&qemu_mutex); - cpu_single_env = env; - - kvm_arch_post_run(env, env->kvm_run); -} - -static void pre_kvm_run(CPUState *env) -{ - kvm_arch_pre_run(env, env->kvm_run); - - if (env->exit_request) { - qemu_cpu_kick_self(); - } - - cpu_single_env = NULL; - pthread_mutex_unlock(&qemu_mutex); -} - -int kvm_is_ready_for_interrupt_injection(CPUState *env) -{ - return env->kvm_run->ready_for_interrupt_injection; -} - -static int kvm_run(CPUState *env) -{ - int r; - struct kvm_run *run = env->kvm_run; - - cpu_single_env = env; - - again: - if (env->kvm_vcpu_dirty) { - kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE); - env->kvm_vcpu_dirty = 0; - } - push_nmi(); - if (!kvm_state->irqchip_in_kernel) { - run->request_interrupt_window = kvm_arch_try_push_interrupts(env); - } - - pre_kvm_run(env); - - r = kvm_vcpu_ioctl(env, KVM_RUN, 0); - - post_kvm_run(env); - - kvm_flush_coalesced_mmio_buffer(); - - if (r == -EINTR || r == -EAGAIN) { - env->exit_request = 0; - return 1; - } - if (r < 0) { - fprintf(stderr, "kvm_run: %s\n", strerror(-r)); - return r; - } - - if (1) { - switch (run->exit_reason) { - case KVM_EXIT_UNKNOWN: - r = handle_unhandled(run->hw.hardware_exit_reason); - break; - case KVM_EXIT_FAIL_ENTRY: - r = handle_failed_vmentry(run->fail_entry.hardware_entry_failure_reason); - break; - case KVM_EXIT_EXCEPTION: - fprintf(stderr, "exception %d (%x)\n", run->ex.exception, - run->ex.error_code); - cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - abort(); - break; - case KVM_EXIT_IO: - kvm_handle_io(run->io.port, - (uint8_t *)run + run->io.data_offset, - run->io.direction, - run->io.size, - run->io.count); - r = 0; - break; - case KVM_EXIT_MMIO: - r = handle_mmio(env); - break; - case KVM_EXIT_HLT: - r = kvm_arch_halt(env); - break; - case KVM_EXIT_IRQ_WINDOW_OPEN: - break; - case KVM_EXIT_SHUTDOWN: - r = handle_shutdown(env); - break; - case KVM_EXIT_INTERNAL_ERROR: - r = kvm_handle_internal_error(env, run); - break; - default: - r = kvm_arch_run(env); - if (r < 0) { - fprintf(stderr, "unhandled vm exit: 0x%x\n", run->exit_reason); - cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - abort(); - } - if (r > 0) { - return r; - } - break; - } - } - if (!r) { - goto again; - } - env->exit_request = 0; - return r; -} - -int kvm_inject_irq(CPUState *env, unsigned irq) -{ - struct kvm_interrupt intr; - - intr.irq = irq; - return kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); -} - -int kvm_inject_nmi(CPUState *env) -{ -#ifdef KVM_CAP_USER_NMI - return kvm_vcpu_ioctl(env, KVM_NMI); -#else - return -ENOSYS; -#endif -} - #ifdef KVM_CAP_DEVICE_ASSIGNMENT int kvm_assign_pci_device(KVMState *s, struct kvm_assigned_pci_dev *assigned_dev) @@ -856,20 +668,6 @@ void kvm_update_interrupt_request(CPUState *env) } } -int kvm_cpu_exec(CPUState *env) -{ - int r; - - r = kvm_run(env); - if (r < 0) { - printf("kvm_run returned %d\n", r); - cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - vm_stop(VMSTOP_PANIC); - } - - return 0; -} - static int kvm_cpu_is_stopped(CPUState *env) { return !vm_running || env->stopped; @@ -1035,16 +833,21 @@ static void qemu_kvm_system_reset(void) static int kvm_main_loop_cpu(CPUState *env) { while (1) { - int run_cpu = !kvm_cpu_is_stopped(env); - if (run_cpu) { - run_cpu = !kvm_arch_process_async_events(env); - } - if (run_cpu) { - kvm_cpu_exec(env); - kvm_main_loop_wait(env, 0); - } else { - kvm_main_loop_wait(env, 1000); + int timeout = 1000; + if (!kvm_cpu_is_stopped(env)) { + switch (kvm_cpu_exec(env)) { + case EXCP_HLT: + break; + case EXCP_DEBUG: + kvm_debug_cpu_requested = env; + env->stopped = 1; + break; + default: + timeout = 0; + break; + } } + kvm_main_loop_wait(env, timeout); } pthread_mutex_unlock(&qemu_mutex); return 0; diff --git a/qemu-kvm.h b/qemu-kvm.h index 5621cfa..57dc6aa 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -37,35 +37,8 @@ #include "kvm.h" -int kvm_arch_run(CPUState *env); - int kvm_create_irqchip(KVMState *s); -/*! - * \brief Check if a vcpu is ready for interrupt injection - * - * This checks if vcpu interrupts are not masked by mov ss or sti. - * - * \param kvm Pointer to the current kvm_context - * \param vcpu Which virtual CPU should get dumped - * \return boolean indicating interrupt injection readiness - */ -int kvm_is_ready_for_interrupt_injection(CPUState *env); - -#if defined(__i386__) || defined(__x86_64__) -/*! - * \brief Simulate an external vectored interrupt - * - * This allows you to simulate an external vectored interrupt. - * - * \param kvm Pointer to the current kvm_context - * \param vcpu Which virtual CPU should get dumped - * \param irq Vector number - * \return 0 on success - */ -int kvm_inject_irq(CPUState *env, unsigned irq); -#endif - #ifdef KVM_CAP_IRQCHIP /*! * \brief Dump in kernel IRQCHIP contents @@ -115,17 +88,6 @@ int kvm_set_lapic(CPUState *env, struct kvm_lapic_state *s); #endif -/*! - * \brief Simulate an NMI - * - * This allows you to simulate a non-maskable interrupt. - * - * \param kvm Pointer to the current kvm_context - * \param vcpu Which virtual CPU should get dumped - * \return 0 on success - */ -int kvm_inject_nmi(CPUState *env); - #endif #ifdef KVM_CAP_PIT @@ -314,8 +276,6 @@ void kvm_hpet_disable_kpit(void); void on_vcpu(CPUState *env, void (*func)(void *data), void *data); void kvm_update_interrupt_request(CPUState *env); -int kvm_arch_try_push_interrupts(void *opaque); -void kvm_arch_push_nmi(void); int kvm_set_boot_cpu_id(KVMState *s, uint32_t id); void kvm_tpr_access_report(CPUState *env, uint64_t rip, int is_write); @@ -347,9 +307,7 @@ struct ioperm_data { QLIST_ENTRY(ioperm_data) entries; }; -int kvm_arch_halt(CPUState *env); -int handle_tpr_access(void *opaque, CPUState *env, uint64_t rip, - int is_write); +int kvm_handle_tpr_access(CPUState *env); #else #define kvm_nested 0 diff --git a/target-i386/kvm.c b/target-i386/kvm.c index e98eccf..bccd87c 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1565,7 +1565,6 @@ int kvm_arch_get_registers(CPUState *env) return 0; } -#ifdef OBSOLETE_KVM_IMPL void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) { int ret; @@ -1623,7 +1622,6 @@ void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) run->cr8 = cpu_get_apic_tpr(env->apic_state); } } -#endif void kvm_arch_post_run(CPUState *env, struct kvm_run *run) {