[PATCH 4/4] arm64/sysreg: Add VTCR_EL2 register

Anshuman Khandual posted 4 patches 5 months, 3 weeks ago
[PATCH 4/4] arm64/sysreg: Add VTCR_EL2 register
Posted by Anshuman Khandual 5 months, 3 weeks ago
Add VTCR_EL2 register fields as per the latest ARM ARM DDI 0487 7.B in
tools sysreg format and drop the existing macros from the header
(arch/arm64/include/asm/kvm_arm.h). While here also drop an explicit
sysreg definction SYS_VTCR_EL2 from sysreg.h header.

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Mark Brown <broonie@kernel.org>
Cc: kvmarm@lists.linux.dev
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h | 32 +++---------------
 arch/arm64/include/asm/sysreg.h  |  1 -
 arch/arm64/kvm/hyp/pgtable.c     |  6 ++--
 arch/arm64/kvm/nested.c          |  2 +-
 arch/arm64/tools/sysreg          | 57 ++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+), 32 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 8994cddef182..5abe3536f1d2 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -110,31 +110,7 @@
 #define TCR_EL2_MASK	(TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
 			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
 
-/* VTCR_EL2 Registers bits */
-#define VTCR_EL2_DS		TCR_EL2_DS
-#define VTCR_EL2_RES1		(1U << 31)
-#define VTCR_EL2_HD		(1 << 22)
-#define VTCR_EL2_HA		(1 << 21)
-#define VTCR_EL2_PS_SHIFT	TCR_EL2_PS_SHIFT
-#define VTCR_EL2_PS_MASK	TCR_EL2_PS_MASK
-#define VTCR_EL2_TG0_MASK	TCR_EL1_TG0_MASK
-#define VTCR_EL2_TG0_4K		(TCR_EL1_TG0_4K << TCR_EL1_TG0_SHIFT)
-#define VTCR_EL2_TG0_16K	(TCR_EL1_TG0_16K << TCR_EL1_TG0_SHIFT)
-#define VTCR_EL2_TG0_64K	(TCR_EL1_TG0_64K << TCR_EL1_TG0_SHIFT)
-#define VTCR_EL2_SH0_MASK	TCR_EL1_SH0_MASK
-#define VTCR_EL2_SH0_INNER	(TCR_EL1_SH0_INNER << TCR_EL1_SH0_SHIFT)
-#define VTCR_EL2_ORGN0_MASK	TCR_EL1_ORGN0_MASK
-#define VTCR_EL2_ORGN0_WBWA	(TCR_EL1_ORGN0_WBWA << TCR_EL1_ORGN0_SHIFT)
-#define VTCR_EL2_IRGN0_MASK	TCR_EL1_IRGN0_MASK
-#define VTCR_EL2_IRGN0_WBWA	(TCR_EL1_IRGN0_WBWA << TCR_EL1_IRGN0_SHIFT)
-#define VTCR_EL2_SL0_SHIFT	6
-#define VTCR_EL2_SL0_MASK	(3 << VTCR_EL2_SL0_SHIFT)
-#define VTCR_EL2_T0SZ_MASK	0x3f
-#define VTCR_EL2_VS_SHIFT	19
-#define VTCR_EL2_VS_8BIT	(0 << VTCR_EL2_VS_SHIFT)
-#define VTCR_EL2_VS_16BIT	(1 << VTCR_EL2_VS_SHIFT)
-
-#define VTCR_EL2_T0SZ(x)	TCR_T0SZ(x)
+#define VTCR_T0SZ(x) ((UL(64) - (x)) << VTCR_EL2_T0SZ_SHIFT)
 
 /*
  * We configure the Stage-2 page tables to always restrict the IPA space to be
@@ -148,8 +124,10 @@
  *
  */
 
