fix(bl31): allow use of EHF with S-EL2 SPMC

Currently, when SPMC at S-EL2 is used, we cannot use the RAS framework
to handle Group 0 interrupts. This is required on platforms where first
level of triaging needs to occur at EL3, before forwarding RAS handling
to a secure partition running atop an SPMC (hafnium).
The RAS framework depends on EHF and EHF registers for Group 0
interrupts to be trapped to EL3 when execution is both in secure world
and normal world. However, an FF-A compliant SPMC requires secure
interrupts to be trapped by the SPMC when execution is in S-EL0/S-EL1.
Consequently, the SPMC (hafnium) is incompatible with EHF, since it is
not re-entrant, and a Group 0 interrupt trapped to EL3 when execution is
in secure world, cannot be forwarded to an SP running atop SPMC.
This patch changes EHF to only register for Group 0 interrupts to be
trapped to EL3 when execution is in normal world and also makes it a
valid routing model to do so, when EL3_EXCEPTION_HANDLING is set (when
enabling the RAS framework).

Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: I72d4cf4d8ecc549a832d1c36055fbe95866747fe
This commit is contained in:
Raghu Krishnamurthy 2022-07-25 14:44:33 -07:00
parent 6a5022278b
commit 7c2fe62f13
3 changed files with 26 additions and 8 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -475,9 +475,16 @@ void __init ehf_init(void)
assert((exception_data.pri_bits >= 1U) ||
(exception_data.pri_bits < 8U));
/* Route EL3 interrupts when in Secure and Non-secure. */
/* Route EL3 interrupts when in Non-secure. */
set_interrupt_rm_flag(flags, NON_SECURE);
/*
* Route EL3 interrupts when in secure, only when SPMC is not present
* in S-EL2.
*/
#if !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1))
set_interrupt_rm_flag(flags, SECURE);
#endif /* !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1)) */
/* Register handler for EL3 interrupts */
ret = register_interrupt_type_handler(INTR_TYPE_EL3,

View file

@ -461,8 +461,11 @@ Common build options
- ``EL3_EXCEPTION_HANDLING``: When set to ``1``, enable handling of exceptions
targeted at EL3. When set ``0`` (default), no exceptions are expected or
handled at EL3, and a panic will result. This is supported only for AArch64
builds.
handled at EL3, and a panic will result. The exception to this rule is when
``SPMD_SPM_AT_SEL2`` is set to ``1``, in which case, only exceptions
occuring during normal world execution, are trapped to EL3. Any exception
trapped during secure world execution are trapped to the SPMC. This is
supported only for AArch64 builds.
- ``EVENT_LOG_LEVEL``: Chooses the log level to use for Measured Boot when
``MEASURED_BOOT`` is enabled. For a list of valid values, see ``LOG_LEVEL``.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -107,15 +107,23 @@ static inline int32_t validate_ns_interrupt_rm(uint32_t x)
static inline int32_t validate_el3_interrupt_rm(uint32_t x)
{
#if EL3_EXCEPTION_HANDLING
#if defined (EL3_EXCEPTION_HANDLING) && !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1))
/*
* With EL3 exception handling, EL3 interrupts are always routed to EL3
* from both Secure and Non-secure, and therefore INTR_EL3_VALID_RM1 is
* the only valid routing model.
* from both Secure and Non-secure, when the SPMC does not live in S-EL2.
* Therefore INTR_EL3_VALID_RM1 is the only valid routing model.
*/
if (x == INTR_EL3_VALID_RM1)
return 0;
#else
/*
* When EL3_EXCEPTION_HANDLING is not defined both routing modes are
* valid. This is the most common case. The exception to this rule is
* when EL3_EXCEPTION_HANDLING is defined but also when the SPMC lives
* at S-EL2. In this case, Group0 Interrupts are trapped to the SPMC
* when running in S-EL0 and S-EL1. The SPMC may handle the interrupt
* itself, delegate it to an SP or forward to EL3 for handling.
*/
if ((x == INTR_EL3_VALID_RM0) || (x == INTR_EL3_VALID_RM1))
return 0;
#endif