diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2015-06-18 18:47:23 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-07-01 15:45:51 +0200 |
commit | 4b8523ee896750c37b4fa224a40d34703cbdf4c6 (patch) | |
tree | 1083d1e6c59b33c68808094d4b6844ddf935c9f0 /target-i386 | |
parent | 4840f10eff37eebc609fcc933ab985dc66df95c6 (diff) | |
download | hqemu-4b8523ee896750c37b4fa224a40d34703cbdf4c6.zip hqemu-4b8523ee896750c37b4fa224a40d34703cbdf4c6.tar.gz |
kvm: First step to push iothread lock out of inner run loop
This opens the path to get rid of the iothread lock on vmexits in KVM
mode. On x86, the in-kernel irqchips has to be used because we otherwise
need to synchronize APIC and other per-cpu state accesses that could be
changed concurrently.
Regarding pre/post-run callbacks, s390x and ARM should be fine without
specific locking as the callbacks are empty. MIPS and POWER require
locking for the pre-run callback.
For the handle_exit callback, it is non-empty in x86, POWER and s390.
Some POWER cases could do without the locking, but it is left in
place for now.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1434646046-27150-7-git-send-email-pbonzini@redhat.com>
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/kvm.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/target-i386/kvm.c b/target-i386/kvm.c index daced5c..6426600 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -2191,7 +2191,10 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) /* Inject NMI */ if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { + qemu_mutex_lock_iothread(); cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; + qemu_mutex_unlock_iothread(); + DPRINTF("injected NMI\n"); ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { @@ -2200,6 +2203,10 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) } } + if (!kvm_irqchip_in_kernel()) { + qemu_mutex_lock_iothread(); + } + /* Force the VCPU out of its inner loop to process any INIT requests * or (for userspace APIC, but it is cheap to combine the checks here) * pending TPR access reports. @@ -2243,6 +2250,8 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) DPRINTF("setting tpr\n"); run->cr8 = cpu_get_apic_tpr(x86_cpu->apic_state); + + qemu_mutex_unlock_iothread(); } } @@ -2256,8 +2265,17 @@ MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) } else { env->eflags &= ~IF_MASK; } + + /* We need to protect the apic state against concurrent accesses from + * different threads in case the userspace irqchip is used. */ + if (!kvm_irqchip_in_kernel()) { + qemu_mutex_lock_iothread(); + } cpu_set_apic_tpr(x86_cpu->apic_state, run->cr8); cpu_set_apic_base(x86_cpu->apic_state, run->apic_base); + if (!kvm_irqchip_in_kernel()) { + qemu_mutex_unlock_iothread(); + } return cpu_get_mem_attrs(env); } @@ -2550,13 +2568,17 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) switch (run->exit_reason) { case KVM_EXIT_HLT: DPRINTF("handle_hlt\n"); + qemu_mutex_lock_iothread(); ret = kvm_handle_halt(cpu); + qemu_mutex_unlock_iothread(); break; case KVM_EXIT_SET_TPR: ret = 0; break; case KVM_EXIT_TPR_ACCESS: + qemu_mutex_lock_iothread(); ret = kvm_handle_tpr_access(cpu); + qemu_mutex_unlock_iothread(); break; case KVM_EXIT_FAIL_ENTRY: code = run->fail_entry.hardware_entry_failure_reason; @@ -2582,7 +2604,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; case KVM_EXIT_DEBUG: DPRINTF("kvm_exit_debug\n"); + qemu_mutex_lock_iothread(); ret = kvm_handle_debug(cpu, &run->debug.arch); + qemu_mutex_unlock_iothread(); break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); |