bl32: add secure interrupt handling in AArch32 sp_min
Add support for a minimal secure interrupt service in sp_min for
the AArch32 implementation. Hard code that only FIQs are handled.
Introduce bolean build directive SP_MIN_WITH_SECURE_FIQ to enable
FIQ handling from SP_MIN.
Configure SCR[FIQ] and SCR[FW] from generic code for both cold and
warm boots to handle FIQ in secure state from monitor.
Since SP_MIN architecture, FIQ are always trapped when system executes
in non secure state. Hence discard relay of the secure/non-secure
state in the FIQ handler.
Change-Id: I1f7d1dc7b21f6f90011b7f3fcd921e455592f5e7
Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
index b3fccde..d868c53 100644
--- a/bl32/sp_min/aarch32/entrypoint.S
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -18,6 +18,17 @@
.globl sp_min_entrypoint
.globl sp_min_warm_entrypoint
+ .macro route_fiq_to_sp_min reg
+ /* -----------------------------------------------------
+ * FIQs are secure interrupts trapped by Monitor and non
+ * secure is not allowed to mask the FIQs.
+ * -----------------------------------------------------
+ */
+ ldcopr \reg, SCR
+ orr \reg, \reg, #SCR_FIQ_BIT
+ bic \reg, \reg, #SCR_FW_BIT
+ stcopr \reg, SCR
+ .endm
vector_base sp_min_vector_table
b sp_min_entrypoint
@@ -27,7 +38,7 @@
b plat_panic_handler /* Data abort */
b plat_panic_handler /* Reserved */
b plat_panic_handler /* IRQ */
- b plat_panic_handler /* FIQ */
+ b handle_fiq /* FIQ */
/*
@@ -92,6 +103,10 @@
mov r1, #0
#endif /* RESET_TO_SP_MIN */
+#if SP_MIN_WITH_SECURE_FIQ
+ route_fiq_to_sp_min r4
+#endif
+
bl sp_min_early_platform_setup
bl sp_min_plat_arch_setup
@@ -166,6 +181,44 @@
endfunc handle_smc
/*
+ * Secure Interrupts handling function for SP_MIN.
+ */
+func handle_fiq
+#if !SP_MIN_WITH_SECURE_FIQ
+ b plat_panic_handler
+#else
+ /* FIQ has a +4 offset for lr compared to preferred return address */
+ sub lr, lr, #4
+ /* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
+ str lr, [sp, #SMC_CTX_LR_MON]
+
+ smcc_save_gp_mode_regs
+
+ /*
+ * AArch32 architectures need to clear the exclusive access when
+ * entering Monitor mode.
+ */
+ clrex
+
+ /* load run-time stack */
+ mov r2, sp
+ ldr sp, [r2, #SMC_CTX_SP_MON]
+
+ /* Switch to Secure Mode */
+ ldr r0, [r2, #SMC_CTX_SCR]
+ bic r0, #SCR_NS_BIT
+ stcopr r0, SCR
+ isb
+
+ push {r2, r3}
+ bl sp_min_fiq
+ pop {r0, r3}
+
+ b sp_min_exit
+#endif
+endfunc handle_fiq
+
+/*
* The Warm boot entrypoint for SP_MIN.
*/
func sp_min_warm_entrypoint
@@ -213,6 +266,10 @@
mov r0, #DISABLE_DCACHE
bl bl32_plat_enable_mmu
+#if SP_MIN_WITH_SECURE_FIQ
+ route_fiq_to_sp_min r0
+#endif
+
#if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY
ldcopr r0, SCTLR
orr r0, r0, #SCTLR_C_BIT
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index f6e58e9..39588ce 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -37,3 +37,9 @@
RESET_TO_SP_MIN := 0
$(eval $(call add_define,RESET_TO_SP_MIN))
$(eval $(call assert_boolean,RESET_TO_SP_MIN))
+
+# Flag to allow SP_MIN to handle FIQ interrupts in monitor mode. The platform
+# port is free to override this value. It is default disabled.
+SP_MIN_WITH_SECURE_FIQ ?= 0
+$(eval $(call add_define,SP_MIN_WITH_SECURE_FIQ))
+$(eval $(call assert_boolean,SP_MIN_WITH_SECURE_FIQ))
diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
index 1c83cbe..06b0f33 100644
--- a/bl32/sp_min/sp_min_main.c
+++ b/bl32/sp_min/sp_min_main.c
@@ -207,3 +207,19 @@
copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
next_smc_ctx);
}
+
+#if SP_MIN_WITH_SECURE_FIQ
+/******************************************************************************
+ * This function is invoked on secure interrupts. By construction of the
+ * SP_MIN, secure interrupts can only be handled when core executes in non
+ * secure state.
+ *****************************************************************************/
+void sp_min_fiq(void)
+{
+ uint32_t id;
+
+ id = plat_ic_acknowledge_interrupt();
+ sp_min_plat_fiq_handler(id);
+ plat_ic_end_of_interrupt(id);
+}
+#endif /* SP_MIN_WITH_SECURE_FIQ */
diff --git a/bl32/sp_min/sp_min_private.h b/bl32/sp_min/sp_min_private.h
index 97185b9..1836af9 100644
--- a/bl32/sp_min/sp_min_private.h
+++ b/bl32/sp_min/sp_min_private.h
@@ -10,5 +10,6 @@
void sp_min_warm_entrypoint(void);
void sp_min_main(void);
void sp_min_warm_boot(void);
+void sp_min_fiq(void);
#endif /* __SP_MIN_H__ */