From: Zenghui Yu yuzenghui@huawei.com
virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8URKX CVE: NA
------------------------------------------------------------------
Having the vtimer_irqbypass flag in the per-vcpu structure is actually pointless, as we will keep the vtimer interrupt delivery capability the same among all vcpus (either direct injection via MBIGEN-ITS-RDist, or purely emulated by KVM).
Let's instead make it a Distributor attribute. This way, we configure the vtimer information for *all* vcpus in kvm_vtimer_config(), in one go. Otherwise we need to configure it for each vcpu in its first run (we may end-up missing the activation of vtimer interrupt for some vcpus whose vtimer_info hasn't been configures yet, and bad things will happen...).
Signed-off-by: Zenghui Yu yuzenghui@huawei.com Signed-off-by: Kunkun Jiang jiangkunkun@huawei.com Signed-off-by: Dongxu Sun sundongxu3@huawei.com --- arch/arm64/include/asm/kvm_emulate.h | 2 +- arch/arm64/kvm/arch_timer.c | 39 ++++++++++++++++++++-------- arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/vgic/vgic-v4.c | 7 ++--- arch/arm64/kvm/vgic/vgic.c | 4 +-- include/kvm/arm_arch_timer.h | 2 +- include/kvm/arm_vgic.h | 5 ++-- 7 files changed, 39 insertions(+), 22 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 60a88c557191..b498b8070347 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -112,7 +112,7 @@ static inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu) { vcpu->arch.hcr_el2 &= ~HCR_TWE; if (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) || - vcpu->arch.vgic_cpu.vtimer_irqbypass || + vcpu->kvm->arch.vgic.vtimer_irqbypass || vcpu->kvm->arch.vgic.nassgireq) vcpu->arch.hcr_el2 &= ~HCR_TWI; else diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 41323aed82bd..8128c2798a34 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -1665,24 +1665,41 @@ static bool vtimer_get_active_stat(struct kvm_vcpu *vcpu, int vintid) return vtimer_mbigen_get_active(vcpu->cpu); }
-int kvm_vtimer_config(struct kvm_vcpu *vcpu) +int kvm_vtimer_config(struct kvm *kvm) { - struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; - int intid; + struct vgic_dist *dist = &kvm->arch.vgic; + struct kvm_vcpu *vcpu; + int ret = 0; + unsigned long c;
if (!vtimer_is_irqbypass()) return 0;
- if (timer->enabled) - return 0; - - if (!irqchip_in_kernel(vcpu->kvm)) + if (!irqchip_in_kernel(kvm)) return -EINVAL; + mutex_lock(&kvm->lock); + if (dist->vtimer_irqbypass) + goto out;
- intid = timer_irq(vcpu_vtimer(vcpu)); - return kvm_vgic_config_vtimer_irqbypass(vcpu, intid, - vtimer_get_active_stat, - vtimer_set_active_stat); + kvm_for_each_vcpu(c, vcpu, kvm) { + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; + int intid; + + WARN_ON(timer->enabled); + + intid = timer_irq(vcpu_vtimer(vcpu)); + ret = kvm_vgic_config_vtimer_irqbypass(vcpu, intid, + vtimer_get_active_stat, + vtimer_set_active_stat); + if (ret) + goto out; + } + + dist->vtimer_irqbypass = true; + +out: + mutex_unlock(&kvm->lock); + return ret; }
int kvm_timer_enable(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 0377276b7d28..731608f5c8c5 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -603,7 +603,7 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
kvm_arm_vcpu_init_debug(vcpu);
- ret = kvm_vtimer_config(vcpu); + ret = kvm_vtimer_config(kvm); if (ret) return ret;
diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c index b479f694cf70..597ef0a41694 100644 --- a/arch/arm64/kvm/vgic/vgic-v4.c +++ b/arch/arm64/kvm/vgic/vgic-v4.c @@ -213,9 +213,6 @@ static void vgic_v4_enable_vtimer(struct kvm_vcpu *vcpu) struct irq_desc *desc; int ret;
- if (!vgic_cpu->vtimer_irqbypass) - return; - irq = vgic_get_irq(vcpu->kvm, vcpu, vtimer->intid); irq->host_irq = irq_find_mapping(vpe->sgi_domain, vtimer->intid);
@@ -243,9 +240,13 @@ static void vgic_v4_enable_vtimer(struct kvm_vcpu *vcpu) /* Must be called with the kvm lock held */ void vgic_v4_configure_vtimer(struct kvm *kvm) { + struct vgic_dist *dist = &kvm->arch.vgic; struct kvm_vcpu *vcpu; unsigned long i;
+ if (!dist->vtimer_irqbypass) + return; + kvm_for_each_vcpu(i, vcpu, kvm) vgic_v4_enable_vtimer(vcpu); } diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index a7444ce63fad..8b70d87e7786 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -600,9 +600,7 @@ int kvm_vgic_config_vtimer_irqbypass(struct kvm_vcpu *vcpu, u32 vintid, unsigned long flags;
if (WARN_ON_ONCE(!irq || !kvm_vgic_vtimer_irqbypass_support())) - return -EINVAL; - - vgic_cpu->vtimer_irqbypass = true; + return -EINVAL;
vtimer->intid = vintid; vtimer->get_active_stat = get_as; diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index c2edcd0be88b..d9946067dd4e 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -106,7 +106,7 @@ struct arch_timer_cpu {
int __init kvm_timer_hyp_init(bool has_gic); int kvm_timer_enable(struct kvm_vcpu *vcpu); -int kvm_vtimer_config(struct kvm_vcpu *vcpu); +int kvm_vtimer_config(struct kvm *kvm); int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu); void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); void kvm_timer_sync_user(struct kvm_vcpu *vcpu); diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 3f1b88cf1402..b0a4bdbebd16 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -276,6 +276,9 @@ struct vgic_dist { /* Wants SGIs without active state */ bool nassgireq;
+ /* Indicate whether the vtimer irqbypass mode is used */ + bool vtimer_irqbypass; + struct vgic_irq *spis;
struct vgic_io_device dist_iodev; @@ -349,8 +352,6 @@ struct vgic_cpu {
struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
- /* Indicate whether the vtimer irqbypass mode is used */ - bool vtimer_irqbypass; struct vtimer_info vtimer;
raw_spinlock_t ap_list_lock; /* Protects the ap_list */