18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h> 48c2ecf20Sopenharmony_ci#include <linux/kvm.h> 58c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 68c2ecf20Sopenharmony_ci#include <kvm/arm_vgic.h> 78c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h> 88c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 98c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "vgic.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic bool group0_trap; 148c2ecf20Sopenharmony_cistatic bool group1_trap; 158c2ecf20Sopenharmony_cistatic bool common_trap; 168c2ecf20Sopenharmony_cistatic bool gicv4_enable; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_civoid vgic_v3_set_underflow(struct kvm_vcpu *vcpu) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci cpuif->vgic_hcr |= ICH_HCR_UIE; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic bool lr_signals_eoi_mi(u64 lr_val) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) && 288c2ecf20Sopenharmony_ci !(lr_val & ICH_LR_HW); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_civoid vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 348c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; 358c2ecf20Sopenharmony_ci u32 model = vcpu->kvm->arch.vgic.vgic_model; 368c2ecf20Sopenharmony_ci int lr; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci DEBUG_SPINLOCK_BUG_ON(!irqs_disabled()); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci cpuif->vgic_hcr &= ~ICH_HCR_UIE; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci for (lr = 0; lr < cpuif->used_lrs; lr++) { 438c2ecf20Sopenharmony_ci u64 val = cpuif->vgic_lr[lr]; 448c2ecf20Sopenharmony_ci u32 intid, cpuid; 458c2ecf20Sopenharmony_ci struct vgic_irq *irq; 468c2ecf20Sopenharmony_ci bool is_v2_sgi = false; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci cpuid = val & GICH_LR_PHYSID_CPUID; 498c2ecf20Sopenharmony_ci cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (model == KVM_DEV_TYPE_ARM_VGIC_V3) { 528c2ecf20Sopenharmony_ci intid = val & ICH_LR_VIRTUAL_ID_MASK; 538c2ecf20Sopenharmony_ci } else { 548c2ecf20Sopenharmony_ci intid = val & GICH_LR_VIRTUALID; 558c2ecf20Sopenharmony_ci is_v2_sgi = vgic_irq_is_sgi(intid); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* Notify fds when the guest EOI'ed a level-triggered IRQ */ 598c2ecf20Sopenharmony_ci if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid)) 608c2ecf20Sopenharmony_ci kvm_notify_acked_irq(vcpu->kvm, 0, 618c2ecf20Sopenharmony_ci intid - VGIC_NR_PRIVATE_IRQS); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci irq = vgic_get_irq(vcpu->kvm, vcpu, intid); 648c2ecf20Sopenharmony_ci if (!irq) /* An LPI could have been unmapped. */ 658c2ecf20Sopenharmony_ci continue; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci raw_spin_lock(&irq->irq_lock); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Always preserve the active bit */ 708c2ecf20Sopenharmony_ci irq->active = !!(val & ICH_LR_ACTIVE_BIT); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (irq->active && is_v2_sgi) 738c2ecf20Sopenharmony_ci irq->active_source = cpuid; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Edge is the only case where we preserve the pending bit */ 768c2ecf20Sopenharmony_ci if (irq->config == VGIC_CONFIG_EDGE && 778c2ecf20Sopenharmony_ci (val & ICH_LR_PENDING_BIT)) { 788c2ecf20Sopenharmony_ci irq->pending_latch = true; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (is_v2_sgi) 818c2ecf20Sopenharmony_ci irq->source |= (1 << cpuid); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * Clear soft pending state when level irqs have been acked. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci if (irq->config == VGIC_CONFIG_LEVEL && !(val & ICH_LR_STATE)) 888c2ecf20Sopenharmony_ci irq->pending_latch = false; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Level-triggered mapped IRQs are special because we only 928c2ecf20Sopenharmony_ci * observe rising edges as input to the VGIC. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * If the guest never acked the interrupt we have to sample 958c2ecf20Sopenharmony_ci * the physical line and set the line level, because the 968c2ecf20Sopenharmony_ci * device state could have changed or we simply need to 978c2ecf20Sopenharmony_ci * process the still pending interrupt later. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * If this causes us to lower the level, we have to also clear 1008c2ecf20Sopenharmony_ci * the physical active state, since we will otherwise never be 1018c2ecf20Sopenharmony_ci * told when the interrupt becomes asserted again. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) { 1048c2ecf20Sopenharmony_ci irq->line_level = vgic_get_phys_line_level(irq); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (!irq->line_level) 1078c2ecf20Sopenharmony_ci vgic_irq_set_phys_active(irq, false); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci raw_spin_unlock(&irq->irq_lock); 1118c2ecf20Sopenharmony_ci vgic_put_irq(vcpu->kvm, irq); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci cpuif->used_lrs = 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Requires the irq to be locked already */ 1188c2ecf20Sopenharmony_civoid vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci u32 model = vcpu->kvm->arch.vgic.vgic_model; 1218c2ecf20Sopenharmony_ci u64 val = irq->intid; 1228c2ecf20Sopenharmony_ci bool allow_pending = true, is_v2_sgi; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci is_v2_sgi = (vgic_irq_is_sgi(irq->intid) && 1258c2ecf20Sopenharmony_ci model == KVM_DEV_TYPE_ARM_VGIC_V2); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (irq->active) { 1288c2ecf20Sopenharmony_ci val |= ICH_LR_ACTIVE_BIT; 1298c2ecf20Sopenharmony_ci if (is_v2_sgi) 1308c2ecf20Sopenharmony_ci val |= irq->active_source << GICH_LR_PHYSID_CPUID_SHIFT; 1318c2ecf20Sopenharmony_ci if (vgic_irq_is_multi_sgi(irq)) { 1328c2ecf20Sopenharmony_ci allow_pending = false; 1338c2ecf20Sopenharmony_ci val |= ICH_LR_EOI; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (irq->hw) { 1388c2ecf20Sopenharmony_ci val |= ICH_LR_HW; 1398c2ecf20Sopenharmony_ci val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT; 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * Never set pending+active on a HW interrupt, as the 1428c2ecf20Sopenharmony_ci * pending state is kept at the physical distributor 1438c2ecf20Sopenharmony_ci * level. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci if (irq->active) 1468c2ecf20Sopenharmony_ci allow_pending = false; 1478c2ecf20Sopenharmony_ci } else { 1488c2ecf20Sopenharmony_ci if (irq->config == VGIC_CONFIG_LEVEL) { 1498c2ecf20Sopenharmony_ci val |= ICH_LR_EOI; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * Software resampling doesn't work very well 1538c2ecf20Sopenharmony_ci * if we allow P+A, so let's not do that. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci if (irq->active) 1568c2ecf20Sopenharmony_ci allow_pending = false; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (allow_pending && irq_is_pending(irq)) { 1618c2ecf20Sopenharmony_ci val |= ICH_LR_PENDING_BIT; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (irq->config == VGIC_CONFIG_EDGE) 1648c2ecf20Sopenharmony_ci irq->pending_latch = false; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (vgic_irq_is_sgi(irq->intid) && 1678c2ecf20Sopenharmony_ci model == KVM_DEV_TYPE_ARM_VGIC_V2) { 1688c2ecf20Sopenharmony_ci u32 src = ffs(irq->source); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n", 1718c2ecf20Sopenharmony_ci irq->intid)) 1728c2ecf20Sopenharmony_ci return; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT; 1758c2ecf20Sopenharmony_ci irq->source &= ~(1 << (src - 1)); 1768c2ecf20Sopenharmony_ci if (irq->source) { 1778c2ecf20Sopenharmony_ci irq->pending_latch = true; 1788c2ecf20Sopenharmony_ci val |= ICH_LR_EOI; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Level-triggered mapped IRQs are special because we only observe 1858c2ecf20Sopenharmony_ci * rising edges as input to the VGIC. We therefore lower the line 1868c2ecf20Sopenharmony_ci * level here, so that we can take new virtual IRQs. See 1878c2ecf20Sopenharmony_ci * vgic_v3_fold_lr_state for more info. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) 1908c2ecf20Sopenharmony_ci irq->line_level = false; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (irq->group) 1938c2ecf20Sopenharmony_ci val |= ICH_LR_GROUP; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_civoid vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_civoid vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; 2088c2ecf20Sopenharmony_ci u32 model = vcpu->kvm->arch.vgic.vgic_model; 2098c2ecf20Sopenharmony_ci u32 vmcr; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (model == KVM_DEV_TYPE_ARM_VGIC_V2) { 2128c2ecf20Sopenharmony_ci vmcr = (vmcrp->ackctl << ICH_VMCR_ACK_CTL_SHIFT) & 2138c2ecf20Sopenharmony_ci ICH_VMCR_ACK_CTL_MASK; 2148c2ecf20Sopenharmony_ci vmcr |= (vmcrp->fiqen << ICH_VMCR_FIQ_EN_SHIFT) & 2158c2ecf20Sopenharmony_ci ICH_VMCR_FIQ_EN_MASK; 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * When emulating GICv3 on GICv3 with SRE=1 on the 2198c2ecf20Sopenharmony_ci * VFIQEn bit is RES1 and the VAckCtl bit is RES0. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci vmcr = ICH_VMCR_FIQ_EN_MASK; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci vmcr |= (vmcrp->cbpr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK; 2258c2ecf20Sopenharmony_ci vmcr |= (vmcrp->eoim << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK; 2268c2ecf20Sopenharmony_ci vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK; 2278c2ecf20Sopenharmony_ci vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK; 2288c2ecf20Sopenharmony_ci vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK; 2298c2ecf20Sopenharmony_ci vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK; 2308c2ecf20Sopenharmony_ci vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci cpu_if->vgic_vmcr = vmcr; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_civoid vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; 2388c2ecf20Sopenharmony_ci u32 model = vcpu->kvm->arch.vgic.vgic_model; 2398c2ecf20Sopenharmony_ci u32 vmcr; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci vmcr = cpu_if->vgic_vmcr; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (model == KVM_DEV_TYPE_ARM_VGIC_V2) { 2448c2ecf20Sopenharmony_ci vmcrp->ackctl = (vmcr & ICH_VMCR_ACK_CTL_MASK) >> 2458c2ecf20Sopenharmony_ci ICH_VMCR_ACK_CTL_SHIFT; 2468c2ecf20Sopenharmony_ci vmcrp->fiqen = (vmcr & ICH_VMCR_FIQ_EN_MASK) >> 2478c2ecf20Sopenharmony_ci ICH_VMCR_FIQ_EN_SHIFT; 2488c2ecf20Sopenharmony_ci } else { 2498c2ecf20Sopenharmony_ci /* 2508c2ecf20Sopenharmony_ci * When emulating GICv3 on GICv3 with SRE=1 on the 2518c2ecf20Sopenharmony_ci * VFIQEn bit is RES1 and the VAckCtl bit is RES0. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci vmcrp->fiqen = 1; 2548c2ecf20Sopenharmony_ci vmcrp->ackctl = 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci vmcrp->cbpr = (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT; 2588c2ecf20Sopenharmony_ci vmcrp->eoim = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT; 2598c2ecf20Sopenharmony_ci vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT; 2608c2ecf20Sopenharmony_ci vmcrp->bpr = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT; 2618c2ecf20Sopenharmony_ci vmcrp->pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT; 2628c2ecf20Sopenharmony_ci vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT; 2638c2ecf20Sopenharmony_ci vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci#define INITIAL_PENDBASER_VALUE \ 2678c2ecf20Sopenharmony_ci (GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWb) | \ 2688c2ecf20Sopenharmony_ci GIC_BASER_CACHEABILITY(GICR_PENDBASER, OUTER, SameAsInner) | \ 2698c2ecf20Sopenharmony_ci GIC_BASER_SHAREABILITY(GICR_PENDBASER, InnerShareable)) 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_civoid vgic_v3_enable(struct kvm_vcpu *vcpu) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * By forcing VMCR to zero, the GIC will restore the binary 2778c2ecf20Sopenharmony_ci * points to their reset values. Anything else resets to zero 2788c2ecf20Sopenharmony_ci * anyway. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci vgic_v3->vgic_vmcr = 0; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * If we are emulating a GICv3, we do it in an non-GICv2-compatible 2848c2ecf20Sopenharmony_ci * way, so we force SRE to 1 to demonstrate this to the guest. 2858c2ecf20Sopenharmony_ci * Also, we don't support any form of IRQ/FIQ bypass. 2868c2ecf20Sopenharmony_ci * This goes with the spec allowing the value to be RAO/WI. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { 2898c2ecf20Sopenharmony_ci vgic_v3->vgic_sre = (ICC_SRE_EL1_DIB | 2908c2ecf20Sopenharmony_ci ICC_SRE_EL1_DFB | 2918c2ecf20Sopenharmony_ci ICC_SRE_EL1_SRE); 2928c2ecf20Sopenharmony_ci vcpu->arch.vgic_cpu.pendbaser = INITIAL_PENDBASER_VALUE; 2938c2ecf20Sopenharmony_ci } else { 2948c2ecf20Sopenharmony_ci vgic_v3->vgic_sre = 0; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 & 2988c2ecf20Sopenharmony_ci ICH_VTR_ID_BITS_MASK) >> 2998c2ecf20Sopenharmony_ci ICH_VTR_ID_BITS_SHIFT; 3008c2ecf20Sopenharmony_ci vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 & 3018c2ecf20Sopenharmony_ci ICH_VTR_PRI_BITS_MASK) >> 3028c2ecf20Sopenharmony_ci ICH_VTR_PRI_BITS_SHIFT) + 1; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Get the show on the road... */ 3058c2ecf20Sopenharmony_ci vgic_v3->vgic_hcr = ICH_HCR_EN; 3068c2ecf20Sopenharmony_ci if (group0_trap) 3078c2ecf20Sopenharmony_ci vgic_v3->vgic_hcr |= ICH_HCR_TALL0; 3088c2ecf20Sopenharmony_ci if (group1_trap) 3098c2ecf20Sopenharmony_ci vgic_v3->vgic_hcr |= ICH_HCR_TALL1; 3108c2ecf20Sopenharmony_ci if (common_trap) 3118c2ecf20Sopenharmony_ci vgic_v3->vgic_hcr |= ICH_HCR_TC; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciint vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 3178c2ecf20Sopenharmony_ci int byte_offset, bit_nr; 3188c2ecf20Sopenharmony_ci gpa_t pendbase, ptr; 3198c2ecf20Sopenharmony_ci bool status; 3208c2ecf20Sopenharmony_ci u8 val; 3218c2ecf20Sopenharmony_ci int ret; 3228c2ecf20Sopenharmony_ci unsigned long flags; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ciretry: 3258c2ecf20Sopenharmony_ci vcpu = irq->target_vcpu; 3268c2ecf20Sopenharmony_ci if (!vcpu) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci byte_offset = irq->intid / BITS_PER_BYTE; 3328c2ecf20Sopenharmony_ci bit_nr = irq->intid % BITS_PER_BYTE; 3338c2ecf20Sopenharmony_ci ptr = pendbase + byte_offset; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = kvm_read_guest_lock(kvm, ptr, &val, 1); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci status = val & (1 << bit_nr); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&irq->irq_lock, flags); 3428c2ecf20Sopenharmony_ci if (irq->target_vcpu != vcpu) { 3438c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&irq->irq_lock, flags); 3448c2ecf20Sopenharmony_ci goto retry; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci irq->pending_latch = status; 3478c2ecf20Sopenharmony_ci vgic_queue_irq_unlock(vcpu->kvm, irq, flags); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (status) { 3508c2ecf20Sopenharmony_ci /* clear consumed data */ 3518c2ecf20Sopenharmony_ci val &= ~(1 << bit_nr); 3528c2ecf20Sopenharmony_ci ret = kvm_write_guest_lock(kvm, ptr, &val, 1); 3538c2ecf20Sopenharmony_ci if (ret) 3548c2ecf20Sopenharmony_ci return ret; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/** 3608c2ecf20Sopenharmony_ci * vgic_v3_save_pending_tables - Save the pending tables into guest RAM 3618c2ecf20Sopenharmony_ci * kvm lock and all vcpu lock must be held 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ciint vgic_v3_save_pending_tables(struct kvm *kvm) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct vgic_dist *dist = &kvm->arch.vgic; 3668c2ecf20Sopenharmony_ci struct vgic_irq *irq; 3678c2ecf20Sopenharmony_ci gpa_t last_ptr = ~(gpa_t)0; 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci u8 val; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { 3728c2ecf20Sopenharmony_ci int byte_offset, bit_nr; 3738c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 3748c2ecf20Sopenharmony_ci gpa_t pendbase, ptr; 3758c2ecf20Sopenharmony_ci bool stored; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci vcpu = irq->target_vcpu; 3788c2ecf20Sopenharmony_ci if (!vcpu) 3798c2ecf20Sopenharmony_ci continue; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci byte_offset = irq->intid / BITS_PER_BYTE; 3848c2ecf20Sopenharmony_ci bit_nr = irq->intid % BITS_PER_BYTE; 3858c2ecf20Sopenharmony_ci ptr = pendbase + byte_offset; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (ptr != last_ptr) { 3888c2ecf20Sopenharmony_ci ret = kvm_read_guest_lock(kvm, ptr, &val, 1); 3898c2ecf20Sopenharmony_ci if (ret) 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci last_ptr = ptr; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci stored = val & (1U << bit_nr); 3958c2ecf20Sopenharmony_ci if (stored == irq->pending_latch) 3968c2ecf20Sopenharmony_ci continue; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (irq->pending_latch) 3998c2ecf20Sopenharmony_ci val |= 1 << bit_nr; 4008c2ecf20Sopenharmony_ci else 4018c2ecf20Sopenharmony_ci val &= ~(1 << bit_nr); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ret = kvm_write_guest_lock(kvm, ptr, &val, 1); 4048c2ecf20Sopenharmony_ci if (ret) 4058c2ecf20Sopenharmony_ci return ret; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/** 4118c2ecf20Sopenharmony_ci * vgic_v3_rdist_overlap - check if a region overlaps with any 4128c2ecf20Sopenharmony_ci * existing redistributor region 4138c2ecf20Sopenharmony_ci * 4148c2ecf20Sopenharmony_ci * @kvm: kvm handle 4158c2ecf20Sopenharmony_ci * @base: base of the region 4168c2ecf20Sopenharmony_ci * @size: size of region 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Return: true if there is an overlap 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cibool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct vgic_dist *d = &kvm->arch.vgic; 4238c2ecf20Sopenharmony_ci struct vgic_redist_region *rdreg; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci list_for_each_entry(rdreg, &d->rd_regions, list) { 4268c2ecf20Sopenharmony_ci if ((base + size > rdreg->base) && 4278c2ecf20Sopenharmony_ci (base < rdreg->base + vgic_v3_rd_region_size(kvm, rdreg))) 4288c2ecf20Sopenharmony_ci return true; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci return false; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* 4348c2ecf20Sopenharmony_ci * Check for overlapping regions and for regions crossing the end of memory 4358c2ecf20Sopenharmony_ci * for base addresses which have already been set. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_cibool vgic_v3_check_base(struct kvm *kvm) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct vgic_dist *d = &kvm->arch.vgic; 4408c2ecf20Sopenharmony_ci struct vgic_redist_region *rdreg; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (!IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) && 4438c2ecf20Sopenharmony_ci d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base) 4448c2ecf20Sopenharmony_ci return false; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci list_for_each_entry(rdreg, &d->rd_regions, list) { 4478c2ecf20Sopenharmony_ci if (rdreg->base + vgic_v3_rd_region_size(kvm, rdreg) < 4488c2ecf20Sopenharmony_ci rdreg->base) 4498c2ecf20Sopenharmony_ci return false; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (IS_VGIC_ADDR_UNDEF(d->vgic_dist_base)) 4538c2ecf20Sopenharmony_ci return true; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return !vgic_v3_rdist_overlap(kvm, d->vgic_dist_base, 4568c2ecf20Sopenharmony_ci KVM_VGIC_V3_DIST_SIZE); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/** 4608c2ecf20Sopenharmony_ci * vgic_v3_rdist_free_slot - Look up registered rdist regions and identify one 4618c2ecf20Sopenharmony_ci * which has free space to put a new rdist region. 4628c2ecf20Sopenharmony_ci * 4638c2ecf20Sopenharmony_ci * @rd_regions: redistributor region list head 4648c2ecf20Sopenharmony_ci * 4658c2ecf20Sopenharmony_ci * A redistributor regions maps n redistributors, n = region size / (2 x 64kB). 4668c2ecf20Sopenharmony_ci * Stride between redistributors is 0 and regions are filled in the index order. 4678c2ecf20Sopenharmony_ci * 4688c2ecf20Sopenharmony_ci * Return: the redist region handle, if any, that has space to map a new rdist 4698c2ecf20Sopenharmony_ci * region. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistruct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rd_regions) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct vgic_redist_region *rdreg; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci list_for_each_entry(rdreg, rd_regions, list) { 4768c2ecf20Sopenharmony_ci if (!vgic_v3_redist_region_full(rdreg)) 4778c2ecf20Sopenharmony_ci return rdreg; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return NULL; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistruct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm, 4838c2ecf20Sopenharmony_ci u32 index) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct list_head *rd_regions = &kvm->arch.vgic.rd_regions; 4868c2ecf20Sopenharmony_ci struct vgic_redist_region *rdreg; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci list_for_each_entry(rdreg, rd_regions, list) { 4898c2ecf20Sopenharmony_ci if (rdreg->index == index) 4908c2ecf20Sopenharmony_ci return rdreg; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci return NULL; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciint vgic_v3_map_resources(struct kvm *kvm) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct vgic_dist *dist = &kvm->arch.vgic; 4998c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 5008c2ecf20Sopenharmony_ci int ret = 0; 5018c2ecf20Sopenharmony_ci int c; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (vgic_ready(kvm)) 5048c2ecf20Sopenharmony_ci goto out; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci kvm_for_each_vcpu(c, vcpu, kvm) { 5078c2ecf20Sopenharmony_ci struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (IS_VGIC_ADDR_UNDEF(vgic_cpu->rd_iodev.base_addr)) { 5108c2ecf20Sopenharmony_ci kvm_debug("vcpu %d redistributor base not set\n", c); 5118c2ecf20Sopenharmony_ci ret = -ENXIO; 5128c2ecf20Sopenharmony_ci goto out; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base)) { 5178c2ecf20Sopenharmony_ci kvm_err("Need to set vgic distributor addresses first\n"); 5188c2ecf20Sopenharmony_ci ret = -ENXIO; 5198c2ecf20Sopenharmony_ci goto out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (!vgic_v3_check_base(kvm)) { 5238c2ecf20Sopenharmony_ci kvm_err("VGIC redist and dist frames overlap\n"); 5248c2ecf20Sopenharmony_ci ret = -EINVAL; 5258c2ecf20Sopenharmony_ci goto out; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * For a VGICv3 we require the userland to explicitly initialize 5308c2ecf20Sopenharmony_ci * the VGIC before we need to use it. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci if (!vgic_initialized(kvm)) { 5338c2ecf20Sopenharmony_ci ret = -EBUSY; 5348c2ecf20Sopenharmony_ci goto out; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3); 5388c2ecf20Sopenharmony_ci if (ret) { 5398c2ecf20Sopenharmony_ci kvm_err("Unable to register VGICv3 dist MMIO regions\n"); 5408c2ecf20Sopenharmony_ci goto out; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (kvm_vgic_global_state.has_gicv4_1) 5448c2ecf20Sopenharmony_ci vgic_v4_configure_vsgis(kvm); 5458c2ecf20Sopenharmony_ci dist->ready = true; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ciout: 5488c2ecf20Sopenharmony_ci return ret; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int __init early_group0_trap_cfg(char *buf) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci return strtobool(buf, &group0_trap); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ciearly_param("kvm-arm.vgic_v3_group0_trap", early_group0_trap_cfg); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int __init early_group1_trap_cfg(char *buf) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci return strtobool(buf, &group1_trap); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ciearly_param("kvm-arm.vgic_v3_group1_trap", early_group1_trap_cfg); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int __init early_common_trap_cfg(char *buf) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci return strtobool(buf, &common_trap); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ciearly_param("kvm-arm.vgic_v3_common_trap", early_common_trap_cfg); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int __init early_gicv4_enable(char *buf) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci return strtobool(buf, &gicv4_enable); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ciearly_param("kvm-arm.vgic_v4_enable", early_gicv4_enable); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/** 5788c2ecf20Sopenharmony_ci * vgic_v3_probe - probe for a VGICv3 compatible interrupt controller 5798c2ecf20Sopenharmony_ci * @info: pointer to the GIC description 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * Returns 0 if the VGICv3 has been probed successfully, returns an error code 5828c2ecf20Sopenharmony_ci * otherwise 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ciint vgic_v3_probe(const struct gic_kvm_info *info) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci u32 ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_ich_vtr_el2); 5878c2ecf20Sopenharmony_ci int ret; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * The ListRegs field is 5 bits, but there is an architectural 5918c2ecf20Sopenharmony_ci * maximum of 16 list registers. Just ignore bit 4... 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1; 5948c2ecf20Sopenharmony_ci kvm_vgic_global_state.can_emulate_gicv2 = false; 5958c2ecf20Sopenharmony_ci kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* GICv4 support? */ 5988c2ecf20Sopenharmony_ci if (info->has_v4) { 5998c2ecf20Sopenharmony_ci kvm_vgic_global_state.has_gicv4 = gicv4_enable; 6008c2ecf20Sopenharmony_ci kvm_vgic_global_state.has_gicv4_1 = info->has_v4_1 && gicv4_enable; 6018c2ecf20Sopenharmony_ci kvm_info("GICv4%s support %sabled\n", 6028c2ecf20Sopenharmony_ci kvm_vgic_global_state.has_gicv4_1 ? ".1" : "", 6038c2ecf20Sopenharmony_ci gicv4_enable ? "en" : "dis"); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (!info->vcpu.start) { 6078c2ecf20Sopenharmony_ci kvm_info("GICv3: no GICV resource entry\n"); 6088c2ecf20Sopenharmony_ci kvm_vgic_global_state.vcpu_base = 0; 6098c2ecf20Sopenharmony_ci } else if (!PAGE_ALIGNED(info->vcpu.start)) { 6108c2ecf20Sopenharmony_ci pr_warn("GICV physical address 0x%llx not page aligned\n", 6118c2ecf20Sopenharmony_ci (unsigned long long)info->vcpu.start); 6128c2ecf20Sopenharmony_ci kvm_vgic_global_state.vcpu_base = 0; 6138c2ecf20Sopenharmony_ci } else { 6148c2ecf20Sopenharmony_ci kvm_vgic_global_state.vcpu_base = info->vcpu.start; 6158c2ecf20Sopenharmony_ci kvm_vgic_global_state.can_emulate_gicv2 = true; 6168c2ecf20Sopenharmony_ci ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2); 6178c2ecf20Sopenharmony_ci if (ret) { 6188c2ecf20Sopenharmony_ci kvm_err("Cannot register GICv2 KVM device.\n"); 6198c2ecf20Sopenharmony_ci return ret; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci kvm_info("vgic-v2@%llx\n", info->vcpu.start); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3); 6248c2ecf20Sopenharmony_ci if (ret) { 6258c2ecf20Sopenharmony_ci kvm_err("Cannot register GICv3 KVM device.\n"); 6268c2ecf20Sopenharmony_ci kvm_unregister_device_ops(KVM_DEV_TYPE_ARM_VGIC_V2); 6278c2ecf20Sopenharmony_ci return ret; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (kvm_vgic_global_state.vcpu_base == 0) 6318c2ecf20Sopenharmony_ci kvm_info("disabling GICv2 emulation\n"); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) { 6348c2ecf20Sopenharmony_ci group0_trap = true; 6358c2ecf20Sopenharmony_ci group1_trap = true; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (group0_trap || group1_trap || common_trap) { 6398c2ecf20Sopenharmony_ci kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n", 6408c2ecf20Sopenharmony_ci group0_trap ? "G0" : "", 6418c2ecf20Sopenharmony_ci group1_trap ? "G1" : "", 6428c2ecf20Sopenharmony_ci common_trap ? "C" : ""); 6438c2ecf20Sopenharmony_ci static_branch_enable(&vgic_v3_cpuif_trap); 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci kvm_vgic_global_state.vctrl_base = NULL; 6478c2ecf20Sopenharmony_ci kvm_vgic_global_state.type = VGIC_V3; 6488c2ecf20Sopenharmony_ci kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_civoid vgic_v3_load(struct kvm_vcpu *vcpu) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* 6588c2ecf20Sopenharmony_ci * If dealing with a GICv2 emulation on GICv3, VMCR_EL2.VFIQen 6598c2ecf20Sopenharmony_ci * is dependent on ICC_SRE_EL1.SRE, and we have to perform the 6608c2ecf20Sopenharmony_ci * VMCR_EL2 save/restore in the world switch. 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_ci if (likely(cpu_if->vgic_sre)) 6638c2ecf20Sopenharmony_ci kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci kvm_call_hyp(__vgic_v3_restore_aprs, cpu_if); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (has_vhe()) 6688c2ecf20Sopenharmony_ci __vgic_v3_activate_traps(cpu_if); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci WARN_ON(vgic_v4_load(vcpu)); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_civoid vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (likely(cpu_if->vgic_sre)) 6788c2ecf20Sopenharmony_ci cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_civoid vgic_v3_put(struct kvm_vcpu *vcpu) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci WARN_ON(vgic_v4_put(vcpu, false)); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci vgic_v3_vmcr_sync(vcpu); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci kvm_call_hyp(__vgic_v3_save_aprs, cpu_if); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (has_vhe()) 6928c2ecf20Sopenharmony_ci __vgic_v3_deactivate_traps(cpu_if); 6938c2ecf20Sopenharmony_ci} 694