Commit 47f15744 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/nv-misc-6.18 into kvmarm-master/next



* kvm-arm64/nv-misc-6.18:
  : .
  : Various NV-related fixes:
  :
  : - Relax KVM's SError injection to consider that HCR_EL2.AMO's
  :   effective value is 1 when HCR_EL2.{E2H,TGE)=={1,0}.
  :   (20250918164632.410404-1-oliver.upton@linux.dev)
  :
  : - Allow userspace to disable some S2 base granule sizes
  :   (20250918165505.415017-1-oliver.upton@linux.dev)
  : .
  KVM: arm64: nv: Allow userspace to de-feature stage-2 TGRANs
  KVM: arm64: nv: Treat AMO as 1 when at EL2 and {E2H,TGE} = {1, 0}

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 46bd74ef 5aea4096
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -220,6 +220,20 @@ static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)

static inline bool vcpu_el2_amo_is_set(const struct kvm_vcpu *vcpu)
{
	/*
	 * DDI0487L.b Known Issue D22105
	 *
	 * When executing at EL2 and HCR_EL2.{E2H,TGE} = {1, 0} it is
	 * IMPLEMENTATION DEFINED whether the effective value of HCR_EL2.AMO
	 * is the value programmed or 1.
	 *
	 * Make the implementation choice of treating the effective value as 1 as
	 * we cannot subsequently catch changes to TGE or AMO that would
	 * otherwise lead to the SError becoming deliverable.
	 */
	if (vcpu_is_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu) && !vcpu_el2_tge_is_set(vcpu))
		return true;

	return ctxt_sys_reg(&vcpu->arch.ctxt, HCR_EL2) & HCR_AMO;
}

+18 −5
Original line number Diff line number Diff line
@@ -2173,16 +2173,29 @@ static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu,
	return set_id_reg(vcpu, rd, user_val);
}

/*
 * Allow userspace to de-feature a stage-2 translation granule but prevent it
 * from claiming the impossible.
 */
#define tgran2_val_allowed(tg, safe, user)			\
({								\
	u8 __s = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, safe);	\
	u8 __u = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, user);	\
								\
	__s == __u || __u == ID_AA64MMFR0_EL1_##tg##_NI;	\
})

static int set_id_aa64mmfr0_el1(struct kvm_vcpu *vcpu,
				const struct sys_reg_desc *rd, u64 user_val)
{
	u64 sanitized_val = kvm_read_sanitised_id_reg(vcpu, rd);
	u64 tgran2_mask = ID_AA64MMFR0_EL1_TGRAN4_2_MASK |
			  ID_AA64MMFR0_EL1_TGRAN16_2_MASK |
			  ID_AA64MMFR0_EL1_TGRAN64_2_MASK;

	if (vcpu_has_nv(vcpu) &&
	    ((sanitized_val & tgran2_mask) != (user_val & tgran2_mask)))
	if (!vcpu_has_nv(vcpu))
		return set_id_reg(vcpu, rd, user_val);

	if (!tgran2_val_allowed(TGRAN4_2, sanitized_val, user_val) ||
	    !tgran2_val_allowed(TGRAN16_2, sanitized_val, user_val) ||
	    !tgran2_val_allowed(TGRAN64_2, sanitized_val, user_val))
		return -EINVAL;

	return set_id_reg(vcpu, rd, user_val);