diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index d5e05d979407..ccbeb2f783c4 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -129,13 +129,30 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) } ret = 0; - if (type == KVM_DEV_TYPE_ARM_VGIC_V2) + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: kvm->max_vcpus = VGIC_V2_MAX_CPUS; - else if (type == KVM_DEV_TYPE_ARM_VGIC_V3) + break; + case KVM_DEV_TYPE_ARM_VGIC_V3: kvm->max_vcpus = VGIC_V3_MAX_CPUS; - else if (type == KVM_DEV_TYPE_ARM_VGIC_V5) - kvm->max_vcpus = min(VGIC_V5_MAX_CPUS, - kvm_vgic_global_state.max_gic_vcpus); + break; + case KVM_DEV_TYPE_ARM_VGIC_V5: + kvm->max_vcpus = kvm_vgic_global_state.max_gicv5_vcpus; + break; + } + + /* + * KVM_CREATE_VCPU enforces the model-specific limit if the VGIC has + * already been created. Apply the same limit to any existing vCPUs so + * that the result does not depend on the order in which userspace + * creates them. + */ + kvm_for_each_vcpu(i, vcpu, kvm) { + if (vcpu->vcpu_id >= kvm->max_vcpus) { + ret = -E2BIG; + goto out_unlock; + } + } if (atomic_read(&kvm->online_vcpus) > kvm->max_vcpus) { ret = -E2BIG; @@ -399,15 +416,27 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) if (ret) return ret; - /* - * If we are creating a VCPU with a GICv3 we must also register the - * KVM io device for the redistributor that belongs to this VCPU. - */ - if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { + switch (dist->vgic_model) { + case KVM_DEV_TYPE_ARM_VGIC_V3: + /* + * If we are creating a VCPU with a GICv3 we must also register + * the KVM io device for the redistributor that belongs to this + * VCPU. + */ mutex_lock(&vcpu->kvm->slots_lock); ret = vgic_register_redist_iodev(vcpu); mutex_unlock(&vcpu->kvm->slots_lock); + break; + case KVM_DEV_TYPE_ARM_VGIC_V5: + /* + * Ensure that it is possible to represent the + * userspace-allocated vcpu_id in the hardware-limited (or + * KVM-capped) VPE table used by GICv5. + */ + if (vcpu->vcpu_id >= kvm_vgic_global_state.max_gicv5_vcpus) + return -EINVAL; } + return ret; } diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c index 3d8f17301567..e1571d1788a6 100644 --- a/arch/arm64/kvm/vgic/vgic-v5.c +++ b/arch/arm64/kvm/vgic/vgic-v5.c @@ -80,7 +80,8 @@ int vgic_v5_probe(const struct gic_kvm_info *info) int ret; kvm_vgic_global_state.type = VGIC_V5; - kvm_vgic_global_state.max_gic_vcpus = VGIC_V5_MAX_CPUS; + kvm_vgic_global_state.max_gic_vcpus = 0; + kvm_vgic_global_state.max_gicv5_vcpus = 0; kvm_vgic_global_state.vcpu_base = 0; kvm_vgic_global_state.vctrl_base = NULL; @@ -105,8 +106,8 @@ int vgic_v5_probe(const struct gic_kvm_info *info) * Even if the HW supports more per-VM vCPUs, artificially cap as we * can't use them all. */ - kvm_vgic_global_state.max_gic_vcpus = min(vgic_v5_irs_max_vpes(&irs_caps), - VGIC_V5_MAX_CPUS); + kvm_vgic_global_state.max_gicv5_vcpus = min(vgic_v5_irs_max_vpes(&irs_caps), + VGIC_V5_MAX_CPUS); /* * GICv5 requires a set of tables to be allocated in order to manage @@ -115,7 +116,7 @@ int vgic_v5_probe(const struct gic_kvm_info *info) * we want to run. For now, we match the maximum number offered by the * hardware, but this might not be a wise choice in the long term. */ - ret = vgic_v5_vmt_allocate(kvm_vgic_global_state.max_gic_vcpus); + ret = vgic_v5_vmt_allocate(kvm_vgic_global_state.max_gicv5_vcpus); if (ret) { kvm_err("Failed to allocate the GICv5 VM tables; no GICv5 support\n"); return -ENODEV; @@ -150,6 +151,8 @@ int vgic_v5_probe(const struct gic_kvm_info *info) } v5_registered = true; + kvm_vgic_global_state.max_gic_vcpus = + kvm_vgic_global_state.max_gicv5_vcpus; kvm_info("GCIE system register CPU interface\n"); skip_v5: @@ -175,9 +178,8 @@ int vgic_v5_probe(const struct gic_kvm_info *info) return v5_registered ? 0 : ret; } - /* We potentially limit the max VCPUs further than we need to here */ - kvm_vgic_global_state.max_gic_vcpus = min(VGIC_V3_MAX_CPUS, - kvm_vgic_global_state.max_gic_vcpus); + kvm_vgic_global_state.max_gic_vcpus = max(kvm_vgic_global_state.max_gic_vcpus, + VGIC_V3_MAX_CPUS); static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif); kvm_info("GCIE legacy system register CPU interface\n"); diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 3ec3f7e1b88b..593145760812 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -172,9 +172,16 @@ struct vgic_global { /* Maintenance IRQ number */ unsigned int maint_irq; - /* maximum number of VCPUs allowed (GICv2 limits us to 8) */ + /* + * Maximum number of VCPUs exposed before userspace has selected a + * VGIC model. Individual VGIC models can impose a lower limit + * (GICv2 limits us to 8). + */ int max_gic_vcpus; + /* Maximum number of VCPUs allowed for a GICv5 VM. */ + int max_gicv5_vcpus; + /* Only needed for the legacy KVM_CREATE_IRQCHIP */ bool can_emulate_gicv2; @@ -622,10 +629,11 @@ void kvm_vgic_process_async_update(struct kvm_vcpu *vcpu); void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg, bool allow_group1); /** - * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW + * kvm_vgic_get_max_vcpus - Get the pre-VGIC-selection VCPU limit * - * The host's GIC naturally limits the maximum amount of VCPUs a guest - * can use. + * Userspace can query KVM_CAP_MAX_VCPUS before selecting a VGIC model, so + * expose the highest model-specific limit and let kvm_vgic_create() enforce + * the selected model's actual limit. */ static inline int kvm_vgic_get_max_vcpus(void) {