1*3b20eb23SThomas 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 */ 43c7c9c56cSYang Zhang static int kvm_cpu_has_extint(struct kvm_vcpu *v) 44c7c9c56cSYang Zhang { 451c1a9ce9SSteve Rutherford u8 accept = kvm_apic_accept_pic_intr(v); 461c1a9ce9SSteve Rutherford 471c1a9ce9SSteve Rutherford if (accept) { 481c1a9ce9SSteve Rutherford if (irqchip_split(v->kvm)) 491c1a9ce9SSteve Rutherford return pending_userspace_extint(v); 50c7c9c56cSYang Zhang else 5190bca052SDavid Hildenbrand return v->kvm->arch.vpic->output; 521c1a9ce9SSteve Rutherford } else 53c7c9c56cSYang Zhang return 0; 54c7c9c56cSYang Zhang } 55c7c9c56cSYang Zhang 56c7c9c56cSYang Zhang /* 57c7c9c56cSYang Zhang * check if there is injectable interrupt: 58c7c9c56cSYang Zhang * when virtual interrupt delivery enabled, 59c7c9c56cSYang Zhang * interrupt from apic will handled by hardware, 60c7c9c56cSYang Zhang * we don't need to check it here. 61c7c9c56cSYang Zhang */ 62c7c9c56cSYang Zhang int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) 63c7c9c56cSYang Zhang { 6404140b41SLiran Alon /* 6504140b41SLiran Alon * FIXME: interrupt.injected represents an interrupt that it's 6604140b41SLiran Alon * side-effects have already been applied (e.g. bit from IRR 6704140b41SLiran Alon * already moved to ISR). Therefore, it is incorrect to rely 6804140b41SLiran Alon * on interrupt.injected to know if there is a pending 6904140b41SLiran Alon * interrupt in the user-mode LAPIC. 7004140b41SLiran Alon * This leads to nVMX/nSVM not be able to distinguish 7104140b41SLiran Alon * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on 7204140b41SLiran Alon * pending interrupt or should re-inject an injected 7304140b41SLiran Alon * interrupt. 7404140b41SLiran Alon */ 7535754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 7604140b41SLiran Alon return v->arch.interrupt.injected; 77c7c9c56cSYang Zhang 78c7c9c56cSYang Zhang if (kvm_cpu_has_extint(v)) 79c7c9c56cSYang Zhang return 1; 80c7c9c56cSYang Zhang 81851c1a18SLiran Alon if (!is_guest_mode(v) && kvm_vcpu_apicv_active(v)) 82c7c9c56cSYang Zhang return 0; 83c7c9c56cSYang Zhang 84c7c9c56cSYang Zhang return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 85c7c9c56cSYang Zhang } 86c7c9c56cSYang Zhang 87c7c9c56cSYang Zhang /* 88edf88417SAvi Kivity * check if there is pending interrupt without 89edf88417SAvi Kivity * intack. 90edf88417SAvi Kivity */ 91edf88417SAvi Kivity int kvm_cpu_has_interrupt(struct kvm_vcpu *v) 92edf88417SAvi Kivity { 9304140b41SLiran Alon /* 9404140b41SLiran Alon * FIXME: interrupt.injected represents an interrupt that it's 9504140b41SLiran Alon * side-effects have already been applied (e.g. bit from IRR 9604140b41SLiran Alon * already moved to ISR). Therefore, it is incorrect to rely 9704140b41SLiran Alon * on interrupt.injected to know if there is a pending 9804140b41SLiran Alon * interrupt in the user-mode LAPIC. 9904140b41SLiran Alon * This leads to nVMX/nSVM not be able to distinguish 10004140b41SLiran Alon * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on 10104140b41SLiran Alon * pending interrupt or should re-inject an injected 10204140b41SLiran Alon * interrupt. 10304140b41SLiran Alon */ 10435754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 10504140b41SLiran Alon return v->arch.interrupt.injected; 1068061823aSGleb Natapov 107c7c9c56cSYang Zhang if (kvm_cpu_has_extint(v)) 108c7c9c56cSYang Zhang return 1; 109f3200d00SGleb Natapov 110f3200d00SGleb Natapov return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 111edf88417SAvi Kivity } 112edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); 113edf88417SAvi Kivity 114edf88417SAvi Kivity /* 115c7c9c56cSYang Zhang * Read pending interrupt(from non-APIC source) 116c7c9c56cSYang Zhang * vector and intack. 117c7c9c56cSYang Zhang */ 118c7c9c56cSYang Zhang static int kvm_cpu_get_extint(struct kvm_vcpu *v) 119c7c9c56cSYang Zhang { 1201c1a9ce9SSteve Rutherford if (kvm_cpu_has_extint(v)) { 1211c1a9ce9SSteve Rutherford if (irqchip_split(v->kvm)) { 1221c1a9ce9SSteve Rutherford int vector = v->arch.pending_external_vector; 1231c1a9ce9SSteve Rutherford 1241c1a9ce9SSteve Rutherford v->arch.pending_external_vector = -1; 1251c1a9ce9SSteve Rutherford return vector; 1261c1a9ce9SSteve Rutherford } else 127c7c9c56cSYang Zhang return kvm_pic_read_irq(v->kvm); /* PIC */ 1281c1a9ce9SSteve Rutherford } else 129c7c9c56cSYang Zhang return -1; 130c7c9c56cSYang Zhang } 131c7c9c56cSYang Zhang 132c7c9c56cSYang Zhang /* 133edf88417SAvi Kivity * Read pending interrupt vector and intack. 134edf88417SAvi Kivity */ 135edf88417SAvi Kivity int kvm_cpu_get_interrupt(struct kvm_vcpu *v) 136edf88417SAvi Kivity { 137c7c9c56cSYang Zhang int vector; 138c7c9c56cSYang Zhang 13935754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 140923c61bbSGleb Natapov return v->arch.interrupt.nr; 1418061823aSGleb Natapov 142c7c9c56cSYang Zhang vector = kvm_cpu_get_extint(v); 143c7c9c56cSYang Zhang 14456cc2406SWanpeng Li if (vector != -1) 145c7c9c56cSYang Zhang return vector; /* PIC */ 146f3200d00SGleb Natapov 147f3200d00SGleb Natapov return kvm_get_apic_interrupt(v); /* APIC */ 148edf88417SAvi Kivity } 14977b0f5d6SBandan Das EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); 150edf88417SAvi Kivity 151edf88417SAvi Kivity void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) 152edf88417SAvi Kivity { 1531e3161b4SPaolo Bonzini if (lapic_in_kernel(vcpu)) 154edf88417SAvi Kivity kvm_inject_apic_timer_irqs(vcpu); 155edf88417SAvi Kivity } 156edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); 157edf88417SAvi Kivity 1582f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu) 1592f599714SMarcelo Tosatti { 1602f599714SMarcelo Tosatti __kvm_migrate_apic_timer(vcpu); 1612f599714SMarcelo Tosatti __kvm_migrate_pit_timer(vcpu); 1622f599714SMarcelo Tosatti } 163654f1f13SPeter Xu 164654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args) 165654f1f13SPeter Xu { 166654f1f13SPeter Xu bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE; 167654f1f13SPeter Xu 168654f1f13SPeter Xu return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm); 169654f1f13SPeter Xu } 170