Limit the number of ID and priority bits supported based on the hardware capabilities when resetting the vcpu state. Additionally, calculate the PPI HMR representation for the vcpu. This is presented to the guest when it accesses the ICC_PPI_HMRx_EL1 register (by trapping and emulating the access). Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/vgic/vgic-init.c | 6 +++- arch/arm64/kvm/vgic/vgic-v5.c | 63 ++++++++++++++++++++++++++++++++- arch/arm64/kvm/vgic/vgic.h | 1 + 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 69e8746516799..120f28b329738 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -396,7 +396,11 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) static void kvm_vgic_vcpu_reset(struct kvm_vcpu *vcpu) { - if (kvm_vgic_global_state.type == VGIC_V2) + const struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + + if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) + vgic_v5_reset(vcpu); + else if (kvm_vgic_global_state.type == VGIC_V2) vgic_v2_reset(vcpu); else vgic_v3_reset(vcpu); diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c index 3567754ae1459..a3d52ce066869 100644 --- a/arch/arm64/kvm/vgic/vgic-v5.c +++ b/arch/arm64/kvm/vgic/vgic-v5.c @@ -54,6 +54,45 @@ int vgic_v5_probe(const struct gic_kvm_info *info) return 0; } +static void vgic_v5_construct_hmrs(struct kvm_vcpu *vcpu); + +void vgic_v5_reset(struct kvm_vcpu *vcpu) +{ + u64 idr0; + + idr0 = read_sysreg_s(SYS_ICC_IDR0_EL1); + switch (FIELD_GET(ICC_IDR0_EL1_ID_BITS, idr0)) { + case ICC_IDR0_EL1_ID_BITS_16BITS: + vcpu->arch.vgic_cpu.num_id_bits = 16; + break; + case ICC_IDR0_EL1_ID_BITS_24BITS: + vcpu->arch.vgic_cpu.num_id_bits = 24; + break; + default: + pr_warn("unknown value for id_bits"); + vcpu->arch.vgic_cpu.num_id_bits = 16; + } + + switch (FIELD_GET(ICC_IDR0_EL1_PRI_BITS, idr0)) { + case ICC_IDR0_EL1_PRI_BITS_4BITS: + vcpu->arch.vgic_cpu.num_pri_bits = 4; + break; + case ICC_IDR0_EL1_PRI_BITS_5BITS: + vcpu->arch.vgic_cpu.num_pri_bits = 5; + break; + default: + pr_warn("unknown value for priority_bits"); + vcpu->arch.vgic_cpu.num_pri_bits = 4; + } + + /* + * We're now ready to run this VCPU so no more changes to the + * PPI config are expected. + */ + vgic_v5_construct_hmrs(vcpu); + +} + int vgic_v5_init(struct kvm *kvm) { struct kvm_vcpu *vcpu; @@ -105,8 +144,30 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu) return priority_mask; } +static void vgic_v5_construct_hmrs(struct kvm_vcpu *vcpu) +{ + /* + * Calculate the PPI HMR to present to the guest (and for + * internal interrupt masking). + */ + vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0] = 0; + vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1] = 0; + for (int i = 0; i < VGIC_V5_NR_PRIVATE_IRQS; ++i) { + int reg = i / 64; + u64 bit = BIT_ULL(i % 64); + struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i]; + + raw_spin_lock(&irq->irq_lock); + + if (irq->config == VGIC_CONFIG_LEVEL) + vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[reg] |= bit; + + raw_spin_unlock(&irq->irq_lock); + } +} + static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu, - struct vgic_irq *irq) + struct vgic_irq *irq) { struct vgic_v5_cpu_if *cpu_if; const u32 id_bit = BIT_ULL(irq->intid % 64); diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 66698973b2872..91969b3b80d04 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -385,6 +385,7 @@ void vgic_debug_init(struct kvm *kvm); void vgic_debug_destroy(struct kvm *kvm); int vgic_v5_probe(const struct gic_kvm_info *info); +void vgic_v5_reset(struct kvm_vcpu *vcpu); int vgic_v5_init(struct kvm *kvm); int vgic_v5_map_resources(struct kvm *kvm); void vgic_v5_set_ppi_ops(struct vgic_irq *irq); -- 2.34.1