KVM: arm64: Add sanitisation to SCTLR_EL2

Sanitise SCTLR_EL2 the usual way. The most important aspect of
this is that we benefit from SCTLR_EL2.SPAN being RES1 when
HCR_EL2.E2H==0.

Reviewed-by: Fuad Tabba <tabba@google.com>
Tested-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20260202184329.2724080-20-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2026-02-02 18:43:28 +00:00
parent fb40cb15e8
commit e8ef27900c
3 changed files with 87 additions and 1 deletions

View file

@ -495,7 +495,6 @@ enum vcpu_sysreg {
DBGVCR32_EL2, /* Debug Vector Catch Register */
/* EL2 registers */
SCTLR_EL2, /* System Control Register (EL2) */
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
HACR_EL2, /* Hypervisor Auxiliary Control Register */
@ -526,6 +525,7 @@ enum vcpu_sysreg {
/* Anything from this can be RES0/RES1 sanitised */
MARKER(__SANITISED_REG_START__),
SCTLR_EL2, /* System Control Register (EL2) */
TCR2_EL2, /* Extended Translation Control Register (EL2) */
SCTLR2_EL2, /* System Control Register 2 (EL2) */
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */

View file

@ -1123,6 +1123,84 @@ static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
static const DECLARE_FEAT_MAP(sctlr_el1_desc, SCTLR_EL1,
sctlr_el1_feat_map, FEAT_AA64EL1);
static const struct reg_bits_to_feat_map sctlr_el2_feat_map[] = {
NEEDS_FEAT_FLAG(SCTLR_EL2_CP15BEN,
RES1_WHEN_E2H0 | REQUIRES_E2H1,
FEAT_AA32EL0),
NEEDS_FEAT_FLAG(SCTLR_EL2_ITD |
SCTLR_EL2_SED,
RES1_WHEN_E2H1 | REQUIRES_E2H1,
FEAT_AA32EL0),
NEEDS_FEAT_FLAG(SCTLR_EL2_BT0, REQUIRES_E2H1, FEAT_BTI),
NEEDS_FEAT(SCTLR_EL2_BT, FEAT_BTI),
NEEDS_FEAT_FLAG(SCTLR_EL2_CMOW, REQUIRES_E2H1, FEAT_CMOW),
NEEDS_FEAT_FLAG(SCTLR_EL2_TSCXT,
RES1_WHEN_E2H1 | REQUIRES_E2H1,
feat_csv2_2_csv2_1p2),
NEEDS_FEAT_FLAG(SCTLR_EL2_EIS |
SCTLR_EL2_EOS,
AS_RES1, FEAT_ExS),
NEEDS_FEAT(SCTLR_EL2_EnFPM, FEAT_FPMR),
NEEDS_FEAT(SCTLR_EL2_IESB, FEAT_IESB),
NEEDS_FEAT_FLAG(SCTLR_EL2_EnALS, REQUIRES_E2H1, FEAT_LS64),
NEEDS_FEAT_FLAG(SCTLR_EL2_EnAS0, REQUIRES_E2H1, FEAT_LS64_ACCDATA),
NEEDS_FEAT_FLAG(SCTLR_EL2_EnASR, REQUIRES_E2H1, FEAT_LS64_V),
NEEDS_FEAT(SCTLR_EL2_nAA, FEAT_LSE2),
NEEDS_FEAT_FLAG(SCTLR_EL2_LSMAOE |
SCTLR_EL2_nTLSMD,
AS_RES1 | REQUIRES_E2H1, FEAT_LSMAOC),
NEEDS_FEAT(SCTLR_EL2_EE, FEAT_MixedEnd),
NEEDS_FEAT_FLAG(SCTLR_EL2_E0E, REQUIRES_E2H1, feat_mixedendel0),
NEEDS_FEAT_FLAG(SCTLR_EL2_MSCEn, REQUIRES_E2H1, FEAT_MOPS),
NEEDS_FEAT_FLAG(SCTLR_EL2_ATA0 |
SCTLR_EL2_TCF0,
REQUIRES_E2H1, FEAT_MTE2),
NEEDS_FEAT(SCTLR_EL2_ATA |
SCTLR_EL2_TCF,
FEAT_MTE2),
NEEDS_FEAT(SCTLR_EL2_ITFSB, feat_mte_async),
NEEDS_FEAT_FLAG(SCTLR_EL2_TCSO0, REQUIRES_E2H1, FEAT_MTE_STORE_ONLY),
NEEDS_FEAT(SCTLR_EL2_TCSO,
FEAT_MTE_STORE_ONLY),
NEEDS_FEAT(SCTLR_EL2_NMI |
SCTLR_EL2_SPINTMASK,
FEAT_NMI),
NEEDS_FEAT_FLAG(SCTLR_EL2_SPAN, AS_RES1 | REQUIRES_E2H1, FEAT_PAN),
NEEDS_FEAT_FLAG(SCTLR_EL2_EPAN, REQUIRES_E2H1, FEAT_PAN3),
NEEDS_FEAT(SCTLR_EL2_EnDA |
SCTLR_EL2_EnDB |
SCTLR_EL2_EnIA |
SCTLR_EL2_EnIB,
feat_pauth),
NEEDS_FEAT_FLAG(SCTLR_EL2_EnTP2, REQUIRES_E2H1, FEAT_SME),
NEEDS_FEAT(SCTLR_EL2_EnRCTX, FEAT_SPECRES),
NEEDS_FEAT(SCTLR_EL2_DSSBS, FEAT_SSBS),
NEEDS_FEAT_FLAG(SCTLR_EL2_TIDCP, REQUIRES_E2H1, FEAT_TIDCP1),
NEEDS_FEAT_FLAG(SCTLR_EL2_TWEDEL |
SCTLR_EL2_TWEDEn,
REQUIRES_E2H1, FEAT_TWED),
NEEDS_FEAT_FLAG(SCTLR_EL2_nTWE |
SCTLR_EL2_nTWI,
AS_RES1 | REQUIRES_E2H1, FEAT_AA64EL2),
NEEDS_FEAT_FLAG(SCTLR_EL2_UCI |
SCTLR_EL2_UCT |
SCTLR_EL2_DZE |
SCTLR_EL2_SA0,
REQUIRES_E2H1, FEAT_AA64EL2),
NEEDS_FEAT(SCTLR_EL2_WXN |
SCTLR_EL2_I |
SCTLR_EL2_SA |
SCTLR_EL2_C |
SCTLR_EL2_A |
SCTLR_EL2_M,
FEAT_AA64EL2),
FORCE_RES0(SCTLR_EL2_RES0),
FORCE_RES1(SCTLR_EL2_RES1),
};
static const DECLARE_FEAT_MAP(sctlr_el2_desc, SCTLR_EL2,
sctlr_el2_feat_map, FEAT_AA64EL2);
static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
NEEDS_FEAT(MDCR_EL2_EBWE, FEAT_Debugv8p9),
NEEDS_FEAT(MDCR_EL2_TDOSA, FEAT_DoubleLock),
@ -1247,6 +1325,7 @@ void __init check_feature_map(void)
check_reg_desc(&sctlr2_desc);
check_reg_desc(&tcr2_el2_desc);
check_reg_desc(&sctlr_el1_desc);
check_reg_desc(&sctlr_el2_desc);
check_reg_desc(&mdcr_el2_desc);
check_reg_desc(&vtcr_el2_desc);
}
@ -1443,6 +1522,9 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
case SCTLR_EL1:
resx = compute_reg_resx_bits(kvm, &sctlr_el1_desc, 0, 0);
break;
case SCTLR_EL2:
resx = compute_reg_resx_bits(kvm, &sctlr_el2_desc, 0, 0);
break;
case MDCR_EL2:
resx = compute_reg_resx_bits(kvm, &mdcr_el2_desc, 0, 0);
break;

View file

@ -1766,6 +1766,10 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
resx = get_reg_fixed_bits(kvm, SCTLR_EL1);
set_sysreg_masks(kvm, SCTLR_EL1, resx);
/* SCTLR_EL2 */
resx = get_reg_fixed_bits(kvm, SCTLR_EL2);
set_sysreg_masks(kvm, SCTLR_EL2, resx);
/* SCTLR2_ELx */
resx = get_reg_fixed_bits(kvm, SCTLR2_EL1);
set_sysreg_masks(kvm, SCTLR2_EL1, resx);