[PATCH v15 4/6] KVM: arm64: Set PSTATE.EXLOCK when entering an exception

Mark Brown posted 6 patches 1 month, 2 weeks ago
There is a newer version of this series
[PATCH v15 4/6] KVM: arm64: Set PSTATE.EXLOCK when entering an exception
Posted by Mark Brown 1 month, 2 weeks ago
As per DDI 0487 RWTXBY we need to manage PSTATE.EXLOCK when entering an
exception, when the exception is entered from a lower EL the bit is cleared
while if entering from the same EL it is set to GCSCR_ELx.EXLOCKEN.
Implement this behaviour in enter_exception64().

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/uapi/asm/ptrace.h |  1 +
 arch/arm64/kvm/hyp/exception.c       | 37 ++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 0f39ba4f3efd..f2fb029fb61a 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -56,6 +56,7 @@
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
 #define PSR_N_BIT	0x80000000
+#define PSR_EXLOCK_BIT 0x400000000
 
 #define PSR_BTYPE_SHIFT		10
 
diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index 95d186e0bf54..46e1d0c3038c 100644
--- a/arch/arm64/kvm/hyp/exception.c
+++ b/arch/arm64/kvm/hyp/exception.c
@@ -73,6 +73,38 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
 		vcpu->arch.ctxt.spsr_und = val;
 }
 
