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),