13b20eb23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2edf88417SAvi Kivity /* 3edf88417SAvi Kivity * irq.c: API for in kernel interrupt controller 4edf88417SAvi Kivity * Copyright (c) 2007, Intel Corporation. 59611c187SNicolas Kaiser * Copyright 2009 Red Hat, Inc. and/or its affiliates. 6edf88417SAvi Kivity * 7edf88417SAvi Kivity * Authors: 8edf88417SAvi Kivity * Yaozu (Eddie) Dong <Eddie.dong@intel.com> 9edf88417SAvi Kivity */ 10edf88417SAvi Kivity 111767e931SPaul Gortmaker #include <linux/export.h> 12edf88417SAvi Kivity #include <linux/kvm_host.h> 13edf88417SAvi Kivity 14edf88417SAvi Kivity #include "irq.h" 157837699fSSheng Yang #include "i8254.h" 168061823aSGleb Natapov #include "x86.h" 17edf88417SAvi Kivity 18edf88417SAvi Kivity /* 193d80840dSMarcelo Tosatti * check if there are pending timer events 203d80840dSMarcelo Tosatti * to be processed. 213d80840dSMarcelo Tosatti */ 223d80840dSMarcelo Tosatti int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 233d80840dSMarcelo Tosatti { 241e3161b4SPaolo Bonzini if (lapic_in_kernel(vcpu)) 2523e7a794SJason Wang return apic_has_pending_timer(vcpu); 261e3161b4SPaolo Bonzini 271e3161b4SPaolo Bonzini return 0; 283d80840dSMarcelo Tosatti } 293d80840dSMarcelo Tosatti EXPORT_SYMBOL(kvm_cpu_has_pending_timer); 303d80840dSMarcelo Tosatti 313d80840dSMarcelo Tosatti /* 321c1a9ce9SSteve Rutherford * check if there is a pending userspace external interrupt 331c1a9ce9SSteve Rutherford */ 341c1a9ce9SSteve Rutherford static int pending_userspace_extint(struct kvm_vcpu *v) 351c1a9ce9SSteve Rutherford { 361c1a9ce9SSteve Rutherford return v->arch.pending_external_vector != -1; 371c1a9ce9SSteve Rutherford } 381c1a9ce9SSteve Rutherford 391c1a9ce9SSteve Rutherford /* 40c7c9c56cSYang Zhang * check if there is pending interrupt from 41c7c9c56cSYang Zhang * non-APIC source without intack. 42c7c9c56cSYang Zhang */ 4371cc849bSPaolo Bonzini int kvm_cpu_has_extint(struct kvm_vcpu *v) 44c7c9c56cSYang Zhang { 45c7c9c56cSYang Zhang /* 4672c3bcdcSPaolo Bonzini * FIXME: interrupt.injected represents an interrupt whose 4704140b41SLiran Alon * side-effects have already been applied (e.g. bit from IRR 4804140b41SLiran Alon * already moved to ISR). Therefore, it is incorrect to rely 4904140b41SLiran Alon * on interrupt.injected to know if there is a pending 5004140b41SLiran Alon * interrupt in the user-mode LAPIC. 5104140b41SLiran Alon * This leads to nVMX/nSVM not be able to distinguish 5204140b41SLiran Alon * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on 5304140b41SLiran Alon * pending interrupt or should re-inject an injected 5404140b41SLiran Alon * interrupt. 5504140b41SLiran Alon */ 5635754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 5704140b41SLiran Alon return v->arch.interrupt.injected; 58c7c9c56cSYang Zhang 5972c3bcdcSPaolo Bonzini if (!kvm_apic_accept_pic_intr(v)) 6072c3bcdcSPaolo Bonzini return 0; 6172c3bcdcSPaolo Bonzini 6272c3bcdcSPaolo Bonzini if (irqchip_split(v->kvm)) 6372c3bcdcSPaolo Bonzini return pending_userspace_extint(v); 6472c3bcdcSPaolo Bonzini else 6572c3bcdcSPaolo Bonzini return v->kvm->arch.vpic->output; 6672c3bcdcSPaolo Bonzini } 6772c3bcdcSPaolo Bonzini 6872c3bcdcSPaolo Bonzini /* 6972c3bcdcSPaolo Bonzini * check if there is injectable interrupt: 7072c3bcdcSPaolo Bonzini * when virtual interrupt delivery enabled, 7172c3bcdcSPaolo Bonzini * interrupt from apic will handled by hardware, 7272c3bcdcSPaolo Bonzini * we don't need to check it here. 7372c3bcdcSPaolo Bonzini */ 7472c3bcdcSPaolo Bonzini int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) 7572c3bcdcSPaolo Bonzini { 76c7c9c56cSYang Zhang if (kvm_cpu_has_extint(v)) 77c7c9c56cSYang Zhang return 1; 78c7c9c56cSYang Zhang 79851c1a18SLiran Alon if (!is_guest_mode(v) && kvm_vcpu_apicv_active(v)) 80c7c9c56cSYang Zhang return 0; 81c7c9c56cSYang Zhang 82c7c9c56cSYang Zhang return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 83c7c9c56cSYang Zhang } 84ffdf7f9eSPaolo Bonzini EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr); 85c7c9c56cSYang Zhang 86c7c9c56cSYang Zhang /* 87edf88417SAvi Kivity * check if there is pending interrupt without 88edf88417SAvi Kivity * intack. 89edf88417SAvi Kivity */ 90edf88417SAvi Kivity int kvm_cpu_has_interrupt(struct kvm_vcpu *v) 91edf88417SAvi Kivity { 92c7c9c56cSYang Zhang if (kvm_cpu_has_extint(v)) 93c7c9c56cSYang Zhang return 1; 94f3200d00SGleb Natapov 95f3200d00SGleb Natapov return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 96edf88417SAvi Kivity } 97edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); 98edf88417SAvi Kivity 99edf88417SAvi Kivity /* 100c7c9c56cSYang Zhang * Read pending interrupt(from non-APIC source) 101c7c9c56cSYang Zhang * vector and intack. 102c7c9c56cSYang Zhang */ 103c7c9c56cSYang Zhang static int kvm_cpu_get_extint(struct kvm_vcpu *v) 104c7c9c56cSYang Zhang { 10572c3bcdcSPaolo Bonzini if (!kvm_cpu_has_extint(v)) { 10672c3bcdcSPaolo Bonzini WARN_ON(!lapic_in_kernel(v)); 10772c3bcdcSPaolo Bonzini return -1; 10872c3bcdcSPaolo Bonzini } 10972c3bcdcSPaolo Bonzini 11072c3bcdcSPaolo Bonzini if (!lapic_in_kernel(v)) 11172c3bcdcSPaolo Bonzini return v->arch.interrupt.nr; 11272c3bcdcSPaolo Bonzini 1131c1a9ce9SSteve Rutherford if (irqchip_split(v->kvm)) { 1141c1a9ce9SSteve Rutherford int vector = v->arch.pending_external_vector; 1151c1a9ce9SSteve Rutherford 1161c1a9ce9SSteve Rutherford v->arch.pending_external_vector = -1; 1171c1a9ce9SSteve Rutherford return vector; 1181c1a9ce9SSteve Rutherford } else 119c7c9c56cSYang Zhang return kvm_pic_read_irq(v->kvm); /* PIC */ 120c7c9c56cSYang Zhang } 121c7c9c56cSYang Zhang 122c7c9c56cSYang Zhang /* 123edf88417SAvi Kivity * Read pending interrupt vector and intack. 124edf88417SAvi Kivity */ 125edf88417SAvi Kivity int kvm_cpu_get_interrupt(struct kvm_vcpu *v) 126edf88417SAvi Kivity { 12772c3bcdcSPaolo Bonzini int vector = kvm_cpu_get_extint(v); 12856cc2406SWanpeng Li if (vector != -1) 129c7c9c56cSYang Zhang return vector; /* PIC */ 130f3200d00SGleb Natapov 131f3200d00SGleb Natapov return kvm_get_apic_interrupt(v); /* APIC */ 132edf88417SAvi Kivity } 13377b0f5d6SBandan Das EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); 134edf88417SAvi Kivity 135edf88417SAvi Kivity void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) 136edf88417SAvi Kivity { 1371e3161b4SPaolo Bonzini if (lapic_in_kernel(vcpu)) 138edf88417SAvi Kivity kvm_inject_apic_timer_irqs(vcpu); 139edf88417SAvi Kivity } 140edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); 141edf88417SAvi Kivity 1422f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu) 1432f599714SMarcelo Tosatti { 1442f599714SMarcelo Tosatti __kvm_migrate_apic_timer(vcpu); 1452f599714SMarcelo Tosatti __kvm_migrate_pit_timer(vcpu); 146*b3646477SJason Baron static_call_cond(kvm_x86_migrate_timers)(vcpu); 1472f599714SMarcelo Tosatti } 148654f1f13SPeter Xu 149654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args) 150654f1f13SPeter Xu { 151654f1f13SPeter Xu bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE; 152654f1f13SPeter Xu 153654f1f13SPeter Xu return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm); 154654f1f13SPeter Xu } 155