Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+32 -5
+14
arch/arm64/include/asm/kvm_emulate.h
··· 220 220 221 221 static inline bool vcpu_el2_amo_is_set(const struct kvm_vcpu *vcpu) 222 222 { 223 + /* 224 + * DDI0487L.b Known Issue D22105 225 + * 226 + * When executing at EL2 and HCR_EL2.{E2H,TGE} = {1, 0} it is 227 + * IMPLEMENTATION DEFINED whether the effective value of HCR_EL2.AMO 228 + * is the value programmed or 1. 229 + * 230 + * Make the implementation choice of treating the effective value as 1 as 231 + * we cannot subsequently catch changes to TGE or AMO that would 232 + * otherwise lead to the SError becoming deliverable. 233 + */ 234 + if (vcpu_is_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu) && !vcpu_el2_tge_is_set(vcpu)) 235 + return true; 236 + 223 237 return ctxt_sys_reg(&vcpu->arch.ctxt, HCR_EL2) & HCR_AMO; 224 238 } 225 239
+18 -5
arch/arm64/kvm/sys_regs.c
··· 2173 2173 return set_id_reg(vcpu, rd, user_val); 2174 2174 } 2175 2175 2176 + /* 2177 + * Allow userspace to de-feature a stage-2 translation granule but prevent it 2178 + * from claiming the impossible. 2179 + */ 2180 + #define tgran2_val_allowed(tg, safe, user) \ 2181 + ({ \ 2182 + u8 __s = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, safe); \ 2183 + u8 __u = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, user); \ 2184 + \ 2185 + __s == __u || __u == ID_AA64MMFR0_EL1_##tg##_NI; \ 2186 + }) 2187 + 2176 2188 static int set_id_aa64mmfr0_el1(struct kvm_vcpu *vcpu, 2177 2189 const struct sys_reg_desc *rd, u64 user_val) 2178 2190 { 2179 2191 u64 sanitized_val = kvm_read_sanitised_id_reg(vcpu, rd); 2180 - u64 tgran2_mask = ID_AA64MMFR0_EL1_TGRAN4_2_MASK | 2181 - ID_AA64MMFR0_EL1_TGRAN16_2_MASK | 2182 - ID_AA64MMFR0_EL1_TGRAN64_2_MASK; 2183 2192 2184 - if (vcpu_has_nv(vcpu) && 2185 - ((sanitized_val & tgran2_mask) != (user_val & tgran2_mask))) 2193 + if (!vcpu_has_nv(vcpu)) 2194 + return set_id_reg(vcpu, rd, user_val); 2195 + 2196 + if (!tgran2_val_allowed(TGRAN4_2, sanitized_val, user_val) || 2197 + !tgran2_val_allowed(TGRAN16_2, sanitized_val, user_val) || 2198 + !tgran2_val_allowed(TGRAN64_2, sanitized_val, user_val)) 2186 2199 return -EINVAL; 2187 2200 2188 2201 return set_id_reg(vcpu, rd, user_val);