All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV
@ 2026-10-29 22:37 Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 1/5] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1 Oliver Upton
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, Oliver Upton

I went ahead and grabbed Wei-Lin's series [1] that added TCR_EL2
sanitisation since it makes life quite a bit easier for computing an
effective TCR_EL1.

Tested on Neoverse-V2 running a guest with FEAT_E2H0.

v2 -> v3:
 - Collect R-b's from Joey
 - Add patch "KVM: arm64: nv: Correctly compute the effective TCR_EL1
   for nVHE TCR_EL2", itself picking up fixes for forwarding missing
   fields into the effective TCR_EL1 value (Fuad)

[*]: https://lore.kernel.org/all/20260917214215.74135-1-weilin.chang@arm.com/

Marc Zyngier (1):
  KVM: arm64: Reset TCR_EL2 according to guest's E2H mode

Oliver Upton (1):
  KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE
    TCR_EL2

Wei-Lin Chang (3):
  KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1
  arm64: sysreg: Add TCR_EL2 to sysreg infrastructure
  KVM: arm64: Convert TCR_EL2 to config-driven sanitisation

 arch/arm64/include/asm/kvm_arm.h    |  13 ---
 arch/arm64/include/asm/kvm_host.h   |   2 +-
 arch/arm64/include/asm/kvm_nested.h |  38 +++++++--
 arch/arm64/include/asm/sysreg.h     |   1 -
 arch/arm64/kvm/config.c             | 112 +++++++++++++++++++++++++
 arch/arm64/kvm/nested.c             |  15 ++++
 arch/arm64/kvm/sys_regs.c           |  10 ++-
 arch/arm64/tools/sysreg             | 125 ++++++++++++++++++++++++++++
 8 files changed, 291 insertions(+), 25 deletions(-)


base-commit: 9e9283e4c941e806d2735f09b66763487bc48b50
-- 
2.47.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/5] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1
  2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
@ 2026-10-29 22:37 ` Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 2/5] arm64: sysreg: Add TCR_EL2 to sysreg infrastructure Oliver Upton
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, stable, Oliver Upton

From: Wei-Lin Chang <weilin.chang@arm.com>

There is no FEAT_LPA2 support for NV guests as of now, but we missed
limiting it for the non-stage-2 granule size fields (TGRAN4, TGRAN16) in
ID_AA64MMFR0_EL1. Add the sanitisation.

Fixes: 9f75b6d447d7 ("KVM: arm64: nv: Filter out unsupported features from ID regs")
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
---
 arch/arm64/kvm/nested.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 4d83281a7a28..cd0dabcf3f81 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1875,6 +1875,17 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
 		/* Hide CNTPOFF if present */
 		val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR0_EL1, ECV, IMP);
 
+		/* NV does not support FEAT_LPA2. */
+		if (SYS_FIELD_GET(ID_AA64MMFR0_EL1, TGRAN4, val) == ID_AA64MMFR0_EL1_TGRAN4_52_BIT) {
+			val &= ~ID_AA64MMFR0_EL1_TGRAN4;
+			val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN4, IMP);
+		}
+
+		if (SYS_FIELD_GET(ID_AA64MMFR0_EL1, TGRAN16, val) == ID_AA64MMFR0_EL1_TGRAN16_52_BIT) {
+			val &= ~ID_AA64MMFR0_EL1_TGRAN16;
+			val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN16, IMP);
+		}
+
 		/* Disallow unsupported S2 page sizes */
 		switch (PAGE_SIZE) {
 		case SZ_64K:
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 2/5] arm64: sysreg: Add TCR_EL2 to sysreg infrastructure
  2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 1/5] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1 Oliver Upton
@ 2026-10-29 22:37 ` Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 3/5] KVM: arm64: Reset TCR_EL2 according to guest's E2H mode Oliver Upton
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, Mark Brown,
	Oliver Upton

From: Wei-Lin Chang <weilin.chang@arm.com>

Convert TCR_EL2 to the sysreg infrastructure with data extracted from
Registers.json of the BSD licenced AARCHMRS
(AARCHMRS_OPENSOURCE_A_profile_FAT-2026-06).

There are two formats of TCR_EL2 based on whether the effective value of
HCR_EL2.E2H is 0 or 1. For the E2H == 1 case, prefix the macros with
"VHE_". For the E2H == 0 case, the macros are left unprefixed.

Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
Signed-off-by: Oliver Upton <oupton@kernel.org>
---
 arch/arm64/include/asm/kvm_arm.h |  13 ----
 arch/arm64/include/asm/sysreg.h  |   1 -
 arch/arm64/tools/sysreg          | 125 +++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index ba0062849be9..3e1c9e31028e 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -45,19 +45,6 @@
 #define MPAMHCR_HOST_FLAGS	0
 
 /* TCR_EL2 Registers bits */
