aboutsummaryrefslogtreecommitdiff
path: root/services/std_svc/sdei/sdei_intr_mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'services/std_svc/sdei/sdei_intr_mgmt.c')
-rw-r--r--services/std_svc/sdei/sdei_intr_mgmt.c52
1 files changed, 34 insertions, 18 deletions
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
index fa1d3d2839..c58adba50c 100644
--- a/services/std_svc/sdei/sdei_intr_mgmt.c
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -1,15 +1,19 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
#include <string.h>
#include <arch_helpers.h>
+#include <arch_features.h>
#include <bl31/ehf.h>
#include <bl31/interrupt_mgmt.h>
+#include <bl31/sync_handle.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
@@ -232,6 +236,25 @@ static cpu_context_t *restore_and_resume_ns_context(void)
}
/*
+ * Prepare for ERET:
+ * - Set the ELR to the registered handler address
+ * - Set the SPSR register by calling the common create_spsr() function
+ */
+
+static void sdei_set_elr_spsr(sdei_entry_t *se, sdei_dispatch_context_t *disp_ctx)
+{
+ unsigned int client_el = sdei_client_el();
+ u_register_t sdei_spsr = SPSR_64(client_el, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+
+ u_register_t interrupted_pstate = disp_ctx->spsr_el3;
+
+ sdei_spsr = create_spsr(interrupted_pstate, client_el);
+
+ cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep, sdei_spsr);
+}
+
+/*
* Populate the Non-secure context so that the next ERET will dispatch to the
* SDEI client.
*/
@@ -256,15 +279,8 @@ static void setup_ns_dispatch(sdei_ev_map_t *map, sdei_entry_t *se,
SMC_SET_GP(ctx, CTX_GPREG_X2, disp_ctx->elr_el3);
SMC_SET_GP(ctx, CTX_GPREG_X3, disp_ctx->spsr_el3);
- /*
- * Prepare for ERET:
- *
- * - Set PC to the registered handler address
- * - Set SPSR to jump to client EL with exceptions masked
- */
- cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep,
- SPSR_64(sdei_client_el(), MODE_SP_ELX,
- DISABLE_ALL_EXCEPTIONS));
+ /* Setup the elr and spsr register to prepare for ERET */
+ sdei_set_elr_spsr(se, disp_ctx);
#if DYNAMIC_WORKAROUND_CVE_2018_3639
cve_2018_3639_t *tgt_cve_2018_3639;
@@ -394,8 +410,8 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
* Interrupts received while this PE was masked can't be
* dispatched.
*/
- SDEI_LOG("interrupt %u on %llx while PE masked\n", map->intr,
- mpidr);
+ SDEI_LOG("interrupt %u on %" PRIx64 " while PE masked\n",
+ map->intr, mpidr);
if (is_event_shared(map))
sdei_map_lock(map);
@@ -466,8 +482,8 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
if (is_event_shared(map))
sdei_map_unlock(map);
- SDEI_LOG("ACK %llx, ev:%d ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num,
- sec_state, read_spsr_el3(), read_elr_el3());
+ SDEI_LOG("ACK %" PRIx64 ", ev:0x%x ss:%d spsr:%lx ELR:%lx\n",
+ mpidr, map->ev_num, sec_state, read_spsr_el3(), read_elr_el3());
ctx = handle;
@@ -503,7 +519,7 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
* interrupt.
*/
if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) {
- ERROR("Invalid SDEI mapping: ev=%u\n", map->ev_num);
+ ERROR("Invalid SDEI mapping: ev=0x%x\n", map->ev_num);
panic();
}
plat_ic_end_of_interrupt(intr_raw);
@@ -571,15 +587,15 @@ int sdei_dispatch_event(int ev_num)
if (!can_sdei_state_trans(se, DO_DISPATCH))
return -1;
- /* Activate the priority corresponding to the event being dispatched */
- ehf_activate_priority(sdei_event_priority(map));
-
/*
* Prepare for NS dispatch by restoring the Non-secure context and
* marking that as active.
*/
ns_ctx = restore_and_resume_ns_context();
+ /* Activate the priority corresponding to the event being dispatched */
+ ehf_activate_priority(sdei_event_priority(map));
+
/* Dispatch event synchronously */
setup_ns_dispatch(map, se, ns_ctx, &dispatch_jmp);
begin_sdei_synchronous_dispatch(&dispatch_jmp);