
From: Marc Zyngier <maz@kernel.org> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I97WGU Reference: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/commit... ----------------------------------------------------------- In order for userspace to be able to control the CPU side of the NMI distribution (just like we have it on the GIC side), allow it to set/clear ID_AA64PFR1_EL1.NMI. This relies on a per-VM property that defaults to the host value. Signed-off-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: caijian <caijian11@h-partners.com> --- arch/arm64/include/asm/kvm_host.h | 2 ++ arch/arm64/kvm/arm.c | 3 +++ arch/arm64/kvm/sys_regs.c | 26 +++++++++++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8c64fa87279b..abe581982a75 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -209,6 +209,8 @@ struct kvm_arch { /* VTCR_EL2 value for this VM */ u64 vtcr; + u8 pfr1_nmi; + /* Interrupt controller */ struct vgic_dist vgic; diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 7f6de7585894..cdfdd08f4c10 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -192,6 +192,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* The maximum number of VCPUs is limited by the host's GIC model */ kvm->max_vcpus = kvm_arm_default_max_vcpus(); + if (system_uses_nmi()) + kvm->arch.pfr1_nmi = ID_AA64PFR1_EL1_NMI_IMP; + kvm_arm_init_hypercalls(kvm); bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES); diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index efc8fbefb434..5a6e64670feb 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1342,6 +1342,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME); val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI); + val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI), vcpu->kvm->arch.pfr1_nmi); break; case SYS_ID_AA64ISAR1_EL1: if (!vcpu_has_ptrauth(vcpu)) @@ -1572,6 +1573,27 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu, return set_id_reg(vcpu, rd, val); } +static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + u64 val) +{ + u8 nmi; + + nmi = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR1_EL1_NMI_SHIFT); + if (nmi > ID_AA64PFR1_EL1_NMI_IMP || (nmi && !system_uses_nmi())) + return -EINVAL; + + /* We can only differ with NMI, and anything else is an error */ + val ^= read_id_reg(vcpu, rd); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI); + if (val) + return -EINVAL; + + vcpu->kvm->arch.pfr1_nmi = nmi; + + return 0; +} + /* * cpufeature ID register user accessors * @@ -2033,7 +2055,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { .set_user = set_id_reg, .reset = read_sanitised_id_aa64pfr0_el1, .val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, }, - ID_SANITISED(ID_AA64PFR1_EL1), + { SYS_DESC(SYS_ID_AA64PFR1_EL1), .access = access_id_reg, + .get_user = get_id_reg, .set_user = set_id_aa64pfr1_el1, + .reset = kvm_read_sanitised_id_reg, }, ID_UNALLOCATED(4,2), ID_UNALLOCATED(4,3), ID_SANITISED(ID_AA64ZFR0_EL1), -- 2.30.0