summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2025-09-20 12:26:24 +0100
committerMarc Zyngier <maz@kernel.org>2025-09-20 12:26:24 +0100
commit47f15744fcf91587afcd228a3c206a978f3d034b (patch)
treede34b7720b8ffb03cdd05a0faf9952f8ab50ff89
parent46bd74ef07a8a9c4085d03595fce2bfc2a38f03a (diff)
parent5aea4096380f5b14e3c0345bdafc291e9ae6d8d1 (diff)
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: Marc Zyngier <maz@kernel.org>
-rw-r--r--arch/arm64/include/asm/kvm_emulate.h14
-rw-r--r--arch/arm64/kvm/sys_regs.c23
2 files changed, 32 insertions, 5 deletions
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index fa8a08a1ccd5..64ce3fec73ee 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -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;
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index caf80c324b35..4bb877e4280f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -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);