Commit 395d99d8 authored by Marc Zyngier's avatar Marc Zyngier Committed by chenxiang
Browse files

KVM: arm64: Allow userspace to control ID_AA64PFR1_EL1.NMI

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/?h=arm64/nmi&id=30ea2005892217b59ae86e6625c3ad578496eead



-----------------------------------------------------------

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: default avatarMarc Zyngier <maz@kernel.org>
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarcaijian <caijian11@h-partners.com>
parent 059de40b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -209,6 +209,8 @@ struct kvm_arch {
	/* VTCR_EL2 value for this VM */
	u64    vtcr;

	u8 pfr1_nmi;

	/* Interrupt controller */
	struct vgic_dist	vgic;

+3 −0
Original line number Diff line number Diff line
@@ -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);
+25 −1
Original line number Diff line number Diff line
@@ -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),