-#define TCR_EL2_DS		(1UL << 32)
-#define TCR_EL2_RES1		((1U << 31) | (1 << 23))
-#define TCR_EL2_HPD		(1 << 24)
-#define TCR_EL2_HA		(1 << 21)
-#define TCR_EL2_TBI		(1 << 20)
-#define TCR_EL2_PS_SHIFT	16
-#define TCR_EL2_PS_MASK		(7 << TCR_EL2_PS_SHIFT)
-#define TCR_EL2_PS_40B		(2 << TCR_EL2_PS_SHIFT)
-#define TCR_EL2_TG0_MASK	TCR_TG0_MASK
-#define TCR_EL2_SH0_MASK	TCR_SH0_MASK
-#define TCR_EL2_ORGN0_MASK	TCR_ORGN0_MASK
-#define TCR_EL2_IRGN0_MASK	TCR_IRGN0_MASK
-#define TCR_EL2_T0SZ_MASK	0x3f
 #define TCR_EL2_MASK	(TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
 			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
 
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index aa65603455a2..fee89cd667d9 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -519,7 +519,6 @@
 
 #define SYS_TTBR0_EL2			sys_reg(3, 4, 2, 0, 0)
 #define SYS_TTBR1_EL2			sys_reg(3, 4, 2, 0, 1)
-#define SYS_TCR_EL2			sys_reg(3, 4, 2, 0, 2)
 #define SYS_VTTBR_EL2			sys_reg(3, 4, 2, 1, 0)
 
 #define SYS_HAFGRTR_EL2			sys_reg(3, 4, 3, 1, 6)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 893b5f9df575..bbe32dee55f9 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -5612,6 +5612,131 @@ Res0    6
 Field   5:0     T0SZ
 EndSysreg
 
+Sysreg	TCR_EL2		3	4	2	0	2
+Prefix	VHE
+Res0	63:62
+Field	61	MTX1
+Field	60	MTX0
+Field	59	DS
+Field	58	TCMA1
+Field	57	TCMA0
+Field	56	E0PD1
+Field	55	E0PD0
+Field	54	NFD1
+Field	53	NFD0
+Field	52	TBID1
+Field	51	TBID0
+Field	50	HWU162
+Field	49	HWU161
+Field	48	HWU160
+Field	47	HWU159
+Field	46	HWU062
+Field	45	HWU061
+Field	44	HWU060
+Field	43	HWU059
+Field	42	HPD1
+Field	41	HPD0
+Field	40	HD
+Field	39	HA
+Field	38	TBI1
+Field	37	TBI0
+Field	36	AS
+Res0	35
+Field	34:32	IPS
+Enum	31:30	TG1
+	0b01	16K
+	0b10	4K
+	0b11	64K
+EndEnum
+Enum	29:28	SH1
+	0b00	NONE
+	0b10	OUTER
+	0b11	INNER
+EndEnum
+Enum	27:26	ORGN1
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Enum	25:24	IRGN1
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Field	23	EPD1
+Field	22	A1
+Field	21:16	T1SZ
+Enum	15:14	TG0
+	0b00	4K
+	0b01	64K
+	0b10	16K
+EndEnum
+Enum	13:12	SH0
+	0b00	NONE
+	0b10	OUTER
+	0b11	INNER
+EndEnum
+Enum	11:10	ORGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Enum	9:8	IRGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Field	7	EPD0
+Res0	6
+Field	5:0	T0SZ
+EndPrefix
+Res0	63:34
+Field	33	MTX
+Field	32	DS
+Res1	31
+Field	30	TCMA
+Field	29	TBID
+Field	28	HWU62
+Field	27	HWU61
+Field	26	HWU60
+Field	25	HWU59
+Field	24	HPD
+Res1	23
+Field	22	HD
+Field	21	HA
+Field	20	TBI
+Res0	19
+Field	18:16	PS
+Enum	15:14	TG0
+	0b00	4K
+	0b01	64K
+	0b10	16K
+EndEnum
+Enum	13:12	SH0
+	0b00	NONE
+	0b10	OUTER
+	0b11	INNER
+EndEnum
+Enum	11:10	ORGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Enum	9:8	IRGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Res0	7:6
+Field	5:0	T0SZ
+EndSysreg
+
 Sysreg	TCR_EL12        3	5	2	0	2
 Mapping	TCR_EL1
 EndSysreg
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 3/5] KVM: arm64: Reset TCR_EL2 according to guest's E2H mode
  2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 1/5] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1 Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 2/5] arm64: sysreg: Add TCR_EL2 to sysreg infrastructure Oliver Upton
