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 */ 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 } 86*ffdf7f9eSPaolo Bonzini EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr); 87c7c9c56cSYang Zhang 88c7c9c56cSYang Zhang /* 89edf88417SAvi Kivity * check if there is pending interrupt without 90edf88417SAvi Kivity * intack. 91edf88417SAvi Kivity */ 92edf88417SAvi Kivity int kvm_cpu_has_interrupt(struct kvm_vcpu *v) 93edf88417SAvi Kivity { 9404140b41SLiran Alon /* 9504140b41SLiran Alon * FIXME: interrupt.injected represents an interrupt that it's 9604140b41SLiran Alon * side-effects have already been applied (e.g. bit from IRR 9704140b41SLiran Alon * already moved to ISR). Therefore, it is incorrect to rely 9804140b41SLiran Alon * on interrupt.injected to know if there is a pending 9904140b41SLiran Alon * interrupt in the user-mode LAPIC. 10004140b41SLiran Alon * This leads to nVMX/nSVM not be able to distinguish 10104140b41SLiran Alon * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on 10204140b41SLiran Alon * pending interrupt or should re-inject an injected 10304140b41SLiran Alon * interrupt. 10404140b41SLiran Alon */ 10535754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 10604140b41SLiran Alon return v->arch.interrupt.injected; 1078061823aSGleb Natapov 108c7c9c56cSYang Zhang if (kvm_cpu_has_extint(v)) 109c7c9c56cSYang Zhang return 1; 110f3200d00SGleb Natapov 111f3200d00SGleb Natapov return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 112edf88417SAvi Kivity } 113edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); 114edf88417SAvi Kivity 115edf88417SAvi Kivity /* 116c7c9c56cSYang Zhang * Read pending interrupt(from non-APIC source) 117c7c9c56cSYang Zhang * vector and intack. 118c7c9c56cSYang Zhang */ 119c7c9c56cSYang Zhang static int kvm_cpu_get_extint(struct kvm_vcpu *v) 120c7c9c56cSYang Zhang { 1211c1a9ce9SSteve Rutherford if (kvm_cpu_has_extint(v)) { 1221c1a9ce9SSteve Rutherford if (irqchip_split(v->kvm)) { 1231c1a9ce9SSteve Rutherford int vector = v->arch.pending_external_vector; 1241c1a9ce9SSteve Rutherford 1251c1a9ce9SSteve Rutherford v->arch.pending_external_vector = -1; 1261c1a9ce9SSteve Rutherford return vector; 1271c1a9ce9SSteve Rutherford } else 128c7c9c56cSYang Zhang return kvm_pic_read_irq(v->kvm); /* PIC */ 1291c1a9ce9SSteve Rutherford } else 130c7c9c56cSYang Zhang return -1; 131c7c9c56cSYang Zhang } 132c7c9c56cSYang Zhang 133c7c9c56cSYang Zhang /* 134edf88417SAvi Kivity * Read pending interrupt vector and intack. 135edf88417SAvi Kivity */ 136edf88417SAvi Kivity int kvm_cpu_get_interrupt(struct kvm_vcpu *v) 137edf88417SAvi Kivity { 138c7c9c56cSYang Zhang int vector; 139c7c9c56cSYang Zhang 14035754c98SPaolo Bonzini if (!lapic_in_kernel(v)) 141923c61bbSGleb Natapov return v->arch.interrupt.nr; 1428061823aSGleb Natapov 143c7c9c56cSYang Zhang vector = kvm_cpu_get_extint(v); 144c7c9c56cSYang Zhang 14556cc2406SWanpeng Li if (vector != -1) 146c7c9c56cSYang Zhang return vector; /* PIC */ 147f3200d00SGleb Natapov 148f3200d00SGleb Natapov return kvm_get_apic_interrupt(v); /* APIC */ 149edf88417SAvi Kivity } 15077b0f5d6SBandan Das EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); 151edf88417SAvi Kivity 152edf88417SAvi Kivity void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) 153edf88417SAvi Kivity { 1541e3161b4SPaolo Bonzini if (lapic_in_kernel(vcpu)) 155edf88417SAvi Kivity kvm_inject_apic_timer_irqs(vcpu); 156edf88417SAvi Kivity } 157edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); 158edf88417SAvi Kivity 1592f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu) 1602f599714SMarcelo Tosatti { 1612f599714SMarcelo Tosatti __kvm_migrate_apic_timer(vcpu); 1622f599714SMarcelo Tosatti __kvm_migrate_pit_timer(vcpu); 16393dff2feSJim Mattson if (kvm_x86_ops.migrate_timers) 16493dff2feSJim Mattson kvm_x86_ops.migrate_timers(vcpu); 1652f599714SMarcelo Tosatti } 166654f1f13SPeter Xu 167654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args) 168654f1f13SPeter Xu { 169654f1f13SPeter Xu bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE; 170654f1f13SPeter Xu 171654f1f13SPeter Xu return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm); 172654f1f13SPeter Xu } 173