-#define VTCR_EL2_COMMON_BITS	(VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
-				 VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1)
+#define VTCR_EL2_COMMON_BITS	((VTCR_EL2_SH0_INNER << VTCR_EL2_SH0_SHIFT) | \
+				 (VTCR_EL2_ORGN0_WBWA << VTCR_EL2_ORGN0_SHIFT) | \
+				 (VTCR_EL2_IRGN0_WBWA << VTCR_EL2_IRGN0_SHIFT) | \
+				 (VTCR_EL2_RES1))
 
 /*
  * VTCR_EL2:SL0 indicates the entry level for Stage2 translation.
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 112d5d0acb50..ea0a7e5a8628 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -524,7 +524,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_VTTBR_EL2			sys_reg(3, 4, 2, 1, 0)
-#define SYS_VTCR_EL2			sys_reg(3, 4, 2, 1, 2)
 
 #define SYS_HAFGRTR_EL2			sys_reg(3, 4, 3, 1, 6)
 #define SYS_SPSR_EL2			sys_reg(3, 4, 4, 0, 0)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index c351b4abd5db..c1607b5b7cbf 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -584,7 +584,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 	s8 lvls;
 
 	vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
-	vtcr |= VTCR_EL2_T0SZ(phys_shift);
+	vtcr |= VTCR_T0SZ(phys_shift);
 	/*
 	 * Use a minimum 2 level page table to prevent splitting
 	 * host PMD huge pages at stage2.
@@ -625,8 +625,8 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 
 	/* Set the vmid bits */
 	vtcr |= (get_vmid_bits(mmfr1) == 16) ?
