From: Wei-Lin Chang <weilin.chang@arm.com>
To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-kernel@vger.kernel.org
Cc: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
Fuad Tabba <fuad.tabba@linux.dev>,
Joey Gouly <joey.gouly@arm.com>,
Steffen Eiden <seiden@linux.ibm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Sascha Bischoff <Sascha.Bischoff@arm.com>,
Ben Horgan <ben.horgan@arm.com>,
Lorenzo Pieralisi <lpieralisi@kernel.org>,
Thomas Huth <thuth@redhat.com>,
James Clark <james.clark@linaro.org>,
Mark Brown <broonie@kernel.org>,
Anshuman Khandual <anshuman.khandual@arm.com>,
Wei-Lin Chang <weilin.chang@arm.com>
Subject: [PATCH v1 3/3] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation
Date: Wed, 9 Sep 2026 23:20:15 +0100 [thread overview]
Message-ID: <20260909222015.3046432-4-weilin.chang@arm.com> (raw)
In-Reply-To: <20260909222015.3046432-1-weilin.chang@arm.com>
Feature dependencies of the fields in TCR_EL2 are extracted from
Registers.json of the BSD licenced AARCHMRS
(AARCHMRS_OPENSOURCE_A_profile_FAT-2026-06).
Places where we slightly deviate from the above:
- Stick to the ARM ARM M.c requirement for TCR_EL2.TCMA*, which only
depends on FEAT_MTE2. This avoids updating ID_AA64PFR2_EL1 with new
VMTE* definitions that we don't know the meaning of, as they aren't
present in the ARM ARM yet.
- Ignore TCR_EL2.DS's requirement of needing the effective value of
TCR2_EL2.D128 be 0. This requires runtime detection of TCR2_EL2.D128
and we don't have D128 support yet.
- TCR_EL2.AS is dependent on FEAT_ASID16, this information is missing
from the json.
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
---
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/kvm/config.c | 113 ++++++++++++++++++++++++++++++
arch/arm64/kvm/nested.c | 4 ++
3 files changed, 118 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 27fe0cd5b2d7..6a5e22ca3430 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -516,7 +516,6 @@ enum vcpu_sysreg {
HACR_EL2, /* Hypervisor Auxiliary Control Register */
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
- TCR_EL2, /* Translation Control Register (EL2) */
PIRE0_EL2, /* Permission Indirection Register 0 (EL2) */
PIR_EL2, /* Permission Indirection Register 1 (EL2) */
POR_EL2, /* Permission Overlay Register 2 (EL2) */
@@ -541,6 +540,7 @@ enum vcpu_sysreg {
/* Anything from this can be RES0/RES1 sanitised */
MARKER(__SANITISED_REG_START__),
SCTLR_EL2, /* System Control Register (EL2) */
+ TCR_EL2, /* Translation Control Register (EL2) */
TCR2_EL2, /* Extended Translation Control Register (EL2) */
SCTLR2_EL2, /* System Control Register 2 (EL2) */
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 1053676551af..3ccf5359a373 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -203,8 +203,11 @@ struct reg_feat_map_desc {
#define FEAT_CPA2 ID_AA64ISAR3_EL1, CPA, CPA2
#define FEAT_ASID2 ID_AA64MMFR4_EL1, ASID2, IMP
#define FEAT_MEC ID_AA64MMFR3_EL1, MEC, IMP
+#define FEAT_HAF ID_AA64MMFR1_EL1, HAFDBS, AF
#define FEAT_HAFT ID_AA64MMFR1_EL1, HAFDBS, HAFT
+#define FEAT_HAFDBS ID_AA64MMFR1_EL1, HAFDBS, DBM
#define FEAT_HDBSS ID_AA64MMFR1_EL1, HAFDBS, HDBSS
+#define FEAT_HPDS ID_AA64MMFR1_EL1, HPDS, IMP
#define FEAT_HPDS2 ID_AA64MMFR1_EL1, HPDS, HPDS2
#define FEAT_BTI ID_AA64PFR1_EL1, BT, IMP
#define FEAT_ExS ID_AA64MMFR0_EL1, EXS, IMP
@@ -215,6 +218,10 @@ struct reg_feat_map_desc {
#define FEAT_MixedEndEL0 ID_AA64MMFR0_EL1, BIGENDEL0, IMP
#define FEAT_MTE_ASYNC ID_AA64PFR1_EL1, MTE_frac, ASYNC
#define FEAT_MTE_STORE_ONLY ID_AA64PFR2_EL1, MTESTOREONLY, IMP
+#define FEAT_MTE_CANONICAL_TAGS ID_AA64PFR1_EL1, MTEX, MTE4
+#define FEAT_MTE_NO_ADDRESS_TAGS ID_AA64PFR1_EL1, MTEX, MTE4
+#define FEAT_E0PD ID_AA64MMFR2_EL1, E0PD, IMP
+#define FEAT_SVE ID_AA64PFR0_EL1, SVE, IMP
#define FEAT_PAN ID_AA64MMFR1_EL1, PAN, IMP
#define FEAT_PAN3 ID_AA64MMFR1_EL1, PAN, PAN3
#define FEAT_SSBS ID_AA64PFR1_EL1, SSBS, IMP
@@ -227,6 +234,19 @@ struct reg_feat_map_desc {
#define FEAT_GCIE ID_AA64PFR2_EL1, GCIE, IMP
#define FEAT_NV3 ID_AA64MMFR4_EL1, NV_frac, NV3
+static bool feat_asid16(struct kvm *kvm)
+{
+ return kvm_has_feat_enum(kvm, ID_AA64MMFR0_EL1, ASIDBITS, 16);
+}
+
+static bool feat_mte_no_addr_tags_or_canonical_tags(struct kvm *kvm)
+{
+ bool no_addr_tags = kvm_has_feat(kvm, FEAT_MTE_NO_ADDRESS_TAGS);
+ bool canonical_tags = kvm_has_feat(kvm, FEAT_MTE_CANONICAL_TAGS);
+
+ return no_addr_tags || canonical_tags;
+}
+
static bool not_feat_aa64el3(struct kvm *kvm)
{
return !kvm_has_feat(kvm, FEAT_AA64EL3);
@@ -1044,6 +1064,91 @@ static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
static const DECLARE_FEAT_MAP(sctlr2_desc, SCTLR2_EL1,
sctlr2_feat_map, FEAT_SCTLR2);
+static const struct reg_bits_to_feat_map tcr_el2_vhe_feat_map[] = {
+ NEEDS_FEAT(VHE_TCR_EL2_MTX1 |
+ VHE_TCR_EL2_MTX0,
+ feat_mte_no_addr_tags_or_canonical_tags),
+ NEEDS_FEAT(VHE_TCR_EL2_DS, feat_lpa2),
+ NEEDS_FEAT(VHE_TCR_EL2_TCMA1 |
+ VHE_TCR_EL2_TCMA0,
+ FEAT_MTE2),
+ NEEDS_FEAT(VHE_TCR_EL2_E0PD1 |
+ VHE_TCR_EL2_E0PD0,
+ FEAT_E0PD),
+ NEEDS_FEAT(VHE_TCR_EL2_NFD1 |
+ VHE_TCR_EL2_NFD0,
+ FEAT_SVE),
+ NEEDS_FEAT(VHE_TCR_EL2_TBID1 |
+ VHE_TCR_EL2_TBID0,
+ feat_pauth),
+ NEEDS_FEAT(VHE_TCR_EL2_HWU162 |
+ VHE_TCR_EL2_HWU161 |
+ VHE_TCR_EL2_HWU160 |
+ VHE_TCR_EL2_HWU159 |
+ VHE_TCR_EL2_HWU062 |
+ VHE_TCR_EL2_HWU061 |
+ VHE_TCR_EL2_HWU060 |
+ VHE_TCR_EL2_HWU059,
+ FEAT_HPDS2),
+ NEEDS_FEAT(VHE_TCR_EL2_HPD1 |
+ VHE_TCR_EL2_HPD0,
+ FEAT_HPDS),
+ NEEDS_FEAT(VHE_TCR_EL2_HD, FEAT_HAFDBS),
+ NEEDS_FEAT(VHE_TCR_EL2_HA, FEAT_HAF),
+ NEEDS_FEAT(VHE_TCR_EL2_AS, feat_asid16),
+ NEEDS_FEAT(VHE_TCR_EL2_TBI1 |
+ VHE_TCR_EL2_TBI0 |
+ VHE_TCR_EL2_IPS |
+ VHE_TCR_EL2_TG1 |
+ VHE_TCR_EL2_SH1 |
+ VHE_TCR_EL2_ORGN1 |
+ VHE_TCR_EL2_IRGN1 |
+ VHE_TCR_EL2_EPD1 |
+ VHE_TCR_EL2_A1 |
+ VHE_TCR_EL2_T1SZ |
+ VHE_TCR_EL2_TG0 |
+ VHE_TCR_EL2_SH0 |
+ VHE_TCR_EL2_ORGN0 |
+ VHE_TCR_EL2_IRGN0 |
+ VHE_TCR_EL2_EPD0 |
+ VHE_TCR_EL2_T0SZ,
+ FEAT_AA64EL2),
+ FORCE_RES0(VHE_TCR_EL2_RES0),
+ FORCE_RES1(VHE_TCR_EL2_RES1),
+};
+
+static const DECLARE_FEAT_MAP(tcr_el2_vhe_desc, VHE_TCR_EL2,
+ tcr_el2_vhe_feat_map, FEAT_AA64EL2);
+
+static const struct reg_bits_to_feat_map tcr_el2_nvhe_feat_map[] = {
+ NEEDS_FEAT(TCR_EL2_MTX,
+ feat_mte_no_addr_tags_or_canonical_tags),
+ NEEDS_FEAT(TCR_EL2_DS, feat_lpa2),
+ NEEDS_FEAT(TCR_EL2_TCMA, FEAT_MTE2),
+ NEEDS_FEAT(TCR_EL2_TBID, feat_pauth),
+ NEEDS_FEAT(TCR_EL2_HWU62 |
+ TCR_EL2_HWU61 |
+ TCR_EL2_HWU60 |
+ TCR_EL2_HWU59,
+ FEAT_HPDS2),
+ NEEDS_FEAT(TCR_EL2_HPD, FEAT_HPDS),
+ NEEDS_FEAT(TCR_EL2_HD, FEAT_HAFDBS),
+ NEEDS_FEAT(TCR_EL2_HA, FEAT_HAF),
+ NEEDS_FEAT(TCR_EL2_TBI |
+ TCR_EL2_PS |
+ TCR_EL2_TG0 |
+ TCR_EL2_SH0 |
+ TCR_EL2_ORGN0 |
+ TCR_EL2_IRGN0 |
+ TCR_EL2_T0SZ,
+ FEAT_AA64EL2),
+ FORCE_RES0(TCR_EL2_RES0),
+ FORCE_RES1(TCR_EL2_RES1),
+};
+
+static const DECLARE_FEAT_MAP(tcr_el2_nvhe_desc, TCR_EL2,
+ tcr_el2_nvhe_feat_map, FEAT_AA64EL2);
+
static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
NEEDS_FEAT_FLAG(TCR2_EL2_FNG1 |
TCR2_EL2_FNG0 |
@@ -1398,6 +1503,8 @@ void __init check_feature_map(void)
check_reg_desc(&hcr_desc);
check_reg_desc(&nvhcr_desc);
check_reg_desc(&sctlr2_desc);
+ check_reg_desc(&tcr_el2_vhe_desc);
+ check_reg_desc(&tcr_el2_nvhe_desc);
check_reg_desc(&tcr2_el2_desc);
check_reg_desc(&sctlr_el1_desc);
check_reg_desc(&sctlr_el2_desc);
@@ -1611,6 +1718,12 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
case SCTLR2_EL2:
resx = compute_reg_resx_bits(kvm, &sctlr2_desc, 0, 0);
break;
+ case TCR_EL2:
+ if (kvm_has_feat(kvm, FEAT_E2H0))
+ resx = compute_reg_resx_bits(kvm, &tcr_el2_nvhe_desc, 0, 0);
+ else
+ resx = compute_reg_resx_bits(kvm, &tcr_el2_vhe_desc, 0, 0);
+ break;
case TCR2_EL2:
resx = compute_reg_resx_bits(kvm, &tcr2_el2_desc, 0, 0);
break;
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 1fd98117df23..5aa16d9d555b 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1959,6 +1959,10 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
resx = get_reg_fixed_bits(kvm, HFGITR2_EL2);
set_sysreg_masks(kvm, HFGITR2_EL2, resx);
+ /* TCR_EL2 */
+ resx = get_reg_fixed_bits(kvm, TCR_EL2);
+ set_sysreg_masks(kvm, TCR_EL2, resx);
+
/* TCR2_EL2 */
resx = get_reg_fixed_bits(kvm, TCR2_EL2);
set_sysreg_masks(kvm, TCR2_EL2, resx);
--
2.43.0
next prev parent reply other threads:[~2026-09-09 22:20 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 22:20 [PATCH v1 0/3] KVM: arm64: Properly advertise !FEAT_LPA2 for NV Wei-Lin Chang
2026-09-09 22:20 ` [PATCH v1 1/3] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1 Wei-Lin Chang
2026-09-09 22:44 ` sashiko-bot
2026-09-10 10:56 ` Wei-Lin Chang
2026-09-11 8:22 ` Marc Zyngier
2026-09-11 9:08 ` Marc Zyngier
2026-09-09 22:20 ` [PATCH v1 2/3] arm64: sysreg: Add TCR_EL2 to sysreg infrastructure Wei-Lin Chang
2026-09-09 22:38 ` sashiko-bot
2026-09-10 10:58 ` Wei-Lin Chang
2026-09-11 8:45 ` Marc Zyngier
2026-09-10 11:54 ` Mark Brown
2026-09-09 22:20 ` Wei-Lin Chang [this message]
2026-09-11 9:04 ` [PATCH v1 3/3] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation Marc Zyngier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260909222015.3046432-4-weilin.chang@arm.com \
--to=weilin.chang@arm.com \
--cc=Sascha.Bischoff@arm.com \
--cc=anshuman.khandual@arm.com \
--cc=ben.horgan@arm.com \
--cc=broonie@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=fuad.tabba@linux.dev \
--cc=james.clark@linaro.org \
--cc=joey.gouly@arm.com \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=seiden@linux.ibm.com \
--cc=suzuki.poulose@arm.com \
--cc=thuth@redhat.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.