+static unsigned long enter_exception64_gcs(struct kvm_vcpu *vcpu,
+					   unsigned long mode,
+					   unsigned long target_mode)
+{
+	u64 gcscr;
+
+	if (!kvm_has_gcs(kern_hyp_va(vcpu->kvm)))
+		return 0;
+
+	/* GCS can't be enabled for 32 bit */
+	if (mode & PSR_MODE32_BIT)
+		return 0;
+
+	/* When taking an exception to a higher EL EXLOCK is cleared. */
+	if ((mode | PSR_MODE_THREAD_BIT) != target_mode)
+		return 0;
+
+	/*
+	 * When taking an exception to the same EL EXLOCK is set to
+	 * the effective value of GCSR_ELx.EXLOCKEN.
+	 */
+	if (vcpu_is_el2(vcpu))
+		gcscr = __vcpu_read_sys_reg(vcpu, GCSCR_EL2);
+	else
+		gcscr = __vcpu_read_sys_reg(vcpu, GCSCR_EL1);
+
+	if (gcscr & GCSCR_ELx_EXLOCKEN)
+		return PSR_EXLOCK_BIT;
+
+	return 0;
+}
+
 /*
  * This performs the exception entry at a given EL (@target_mode), stashing PC
  * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
@@ -162,6 +194,11 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
 	// PSTATE.BTYPE is set to zero upon any exception to AArch64
 	// See ARM DDI 0487E.a, pages D1-2293 to D1-2294.
 
+	// PSTATE.EXLOCK is set to 0 upon any exception to a higher
+	// EL, or to GCSCR_ELx.EXLOCKEN for an exception to the same
+	// exception level.  See ARM DDI 0487 RWTXBY, D.1.3.2 in K.a.
+	new |= enter_exception64_gcs(vcpu, mode, target_mode);
+
 	new |= PSR_D_BIT;
 	new |= PSR_A_BIT;
 	new |= PSR_I_BIT;

-- 
2.39.5
Re: [PATCH v15 4/6] KVM: arm64: Set PSTATE.EXLOCK when entering an exception
Posted by Marc Zyngier 1 month, 2 weeks ago
On Wed, 20 Aug 2025 15:14:44 +0100,
Mark Brown <broonie@kernel.org> wrote:
> 
> As per DDI 0487 RWTXBY we need to manage PSTATE.EXLOCK when entering an

Nit: please use an underscore between the type of a statement and its
"name", as it makes it a bit more readable (R_WTXBY).

> exception, when the exception is entered from a lower EL the bit is cleared
> while if entering from the same EL it is set to GCSCR_ELx.EXLOCKEN.
> Implement this behaviour in enter_exception64().
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  arch/arm64/include/uapi/asm/ptrace.h |  1 +
>  arch/arm64/kvm/hyp/exception.c       | 37 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 38 insertions(+)
> 
> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> index 0f39ba4f3efd..f2fb029fb61a 100644
> --- a/arch/arm64/include/uapi/asm/ptrace.h
> +++ b/arch/arm64/include/uapi/asm/ptrace.h
> @@ -56,6 +56,7 @@
>  #define PSR_C_BIT	0x20000000
>  #define PSR_Z_BIT	0x40000000
>  #define PSR_N_BIT	0x80000000
> +#define PSR_EXLOCK_BIT 0x400000000
>  
>  #define PSR_BTYPE_SHIFT		10
>  
> diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
> index 95d186e0bf54..46e1d0c3038c 100644
> --- a/arch/arm64/kvm/hyp/exception.c
> +++ b/arch/arm64/kvm/hyp/exception.c
> @@ -73,6 +73,38 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
>  		vcpu->arch.ctxt.spsr_und = val;
>  }
>  
> +static unsigned long enter_exception64_gcs(struct kvm_vcpu *vcpu,
> +					   unsigned long mode,
> +					   unsigned long target_mode)

A more appropriate name would be compute_exlock().

> +{
> +	u64 gcscr;
> +
> +	if (!kvm_has_gcs(kern_hyp_va(vcpu->kvm)))
> +		return 0;
> +
> +	/* GCS can't be enabled for 32 bit */
> +	if (mode & PSR_MODE32_BIT)
> +		return 0;
> +
> +	/* When taking an exception to a higher EL EXLOCK is cleared. */
> +	if ((mode | PSR_MODE_THREAD_BIT) != target_mode)
> +		return 0;
> +
> +	/*
> +	 * When taking an exception to the same EL EXLOCK is set to
> +	 * the effective value of GCSR_ELx.EXLOCKEN.
> +	 */
> +	if (vcpu_is_el2(vcpu))
> +		gcscr = __vcpu_read_sys_reg(vcpu, GCSCR_EL2);
> +	else
> +		gcscr = __vcpu_read_sys_reg(vcpu, GCSCR_EL1);
> +
> +	if (gcscr & GCSCR_ELx_EXLOCKEN)
> +		return PSR_EXLOCK_BIT;
> +
> +	return 0;
> +}
> +
>  /*
>   * This performs the exception entry at a given EL (@target_mode), stashing PC
>   * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
> @@ -162,6 +194,11 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
>  	// PSTATE.BTYPE is set to zero upon any exception to AArch64
>  	// See ARM DDI 0487E.a, pages D1-2293 to D1-2294.
>  
> +	// PSTATE.EXLOCK is set to 0 upon any exception to a higher
> +	// EL, or to GCSCR_ELx.EXLOCKEN for an exception to the same
> +	// exception level.  See ARM DDI 0487 RWTXBY, D.1.3.2 in K.a.
> +	new |= enter_exception64_gcs(vcpu, mode, target_mode);
> +
>  	new |= PSR_D_BIT;
>  	new |= PSR_A_BIT;
>  	new |= PSR_I_BIT;
> 

But that's not the only case where we have to deal with EXLOCK, is it?
What of ERET and its PAuth variants? R_TYTWB says:

<quote>
If in AArch64 state, any of the following situations can cause an
illegal exception return:

[...]

- If the Effective value of GCSCR_ELx.EXLOCKEN is 1 and PSTATE.EXLOCK
  is 0, the execution of an exception return instruction to return to
  the current Exception level ELx.
</quote>

My reading of the spec is that this needs handling.

	M.

-- 
Jazz isn't dead. It just smells funny.
Re: [PATCH v15 4/6] KVM: arm64: Set PSTATE.EXLOCK when entering an exception
Posted by Mark Brown 1 month, 1 week ago
On Wed, Aug 20, 2025 at 11:02:11PM +0100, Marc Zyngier wrote:
> Mark Brown <broonie@kernel.org> wrote:

> > As per DDI 0487 RWTXBY we need to manage PSTATE.EXLOCK when entering an

> Nit: please use an underscore between the type of a statement and its
> "name", as it makes it a bit more readable (R_WTXBY).

Updated as you request.  I have seen both usages - the non _ version
plays nicer with searching the PDF to find the rules since you can just
copy it directly into a PDF viewer.

> > +	// EL, or to GCSCR_ELx.EXLOCKEN for an exception to the same
> > +	// exception level.  See ARM DDI 0487 RWTXBY, D.1.3.2 in K.a.
> > +	new |= enter_exception64_gcs(vcpu, mode, target_mode);
> > +
> >  	new |= PSR_D_BIT;
> >  	new |= PSR_A_BIT;
> >  	new |= PSR_I_BIT;

> But that's not the only case where we have to deal with EXLOCK, is it?
> What of ERET and its PAuth variants? R_TYTWB says:

> <quote>
> If in AArch64 state, any of the following situations can cause an
> illegal exception return:
> 
> [...]
> 
> - If the Effective value of GCSCR_ELx.EXLOCKEN is 1 and PSTATE.EXLOCK
>   is 0, the execution of an exception return instruction to return to
>   the current Exception level ELx.
> </quote>

> My reading of the spec is that this needs handling.

Am I right in thinking that this handling is needed for the NV case
only?
Re: [PATCH v15 4/6] KVM: arm64: Set PSTATE.EXLOCK when entering an exception
Posted by Marc Zyngier 3 weeks, 4 days ago
On Thu, 21 Aug 2025 21:44:21 +0100,
Mark Brown <broonie@kernel.org> wrote:
> 
> On Wed, Aug 20, 2025 at 11:02:11PM +0100, Marc Zyngier wrote:
> > Mark Brown <broonie@kernel.org> wrote:
> 
> > > +	// EL, or to GCSCR_ELx.EXLOCKEN for an exception to the same
> > > +	// exception level.  See ARM DDI 0487 RWTXBY, D.1.3.2 in K.a.

nit: I think you can drop the section number in the ARM ARM. The rule
"numbers" are stable across revision of the document, and K.a is
already absolutely ancient (over a year old and two revisions behind).

> > > +	new |= enter_exception64_gcs(vcpu, mode, target_mode);
> > > +
> > >  	new |= PSR_D_BIT;
> > >  	new |= PSR_A_BIT;
> > >  	new |= PSR_I_BIT;
> 
> > But that's not the only case where we have to deal with EXLOCK, is it?
> > What of ERET and its PAuth variants? R_TYTWB says:
> 
> > <quote>
> > If in AArch64 state, any of the following situations can cause an
> > illegal exception return:
> > 
> > [...]
> > 
> > - If the Effective value of GCSCR_ELx.EXLOCKEN is 1 and PSTATE.EXLOCK
> >   is 0, the execution of an exception return instruction to return to
> >   the current Exception level ELx.
> > </quote>
> 
> > My reading of the spec is that this needs handling.
> 
> Am I right in thinking that this handling is needed for the NV case
> only?

So far, NV is indeed the only case where we have to emulate ERET.

	M.

-- 
Without deviation from the norm, progress is not possible.