cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

irq.c (3873B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * irq.c: API for in kernel interrupt controller
      4 * Copyright (c) 2007, Intel Corporation.
      5 * Copyright 2009 Red Hat, Inc. and/or its affiliates.
      6 *
      7 * Authors:
      8 *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
      9 */
     10
     11#include <linux/export.h>
     12#include <linux/kvm_host.h>
     13
     14#include "irq.h"
     15#include "i8254.h"
     16#include "x86.h"
     17#include "xen.h"
     18
     19/*
     20 * check if there are pending timer events
     21 * to be processed.
     22 */
     23int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
     24{
     25	int r = 0;
     26
     27	if (lapic_in_kernel(vcpu))
     28		r = apic_has_pending_timer(vcpu);
     29	if (kvm_xen_timer_enabled(vcpu))
     30		r += kvm_xen_has_pending_timer(vcpu);
     31
     32	return r;
     33}
     34EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
     35
     36/*
     37 * check if there is a pending userspace external interrupt
     38 */
     39static int pending_userspace_extint(struct kvm_vcpu *v)
     40{
     41	return v->arch.pending_external_vector != -1;
     42}
     43
     44/*
     45 * check if there is pending interrupt from
     46 * non-APIC source without intack.
     47 */
     48int kvm_cpu_has_extint(struct kvm_vcpu *v)
     49{
     50	/*
     51	 * FIXME: interrupt.injected represents an interrupt whose
     52	 * side-effects have already been applied (e.g. bit from IRR
     53	 * already moved to ISR). Therefore, it is incorrect to rely
     54	 * on interrupt.injected to know if there is a pending
     55	 * interrupt in the user-mode LAPIC.
     56	 * This leads to nVMX/nSVM not be able to distinguish
     57	 * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on
     58	 * pending interrupt or should re-inject an injected
     59	 * interrupt.
     60	 */
     61	if (!lapic_in_kernel(v))
     62		return v->arch.interrupt.injected;
     63
     64	if (kvm_xen_has_interrupt(v))
     65		return 1;
     66
     67	if (!kvm_apic_accept_pic_intr(v))
     68		return 0;
     69
     70	if (irqchip_split(v->kvm))
     71		return pending_userspace_extint(v);
     72	else
     73		return v->kvm->arch.vpic->output;
     74}
     75
     76/*
     77 * check if there is injectable interrupt:
     78 * when virtual interrupt delivery enabled,
     79 * interrupt from apic will handled by hardware,
     80 * we don't need to check it here.
     81 */
     82int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
     83{
     84	if (kvm_cpu_has_extint(v))
     85		return 1;
     86
     87	if (!is_guest_mode(v) && kvm_vcpu_apicv_active(v))
     88		return 0;
     89
     90	return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
     91}
     92EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr);
     93
     94/*
     95 * check if there is pending interrupt without
     96 * intack.
     97 */
     98int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
     99{
    100	if (kvm_cpu_has_extint(v))
    101		return 1;
    102
    103	return kvm_apic_has_interrupt(v) != -1;	/* LAPIC */
    104}
    105EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
    106
    107/*
    108 * Read pending interrupt(from non-APIC source)
    109 * vector and intack.
    110 */
    111static int kvm_cpu_get_extint(struct kvm_vcpu *v)
    112{
    113	if (!kvm_cpu_has_extint(v)) {
    114		WARN_ON(!lapic_in_kernel(v));
    115		return -1;
    116	}
    117
    118	if (!lapic_in_kernel(v))
    119		return v->arch.interrupt.nr;
    120
    121	if (kvm_xen_has_interrupt(v))
    122		return v->kvm->arch.xen.upcall_vector;
    123
    124	if (irqchip_split(v->kvm)) {
    125		int vector = v->arch.pending_external_vector;
    126
    127		v->arch.pending_external_vector = -1;
    128		return vector;
    129	} else
    130		return kvm_pic_read_irq(v->kvm); /* PIC */
    131}
    132
    133/*
    134 * Read pending interrupt vector and intack.
    135 */
    136int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
    137{
    138	int vector = kvm_cpu_get_extint(v);
    139	if (vector != -1)
    140		return vector;			/* PIC */
    141
    142	return kvm_get_apic_interrupt(v);	/* APIC */
    143}
    144EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
    145
    146void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
    147{
    148	if (lapic_in_kernel(vcpu))
    149		kvm_inject_apic_timer_irqs(vcpu);
    150	if (kvm_xen_timer_enabled(vcpu))
    151		kvm_xen_inject_timer_irqs(vcpu);
    152}
    153EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
    154
    155void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
    156{
    157	__kvm_migrate_apic_timer(vcpu);
    158	__kvm_migrate_pit_timer(vcpu);
    159	static_call_cond(kvm_x86_migrate_timers)(vcpu);
    160}
    161
    162bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
    163{
    164	bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE;
    165
    166	return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm);
    167}