-		VTCR_EL2_VS_16BIT :
-		VTCR_EL2_VS_8BIT;
+		SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 16BIT) :
+		SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 8BIT);
 
 	return vtcr;
 }
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 7b1802a4072e..34d8d192d5c2 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -336,7 +336,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi)
 {
 	wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK;
 
-	switch (vtcr & VTCR_EL2_TG0_MASK) {
+	switch (SYS_FIELD_GET(VTCR_EL2, TG0, vtcr)) {
 	case VTCR_EL2_TG0_4K:
 		wi->pgshift = 12;	 break;
 	case VTCR_EL2_TG0_16K:
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index d2b40105eb41..f5a0a304f844 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4910,6 +4910,63 @@ Field	1	PIE
 Field	0	PnCH
 EndSysreg
 
+Sysreg	VTCR_EL2	3	4	2	1	2
+Res0	63:46
+Field	45	HDBSS
+Field	44	HAFT
+Res0	43:42
+Field	41	TL0
+Field	40	GCSH
+Res0	39
+Field	38	D128
+Field	37	S2POE
+Field	36	S2PIE
+Field	35	TL1
+Field	34	AssuredOnly
+Field	33	SL2
+Field	32	DS
+Res1	31
+Field	30	NSA
+Field	29	NSW
+Field	28	HWU62
+Field	27	HWU61
+Field	26	HWU60
+Field	25	HWU59
+Res0	24:23
+Field	22	HD
+Field	21	HA
+Res0	20
+UnsignedEnum	19	VS
+	0b0	8BIT
+	0b1	16BIT
+EndEnum
+Field	18:16	PS
+UnsignedEnum	15:14	TG0
+		0b00	4K
+		0b01	64K
+		0b10	16K
+EndEnum
+UnsignedEnum	13:12	SH0
+		0b00	NONE
+		0b10	OUTER
+		0b11	INNER
+EndEnum
+UnsignedEnum	11:10	ORGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+UnsignedEnum	9:8	IRGN0
+	0b00	NC
+	0b01	WBWA
+	0b10	WT
+	0b11	WBnWA
+EndEnum
+Field	7:6	SL0
+Field	5:0	T0SZ
+EndSysreg
+
 SysregFields MAIR2_ELx
 Field	63:56	Attr7
 Field	55:48	Attr6
-- 
2.25.1
Re: [PATCH 4/4] arm64/sysreg: Add VTCR_EL2 register
Posted by Mark Rutland 5 months, 3 weeks ago
On Mon, Aug 18, 2025 at 10:27:59AM +0530, Anshuman Khandual wrote:
> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> index d2b40105eb41..f5a0a304f844 100644
> --- a/arch/arm64/tools/sysreg
> +++ b/arch/arm64/tools/sysreg
> @@ -4910,6 +4910,63 @@ Field	1	PIE
>  Field	0	PnCH
>  EndSysreg
>  
> +Sysreg	VTCR_EL2	3	4	2	1	2
> +Res0	63:46
> +Field	45	HDBSS
> +Field	44	HAFT
> +Res0	43:42
> +Field	41	TL0
> +Field	40	GCSH
> +Res0	39
> +Field	38	D128
> +Field	37	S2POE
> +Field	36	S2PIE
> +Field	35	TL1
> +Field	34	AssuredOnly
> +Field	33	SL2
> +Field	32	DS
> +Res1	31
> +Field	30	NSA
> +Field	29	NSW
> +Field	28	HWU62
> +Field	27	HWU61
> +Field	26	HWU60
> +Field	25	HWU59
> +Res0	24:23
> +Field	22	HD
> +Field	21	HA
> +Res0	20
> +UnsignedEnum	19	VS
> +	0b0	8BIT
> +	0b1	16BIT
> +EndEnum

You left TCR_EL1.AS as a single-bit 'Field', so please do the same here
for consistency. I don't think there's much gained by making this any
sort of enum.

> +Field	18:16	PS
> +UnsignedEnum	15:14	TG0
> +		0b00	4K
> +		0b01	64K
> +		0b10	16K
> +EndEnum

As with other patches, this is not ordered. Please use Enum.

Likewise for the other cases below.

Mark.

> +UnsignedEnum	13:12	SH0
> +		0b00	NONE
> +		0b10	OUTER
> +		0b11	INNER
> +EndEnum
> +UnsignedEnum	11:10	ORGN0
> +	0b00	NC
> +	0b01	WBWA
> +	0b10	WT
> +	0b11	WBnWA
> +EndEnum
> +UnsignedEnum	9:8	IRGN0
> +	0b00	NC
> +	0b01	WBWA
> +	0b10	WT
> +	0b11	WBnWA
> +EndEnum
> +Field	7:6	SL0
> +Field	5:0	T0SZ
> +EndSysreg
> +
>  SysregFields MAIR2_ELx
>  Field	63:56	Attr7
>  Field	55:48	Attr6
> -- 
> 2.25.1
> 
>
Re: [PATCH 4/4] arm64/sysreg: Add VTCR_EL2 register
Posted by Anshuman Khandual 5 months, 3 weeks ago

On 18/08/25 2:52 PM, Mark Rutland wrote:
> On Mon, Aug 18, 2025 at 10:27:59AM +0530, Anshuman Khandual wrote:
>> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
>> index d2b40105eb41..f5a0a304f844 100644
>> --- a/arch/arm64/tools/sysreg
>> +++ b/arch/arm64/tools/sysreg
>> @@ -4910,6 +4910,63 @@ Field	1	PIE
>>  Field	0	PnCH
>>  EndSysreg
>>  
>> +Sysreg	VTCR_EL2	3	4	2	1	2
>> +Res0	63:46
>> +Field	45	HDBSS
>> +Field	44	HAFT
>> +Res0	43:42
>> +Field	41	TL0
>> +Field	40	GCSH
>> +Res0	39
>> +Field	38	D128
>> +Field	37	S2POE
>> +Field	36	S2PIE
>> +Field	35	TL1
>> +Field	34	AssuredOnly
>> +Field	33	SL2
>> +Field	32	DS
>> +Res1	31
>> +Field	30	NSA
>> +Field	29	NSW
>> +Field	28	HWU62
>> +Field	27	HWU61
>> +Field	26	HWU60
>> +Field	25	HWU59
>> +Res0	24:23
>> +Field	22	HD
>> +Field	21	HA
>> +Res0	20
>> +UnsignedEnum	19	VS
>> +	0b0	8BIT
>> +	0b1	16BIT
>> +EndEnum
> 
> You left TCR_EL1.AS as a single-bit 'Field', so please do the same here
> for consistency. I don't think there's much gained by making this any
> sort of enum.

But actually there is an use case in kvm_get_vtcr().

        /* Set the vmid bits */
        vtcr |= (get_vmid_bits(mmfr1) == 16) ?
                SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 16BIT) :
                SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 8BIT);

> 
>> +Field	18:16	PS
>> +UnsignedEnum	15:14	TG0
>> +		0b00	4K
>> +		0b01	64K
>> +		0b10	16K
>> +EndEnum
> 
> As with other patches, this is not ordered. Please use Enum.
> 
> Likewise for the other cases below.


Sure, will do the changes.
> 
> Mark.
> 
>> +UnsignedEnum	13:12	SH0
>> +		0b00	NONE
>> +		0b10	OUTER
>> +		0b11	INNER
>> +EndEnum
>> +UnsignedEnum	11:10	ORGN0
>> +	0b00	NC
>> +	0b01	WBWA
>> +	0b10	WT
>> +	0b11	WBnWA
>> +EndEnum
>> +UnsignedEnum	9:8	IRGN0
>> +	0b00	NC
>> +	0b01	WBWA
>> +	0b10	WT
>> +	0b11	WBnWA
>> +EndEnum
>> +Field	7:6	SL0
>> +Field	5:0	T0SZ
>> +EndSysreg
>> +
>>  SysregFields MAIR2_ELx
>>  Field	63:56	Attr7
>>  Field	55:48	Attr6
>> -- 
>> 2.25.1
>>
>>
Re: [PATCH 4/4] arm64/sysreg: Add VTCR_EL2 register
Posted by Marc Zyngier 5 months, 3 weeks ago
On Tue, 19 Aug 2025 05:24:29 +0100,
Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> 
> 
> 
> On 18/08/25 2:52 PM, Mark Rutland wrote:
> > On Mon, Aug 18, 2025 at 10:27:59AM +0530, Anshuman Khandual wrote:
> >> diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
> >> index d2b40105eb41..f5a0a304f844 100644
> >> --- a/arch/arm64/tools/sysreg
> >> +++ b/arch/arm64/tools/sysreg
> >> @@ -4910,6 +4910,63 @@ Field	1	PIE
> >>  Field	0	PnCH
> >>  EndSysreg
> >>  
> >> +Sysreg	VTCR_EL2	3	4	2	1	2
> >> +Res0	63:46
> >> +Field	45	HDBSS
> >> +Field	44	HAFT
> >> +Res0	43:42
> >> +Field	41	TL0
> >> +Field	40	GCSH
> >> +Res0	39
> >> +Field	38	D128
> >> +Field	37	S2POE
> >> +Field	36	S2PIE
> >> +Field	35	TL1
> >> +Field	34	AssuredOnly
> >> +Field	33	SL2
> >> +Field	32	DS
> >> +Res1	31
> >> +Field	30	NSA
> >> +Field	29	NSW
> >> +Field	28	HWU62
> >> +Field	27	HWU61
> >> +Field	26	HWU60
> >> +Field	25	HWU59
> >> +Res0	24:23
> >> +Field	22	HD
> >> +Field	21	HA
> >> +Res0	20
> >> +UnsignedEnum	19	VS
> >> +	0b0	8BIT
> >> +	0b1	16BIT
> >> +EndEnum
> > 
> > You left TCR_EL1.AS as a single-bit 'Field', so please do the same here
> > for consistency. I don't think there's much gained by making this any
> > sort of enum.
> 
> But actually there is an use case in kvm_get_vtcr().
> 
>         /* Set the vmid bits */
>         vtcr |= (get_vmid_bits(mmfr1) == 16) ?
>                 SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 16BIT) :
>                 SYS_FIELD_PREP_ENUM(VTCR_EL2, VS, 8BIT);
>

Here you go (untested):

diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index c351b4abd5db..49266efc8bab 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -623,10 +623,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
 	if (kvm_lpa2_is_enabled())
 		vtcr |= VTCR_EL2_DS;
 
-	/* Set the vmid bits */
-	vtcr |= (get_vmid_bits(mmfr1) == 16) ?
-		VTCR_EL2_VS_16BIT :
-		VTCR_EL2_VS_8BIT;
+	vtcr |= FIELD_PREP(BIT(VTCR_EL2_VS_SHIFT), (get_vmid_bits(mmfr1) == 16));
 
 	return vtcr;
 }

	M.

-- 
Jazz isn't dead. It just smells funny.