@ 2026-10-29 22:37 ` Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation Oliver Upton
  2026-10-29 22:37 ` [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2 Oliver Upton
  4 siblings, 0 replies; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, Oliver Upton

From: Marc Zyngier <maz@kernel.org>

Previously vCPU TCR_EL2's reset value didn't consider TCR_EL2's
different formats based on the value of HCR_EL2.E2H. It always resets to
the E2H == 0 version.

This didn't cause any problem because the bits set in the E2H == 0
version (TCR_EL2_RES1) all reset to UNKNOWN for E2H == 1 per the
architecture.

Still, it's better to fix it. Choose the correct reset value by checking
KVM_ARM_VCPU_HAS_EL2_E2H0.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Oliver Upton <oupton@kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 0687b78cd7c2..bc880d777442 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3273,6 +3273,14 @@ static u64 reset_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	return vcpu->kvm->arch.nr_pmu_counters;
 }
 
+static u64 reset_tcr_el2(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+	__vcpu_assign_sys_reg(vcpu, r->reg,
+			      vcpu_has_feature(vcpu, KVM_ARM_VCPU_HAS_EL2_E2H0) ?
+			      TCR_EL2_RES1 : VHE_TCR_EL2_RES1);
+	return __vcpu_sys_reg(vcpu, r->reg);
+}
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -3851,7 +3859,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
 	EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
-	EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),
+	EL2_REG(TCR_EL2, access_rw, reset_tcr_el2, 0),
 	EL2_REG_FILTERED(TCR2_EL2, access_rw, reset_val, TCR2_EL2_RES1,
 			 tcr2_el2_visibility),
 	EL2_REG_VNCR(VTTBR_EL2, reset_val, 0),
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation
  2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
                   ` (2 preceding siblings ...)
  2026-10-29 22:37 ` [PATCH v3 3/5] KVM: arm64: Reset TCR_EL2 according to guest's E2H mode Oliver Upton
@ 2026-10-29 22:37 ` Oliver Upton
  2026-10-30  1:26   ` Wei-Lin Chang
  2026-10-29 22:37 ` [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2 Oliver Upton
  4 siblings, 1 reply; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, Oliver Upton

From: Wei-Lin Chang <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>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Oliver Upton <oupton@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h |   2 +-
 arch/arm64/kvm/config.c           | 112 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/nested.c           |   4 ++
 3 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 95de3dd23fa1..eda8bfcc5eaa 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -598,7 +598,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) */
@@ -623,6 +622,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 cfdb6c713320..31ceac9f271a 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -219,7 +219,9 @@ 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
@@ -232,6 +234,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
@@ -244,6 +250,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);
@@ -1080,6 +1099,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 vhe_tcr_el2_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(vhe_tcr_el2_desc, VHE_TCR_EL2,
+			      vhe_tcr_el2_feat_map, FEAT_AA64EL2);
+
+static const struct reg_bits_to_feat_map tcr_el2_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_desc, TCR_EL2,
+			      tcr_el2_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	|
@@ -1442,6 +1546,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(&vhe_tcr_el2_desc);
+	check_reg_desc(&tcr_el2_desc);
 	check_reg_desc(&tcr2_el2_desc);
 	check_reg_desc(&sctlr_el1_desc);
 	check_reg_desc(&sctlr_el2_desc);
@@ -1689,6 +1795,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_desc, 0, 0);
+		else
+			resx = compute_reg_resx_bits(kvm, &vhe_tcr_el2_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 cd0dabcf3f81..78fa433774c6 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -2101,6 +2101,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.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2
  2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
                   ` (3 preceding siblings ...)
  2026-10-29 22:37 ` [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation Oliver Upton
@ 2026-10-29 22:37 ` Oliver Upton
  2026-10-30  1:13   ` Wei-Lin Chang
  4 siblings, 1 reply; 8+ messages in thread
From: Oliver Upton @ 2026-10-29 22:37 UTC (permalink / raw)
  To: kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Wei-Lin Chang, Steffen Eiden, Fuad Tabba, Oliver Upton, stable

It would appear that nVHE hypervisor support has a few warts which
shouldn't come as a surprise. Several fields in TCR_EL2 for features
supported in the VM (TCR_EL2.HA for example) are not correctly
propagated to the effective value of TCR_EL1.

Forward fields in bulk from nVHE TCR_EL2 to the effective TCR_EL1,
relying on config-based sanitisation to enforce the RESx behavior of
unsupported features. Deal with the slightly annoying case where the
E2H==0 bitfield names are not annotated by TTBR like they are in E2H==1.

Cc: stable@vger.kernel.org # v6.18+
Fixes: d5bbb76f4474 ("KVM: arm64: nv: Expose hardware access flag management to NV guests")
Fixes: 3606e0b2e462 ("KVM: arm64: nv: Add non-VHE-EL2->EL1 translation helpers")
Signed-off-by: Oliver Upton <oupton@kernel.org>
---
 arch/arm64/include/asm/kvm_nested.h | 38 ++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index 0f899addafa8..27ec73da02c6 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -20,16 +20,36 @@ static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2)
 	return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT;
 }
 
-static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
+#define __xlate_tcr_nvhe_to_vhe(nfld, vfld, nvhe, vhe)				\
+	FIELD_MODIFY(VHE_TCR_EL2_##vfld, vhe, FIELD_GET(TCR_EL2_##nfld, *(nvhe)))
+
+#define __xlate_tcr_nvhe_to_vhe_field(fld, nvhe, vhe)				\
+	__xlate_tcr_nvhe_to_vhe(fld, fld, nvhe, vhe)
+
+static inline u64 translate_tcr_el2_to_tcr_el1(u64 nvhe)
 {
-	return TCR_EPD1_MASK |				/* disable TTBR1_EL1 */
-	       ((tcr & TCR_EL2_DS) ? TCR_DS : 0) |
-	       ((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
-	       tcr_el2_ps_to_tcr_el1_ips(tcr) |
-	       (tcr & TCR_EL2_TG0_MASK) |
-	       (tcr & TCR_EL2_ORGN0_MASK) |
-	       (tcr & TCR_EL2_IRGN0_MASK) |
-	       (tcr & TCR_EL2_T0SZ_MASK);
+	u64 vhe = VHE_TCR_EL2_EPD1 |			/* disable TTBR1_EL1 */
+		  tcr_el2_ps_to_tcr_el1_ips(nvhe);
+
+	__xlate_tcr_nvhe_to_vhe(MTX,	MTX0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(TCMA,	TCMA0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(TBID,	TBID0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(HWU62,	HWU062,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(HWU61,	HWU061,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(HWU60,	HWU060,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(HWU59,	HWU059,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(HPD,	HPD0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe(TBI,	TBI0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	DS,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	HA,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	HD,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	TG0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	SH0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	ORGN0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	IRGN0,	&nvhe,	&vhe);
+	__xlate_tcr_nvhe_to_vhe_field(	T0SZ,	&nvhe,	&vhe);
+
+	return vhe;
 }
 
 static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2
  2026-10-29 22:37 ` [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2 Oliver Upton
@ 2026-10-30  1:13   ` Wei-Lin Chang
  0 siblings, 0 replies; 8+ messages in thread
From: Wei-Lin Chang @ 2026-10-30  1:13 UTC (permalink / raw)
  To: Oliver Upton, kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Steffen Eiden, Fuad Tabba, stable

On Thu, Oct 29, 2026 at 03:37:32PM -0700, Oliver Upton wrote:
> It would appear that nVHE hypervisor support has a few warts which
> shouldn't come as a surprise. Several fields in TCR_EL2 for features
> supported in the VM (TCR_EL2.HA for example) are not correctly
> propagated to the effective value of TCR_EL1.
> 
> Forward fields in bulk from nVHE TCR_EL2 to the effective TCR_EL1,
> relying on config-based sanitisation to enforce the RESx behavior of
> unsupported features. Deal with the slightly annoying case where the
> E2H==0 bitfield names are not annotated by TTBR like they are in E2H==1.
> 
> Cc: stable@vger.kernel.org # v6.18+
> Fixes: d5bbb76f4474 ("KVM: arm64: nv: Expose hardware access flag management to NV guests")
> Fixes: 3606e0b2e462 ("KVM: arm64: nv: Add non-VHE-EL2->EL1 translation helpers")
> Signed-off-by: Oliver Upton <oupton@kernel.org>

Reviewed-by: Wei-Lin Chang <weilin.chang@arm.com>

> ---
>  arch/arm64/include/asm/kvm_nested.h | 38 ++++++++++++++++++++++-------
>  1 file changed, 29 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
> index 0f899addafa8..27ec73da02c6 100644
> --- a/arch/arm64/include/asm/kvm_nested.h
> +++ b/arch/arm64/include/asm/kvm_nested.h
> @@ -20,16 +20,36 @@ static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2)
>  	return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT;
>  }
>  
> -static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
> +#define __xlate_tcr_nvhe_to_vhe(nfld, vfld, nvhe, vhe)				\
> +	FIELD_MODIFY(VHE_TCR_EL2_##vfld, vhe, FIELD_GET(TCR_EL2_##nfld, *(nvhe)))
> +
> +#define __xlate_tcr_nvhe_to_vhe_field(fld, nvhe, vhe)				\
> +	__xlate_tcr_nvhe_to_vhe(fld, fld, nvhe, vhe)
> +
> +static inline u64 translate_tcr_el2_to_tcr_el1(u64 nvhe)
>  {
> -	return TCR_EPD1_MASK |				/* disable TTBR1_EL1 */
> -	       ((tcr & TCR_EL2_DS) ? TCR_DS : 0) |
> -	       ((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
> -	       tcr_el2_ps_to_tcr_el1_ips(tcr) |
> -	       (tcr & TCR_EL2_TG0_MASK) |
> -	       (tcr & TCR_EL2_ORGN0_MASK) |
> -	       (tcr & TCR_EL2_IRGN0_MASK) |
> -	       (tcr & TCR_EL2_T0SZ_MASK);
> +	u64 vhe = VHE_TCR_EL2_EPD1 |			/* disable TTBR1_EL1 */
> +		  tcr_el2_ps_to_tcr_el1_ips(nvhe);
> +
> +	__xlate_tcr_nvhe_to_vhe(MTX,	MTX0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(TCMA,	TCMA0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(TBID,	TBID0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(HWU62,	HWU062,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(HWU61,	HWU061,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(HWU60,	HWU060,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(HWU59,	HWU059,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(HPD,	HPD0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe(TBI,	TBI0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	DS,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	HA,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	HD,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	TG0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	SH0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	ORGN0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	IRGN0,	&nvhe,	&vhe);
> +	__xlate_tcr_nvhe_to_vhe_field(	T0SZ,	&nvhe,	&vhe);
> +
> +	return vhe;
>  }
>  
>  static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
> -- 
> 2.47.3
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation
  2026-10-29 22:37 ` [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation Oliver Upton
@ 2026-10-30  1:26   ` Wei-Lin Chang
  0 siblings, 0 replies; 8+ messages in thread
From: Wei-Lin Chang @ 2026-10-30  1:26 UTC (permalink / raw)
  To: Oliver Upton, kvmarm
  Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Steffen Eiden, Fuad Tabba

Hi Oliver,

I have checked TCR_EL2 information in the latest 2026-09 release,
the only difference is it correctly states TCR_EL2.AS is dependent on
FEAT_ASID16 now, like what Joey said.

On Thu, Oct 29, 2026 at 03:37:31PM -0700, Oliver Upton wrote:
> From: Wei-Lin Chang <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).

So if you like you can change this to 2026-09,

> 
> Places where we slightly deviate from the above:
> 
>  - Stick to the ARM ARM M.c requirement for TCR_EL2.TCMA*, which only

and change this to M.d,

>    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.

and remove this item.

Not that these stay up to date for long though, but just thought I'd
point them out.

Thanks,
Wei-Lin Chang

> 
> Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
> Reviewed-by: Joey Gouly <joey.gouly@arm.com>
> Signed-off-by: Oliver Upton <oupton@kernel.org>
> ---

[...]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-30  1:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29 22:37 [PATCH v3 0/5] KVM: arm64: TCR_EL2 fixes, FEAT_LPA2=NI for NV Oliver Upton
2026-10-29 22:37 ` [PATCH v3 1/5] KVM: arm64: nv: Don't advertise FEAT_LPA2 for guest stage-1 Oliver Upton
2026-10-29 22:37 ` [PATCH v3 2/5] arm64: sysreg: Add TCR_EL2 to sysreg infrastructure Oliver Upton
2026-10-29 22:37 ` [PATCH v3 3/5] KVM: arm64: Reset TCR_EL2 according to guest's E2H mode Oliver Upton
2026-10-29 22:37 ` [PATCH v3 4/5] KVM: arm64: Convert TCR_EL2 to config-driven sanitisation Oliver Upton
2026-10-30  1:26   ` Wei-Lin Chang
2026-10-29 22:37 ` [PATCH v3 5/5] KVM: arm64: nv: Correctly compute the effective TCR_EL1 for nVHE TCR_EL2 Oliver Upton
2026-10-30  1:13   ` Wei-Lin Chang

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.