Core: Initial implementation of sec IRQ handling
This commit makes possible for partitions to define IRQ handlers that
are executed in case of an interrupt is triggered, with the isolation
required by TFM_LVL settings.
Detailed changes:
- Add template files to generate code for configuring IRQs, and set
up IRQ handlers based on information provided in the partition's
manifest
- Add capability to Core to isolate the IRQ handlers
- Add documentation
Change-Id: I0e46b9a41fb4e20ca4c398acf5ce1d4027e8597f
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/docs/index.rst.in b/docs/index.rst.in
index e2151a4..010443d 100644
--- a/docs/index.rst.in
+++ b/docs/index.rst.in
@@ -29,6 +29,7 @@
docs/user_guides/tfm_integration_guide
docs/user_guides/tfm_ns_client_identification
docs/user_guides/tfm_secure_boot
+ docs/user_guides/tfm_secure_irq_handling
.. toctree::
:maxdepth: 2
diff --git a/docs/user_guides/tfm_secure_irq_handling.rst b/docs/user_guides/tfm_secure_irq_handling.rst
new file mode 100644
index 0000000..77993a3
--- /dev/null
+++ b/docs/user_guides/tfm_secure_irq_handling.rst
@@ -0,0 +1,180 @@
+###################
+Secure IRQ handling
+###################
+
+The Armv8-M Architecture makes it possible to configure interrupts to target
+secure state.
+
+TF-M makes it possible for secure partitions to get notified of secure
+interrupts.
+
+By default TF-M sets up interrupts to target NS state. To configure an interrupt
+to target secure state and assign a handler to it, the manifest of the partition
+must be edited.
+
+See the following example:
+
+
+.. code-block:: yaml
+
+ {
+ "name": "...",
+ "type": "...",
+ "priority": "...",
+
+ ...
+
+ "irqs": [
+ {
+ "line_num": "5",
+ "signal": "DUAL_TIMER"
+ },
+ {
+ "line_name": "TFM_IRQ_LINE_TIMER_1",
+ "signal": "TIMER_1"
+ "tfm_irq_priority": 64,
+ }
+ ],
+
+ ...
+
+ }
+
+To set up a handler in a partition, the ``irqs`` node must be added. A single
+secure partition can have handlers registered for multiple IRQs, in this case
+the list ``irqs`` has multiple elements in it.
+
+An IRQ handler is defined by the following nodes:
+
+- ``line_num``: The number of the IRQ.
+- ``line_name``: The name of the IRQ line. With the name of the IRQ line there
+ must be defined a macro in ``tfm_peripherals_def.h`` which is substituted to
+ the IRQ line num.
+- ``signal`` The name of the signal for this IRQ
+- ``tfm_irq_priority``: The priority of the IRQ. This number must be in the
+ range [0-255] inclusive. Please note that some of the less significant bits of
+ this value might be dropped based on the number of priority bits implemented
+ in the platform.
+
+.. important::
+
+ The name of the privileged interrupt handler is derived from the node
+ specifying the IRQ line number.
+
+ - In case ``line_num`` is provided, the name of the handler becomes
+ ``void irq_<line_num>_Handler(void)``.
+ - In case ``line_name`` is provided, the name of the handler becomes
+ ``void <line_name>_Handler(void)``.
+
+ This is important, because the derived name have to be present in the vector
+ table as the handler of the IRQ.
+
+.. Note::
+
+ ``signal`` is mandatory. Specifying the IRQ line is also mandatory, so exactly
+ one of ``line_num`` and ``line_name`` must be defined.
+
+ ``tfm_irq_priority`` is optional. If ``tfm_irq_priority`` is not set for an
+ IRQ, the default is value is ``TFM_DEFAULT_SECURE_IRQ_PRIOTITY``.
+
+If an IRQ handler is registered, TF-M will:
+
+- Set the IRQ with number ``line_num`` or ``line_name`` to target secure state
+- Set the priority of IRQ with number ``line_num`` or ``line_name`` to
+ ``tfm_irq_priority`` or to the default.
+
+TF-M configures the interrupt lines to be disabled by default. Interrupts for a
+service can be enabled by the secure service by calling
+``void tfm_enable_irq(psa_signal_t irq_signal)``. The function can be called in
+the service init function.
+
+*************
+Library model
+*************
+
+In Library model a function with the name derived from the value of the
+``line_num`` or ``line_name`` property is generated. This function will be put
+in the vector table by the linker (as the handlers in the startup assembly are
+defined as weak symbols). The code generated for this function will forward the
+call to the function with the name of the value of the ``signal`` property
+post-fixed with ``_isr``.
+
+.. hint::
+
+ for a signal ``"signal": "DUAL_TIMER"`` the name of the handler function is
+ ``DUAL_TIMER_isr``
+
+The signature of the IRQ handler in the partition must be the following:
+
+.. code-block:: c
+
+ void partition_irq_handler(void);
+
+The detailed description on how secure interrupt handling works in the Library
+model see
+`Secure Partition Interrupt Handling design document <https://developer.trustedfirmware.org/w/tf_m/design/secure_partition_interrupt_handling/>`_.
+
+*********
+IPC model
+*********
+
+The detailed description on how secure interrupt handling works in the IPC
+model, see the
+`PSA Firmware Framework and RoT Services specification <https://pages.arm.com/psa-resources-ff.html>`_.
+
+######################
+Implementation details
+######################
+
+*************
+Library model
+*************
+
+As a result of the function call like behaviour of secure services in library
+model, some information that is critical for the SPM to keep track of partition
+states, is stored on the stack of the active partitions. When an interrupt
+happens, and a handler partition is set to running state, it has access to its
+whole stack, and could corrupt the data stacked by the SPM. To prevent this, a
+separate Context stack is introduced for each secure partition, that is used by
+the SPM to save this information before starting to execute secure partition
+code.
+
+A stack frame to this context stack is pushed when the execution in the
+partition is interrupted, and when a handler in the partition interrupts another
+service. So the maximal stack usage can happen in the following situation:
+
+Consider secure partition 'A'. 'A' is running, and then it is interrupted by
+an other partition. Then the lowest priority interrupt of 'A' is triggered.
+Then before the handler returns, the partition is interrupted by another
+partition's handler. Then before the running handler returns, the second
+lowest interrupt of 'A' is triggered. This can go until the highest priority
+interrupt of 'A' is triggered, and then this last handler is interrupted. At
+this point the context stack looks like this:
+
+.. code-block::
+
+ +------------+
+ | [intr_ctx] |
+ | [hndl_ctx] |
+ | . |
+ | . |
+ | . |
+ | [intr_ctx] |
+ | [hndl_ctx] |
+ | [intr_ctx] |
+ +------------+
+
+ Legend:
+ [intr_ctx]: Frame pushed when the partition is interrupted
+ [hndl_ctx]: Frame pushed when the partition is handling an interrupt
+
+So the max stack size can be calculated as a function of the IRQ count of 'A':
+
+.. code-block::
+
+
+ max_stack_size = intr_ctx_size + (IRQ_CNT * (intr_ctx_size + hndl_ctx_size))
+
+--------------
+
+*Copyright (c) 2018-2019, Arm Limited. All rights reserved.*
diff --git a/interface/include/tfm_api.h b/interface/include/tfm_api.h
index 2ba93c0..8e152ff 100644
--- a/interface/include/tfm_api.h
+++ b/interface/include/tfm_api.h
@@ -38,6 +38,9 @@
/* Maximum number of input and output vectors */
#define PSA_MAX_IOVEC (4)
+/* The mask used for timeout values */
+#define PSA_TIMEOUT_MASK PSA_BLOCK
+
/* FixMe: sort out DEBUG compile option and limit return value options
* on external interfaces */
/* For secure functions using prorietary signatures
diff --git a/platform/ext/target/mps2/an519/spm_hal.c b/platform/ext/target/mps2/an519/spm_hal.c
index e486e52..1c07116 100644
--- a/platform/ext/target/mps2/an519/spm_hal.c
+++ b/platform/ext/target/mps2/an519/spm_hal.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include "cmsis.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
@@ -398,3 +399,37 @@
uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
NVIC_SetPriority(irq_line, quantized_priority);
}
+
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(int32_t irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(int32_t irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state)
+{
+ uint32_t result;
+
+ if (target_state == TFM_IRQ_TARGET_STATE_SECURE) {
+ result = NVIC_ClearTargetState(irq_line);
+ } else {
+ result = NVIC_SetTargetState(irq_line);
+ }
+
+ if (result) {
+ return TFM_IRQ_TARGET_STATE_NON_SECURE;
+ } else {
+ return TFM_IRQ_TARGET_STATE_SECURE;
+ }
+}
diff --git a/platform/ext/target/mps2/an519/tfm_peripherals_def.h b/platform/ext/target/mps2/an519/tfm_peripherals_def.h
index 340a19c..b5f963c 100644
--- a/platform/ext/target/mps2/an519/tfm_peripherals_def.h
+++ b/platform/ext/target/mps2/an519/tfm_peripherals_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,6 +8,8 @@
#ifndef __TFM_PERIPHERALS_DEF_H__
#define __TFM_PERIPHERALS_DEF_H__
+#define TFM_TIMER0_IRQ (3)
+
struct tfm_spm_partition_platform_data_t;
extern struct tfm_spm_partition_platform_data_t tfm_peripheral_std_uart;
diff --git a/platform/ext/target/mps2/an521/spm_hal.c b/platform/ext/target/mps2/an521/spm_hal.c
index 193b2a3..bc91d41 100644
--- a/platform/ext/target/mps2/an521/spm_hal.c
+++ b/platform/ext/target/mps2/an521/spm_hal.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include "cmsis.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
@@ -398,3 +399,37 @@
uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
NVIC_SetPriority(irq_line, quantized_priority);
}
+
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(int32_t irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(int32_t irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state)
+{
+ uint32_t result;
+
+ if (target_state == TFM_IRQ_TARGET_STATE_SECURE) {
+ result = NVIC_ClearTargetState(irq_line);
+ } else {
+ result = NVIC_SetTargetState(irq_line);
+ }
+
+ if (result) {
+ return TFM_IRQ_TARGET_STATE_NON_SECURE;
+ } else {
+ return TFM_IRQ_TARGET_STATE_SECURE;
+ }
+}
diff --git a/platform/ext/target/mps2/an521/tfm_peripherals_def.h b/platform/ext/target/mps2/an521/tfm_peripherals_def.h
index 340a19c..b5f963c 100644
--- a/platform/ext/target/mps2/an521/tfm_peripherals_def.h
+++ b/platform/ext/target/mps2/an521/tfm_peripherals_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,6 +8,8 @@
#ifndef __TFM_PERIPHERALS_DEF_H__
#define __TFM_PERIPHERALS_DEF_H__
+#define TFM_TIMER0_IRQ (3)
+
struct tfm_spm_partition_platform_data_t;
extern struct tfm_spm_partition_platform_data_t tfm_peripheral_std_uart;
diff --git a/platform/ext/target/mps3/an524/spm_hal.c b/platform/ext/target/mps3/an524/spm_hal.c
index 0d1316d..361d332 100644
--- a/platform/ext/target/mps3/an524/spm_hal.c
+++ b/platform/ext/target/mps3/an524/spm_hal.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include "cmsis.h"
#include "tfm_spm_hal.h"
#include "tfm_platform_core_api.h"
#include "spm_db.h"
@@ -427,3 +428,37 @@
uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
NVIC_SetPriority(irq_line, quantized_priority);
}
+
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(int32_t irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(int32_t irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state)
+{
+ uint32_t result;
+
+ if (target_state == TFM_IRQ_TARGET_STATE_SECURE) {
+ result = NVIC_ClearTargetState(irq_line);
+ } else {
+ result = NVIC_SetTargetState(irq_line);
+ }
+
+ if (result) {
+ return TFM_IRQ_TARGET_STATE_NON_SECURE;
+ } else {
+ return TFM_IRQ_TARGET_STATE_SECURE;
+ }
+}
diff --git a/platform/ext/target/mps3/an524/tfm_peripherals_def.h b/platform/ext/target/mps3/an524/tfm_peripherals_def.h
index 7966756..e56cde2 100644
--- a/platform/ext/target/mps3/an524/tfm_peripherals_def.h
+++ b/platform/ext/target/mps3/an524/tfm_peripherals_def.h
@@ -12,6 +12,8 @@
extern "C" {
#endif
+#define TFM_TIMER0_IRQ (3)
+
struct tfm_spm_partition_platform_data_t;
extern struct tfm_spm_partition_platform_data_t tfm_peripheral_std_uart;
diff --git a/platform/ext/target/musca_a/spm_hal.c b/platform/ext/target/musca_a/spm_hal.c
index e658fc8..5637aaf 100644
--- a/platform/ext/target/musca_a/spm_hal.c
+++ b/platform/ext/target/musca_a/spm_hal.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include "cmsis.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
@@ -398,3 +399,37 @@
uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
NVIC_SetPriority(irq_line, quantized_priority);
}
+
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(int32_t irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(int32_t irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state)
+{
+ uint32_t result;
+
+ if (target_state == TFM_IRQ_TARGET_STATE_SECURE) {
+ result = NVIC_ClearTargetState(irq_line);
+ } else {
+ result = NVIC_SetTargetState(irq_line);
+ }
+
+ if (result) {
+ return TFM_IRQ_TARGET_STATE_NON_SECURE;
+ } else {
+ return TFM_IRQ_TARGET_STATE_SECURE;
+ }
+}
diff --git a/platform/ext/target/musca_a/tfm_peripherals_def.h b/platform/ext/target/musca_a/tfm_peripherals_def.h
index ab5f174..f47e756 100644
--- a/platform/ext/target/musca_a/tfm_peripherals_def.h
+++ b/platform/ext/target/musca_a/tfm_peripherals_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -8,6 +8,8 @@
#ifndef __TFM_PERIPHERALS_DEF_H__
#define __TFM_PERIPHERALS_DEF_H__
+#define TFM_TIMER0_IRQ (3)
+
struct tfm_spm_partition_platform_data_t;
extern struct tfm_spm_partition_platform_data_t tfm_peripheral_std_uart;
diff --git a/platform/ext/target/musca_b1/spm_hal.c b/platform/ext/target/musca_b1/spm_hal.c
index 1e350ca..84fc144 100644
--- a/platform/ext/target/musca_b1/spm_hal.c
+++ b/platform/ext/target/musca_b1/spm_hal.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include "cmsis.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
@@ -398,3 +399,37 @@
uint32_t quantized_priority = priority >> (8U - __NVIC_PRIO_BITS);
NVIC_SetPriority(irq_line, quantized_priority);
}
+
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line)
+{
+ NVIC_ClearPendingIRQ(irq_line);
+}
+
+void tfm_spm_hal_enable_irq(int32_t irq_line)
+{
+ NVIC_EnableIRQ(irq_line);
+}
+
+void tfm_spm_hal_disable_irq(int32_t irq_line)
+{
+ NVIC_DisableIRQ(irq_line);
+}
+
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state)
+{
+ uint32_t result;
+
+ if (target_state == TFM_IRQ_TARGET_STATE_SECURE) {
+ result = NVIC_ClearTargetState(irq_line);
+ } else {
+ result = NVIC_SetTargetState(irq_line);
+ }
+
+ if (result) {
+ return TFM_IRQ_TARGET_STATE_NON_SECURE;
+ } else {
+ return TFM_IRQ_TARGET_STATE_SECURE;
+ }
+}
diff --git a/platform/ext/target/musca_b1/tfm_peripherals_def.h b/platform/ext/target/musca_b1/tfm_peripherals_def.h
index d9bcc1d..6663f8b 100644
--- a/platform/ext/target/musca_b1/tfm_peripherals_def.h
+++ b/platform/ext/target/musca_b1/tfm_peripherals_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -12,6 +12,8 @@
extern "C" {
#endif
+#define TFM_TIMER0_IRQ (3)
+
struct tfm_spm_partition_platform_data_t;
extern struct tfm_spm_partition_platform_data_t tfm_peripheral_std_uart;
diff --git a/platform/include/tfm_spm_hal.h b/platform/include/tfm_spm_hal.h
index 3458b17..cb54186 100644
--- a/platform/include/tfm_spm_hal.h
+++ b/platform/include/tfm_spm_hal.h
@@ -28,6 +28,11 @@
*/
struct tfm_spm_partition_platform_data_t;
+enum irq_target_state_t {
+ TFM_IRQ_TARGET_STATE_SECURE,
+ TFM_IRQ_TARGET_STATE_NON_SECURE,
+};
+
#if defined (TFM_PSA_API) || (TFM_LVL != 1)
/**
* \brief Holds SPM db fields that define the memory regions used by a
@@ -160,6 +165,42 @@
*/
void tfm_spm_hal_set_secure_irq_priority(int32_t irq_line, uint32_t priority);
+/**
+ * \brief Clears a pending IRQ
+ *
+ * \param[in] irq_line The IRQ to clear pending for.
+ */
+void tfm_spm_hal_clear_pending_irq(int32_t irq_line);
+
+/**
+ * \brief Enables an IRQ
+ *
+ * \param[in] irq_line The IRQ to be enabled.
+ */
+void tfm_spm_hal_enable_irq(int32_t irq_line);
+
+/**
+ * \brief Disables an IRQ
+ *
+ * \param[in] irq_line The IRQ to be disabled
+ */
+void tfm_spm_hal_disable_irq(int32_t irq_line);
+
+/**
+ * \brief Set the target state of an IRQ
+ *
+ * \param[in] irq_line The IRQ to set the priority for.
+ * \param[in] target_state Target state to ret for the IRQ.
+ *
+ * \return TFM_IRQ_TARGET_STATE_SECURE if interrupt is assigned
+ * to Secure
+ * TFM_IRQ_TARGET_STATE_NON_SECURE if interrupt is
+ * assigned to Non-Secure
+ */
+enum irq_target_state_t tfm_spm_hal_set_irq_target_state(
+ int32_t irq_line,
+ enum irq_target_state_t target_state);
+
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
/**
* \brief Configure the sandbox for a partition.
diff --git a/secure_fw/core/arch/tfm_arch_v8m_base.c b/secure_fw/core/arch/tfm_arch_v8m_base.c
index 35029b1..6aa969a 100644
--- a/secure_fw/core/arch/tfm_arch_v8m_base.c
+++ b/secure_fw/core/arch/tfm_arch_v8m_base.c
@@ -123,6 +123,53 @@
[SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
+
+__attribute__((section("SFN"), naked))
+void priv_irq_handler_main(uint32_t partition_id,
+ uint32_t unpriv_handler,
+ uint32_t irq_signal,
+ uint32_t irq_line)
+{
+ __ASM(
+ /* Save the callee saved registers*/
+ "PUSH {r4-r7, lr} \n"
+ "MOV r4, r8 \n"
+ "MOV r5, r9 \n"
+ "MOV r6, r10 \n"
+ "MOV r7, r11 \n"
+ "PUSH {r4-r7} \n"
+ "MOV r4, r12 \n"
+ "PUSH {r4} \n"
+ /* Request SVC to configure environment for the unpriv IRQ handler */
+ "SVC %[SVC_REQ] \n"
+ /* clear the callee saved registers to prevent information leak */
+ "MOVS r4, #0 \n"
+ "MOV r5, r4 \n"
+ "MOV r6, r4 \n"
+ "MOV r7, r4 \n"
+ "MOV r8, r4 \n"
+ "MOV r9, r4 \n"
+ "MOV r10, r4 \n"
+ "MOV r11, r4 \n"
+ /* Branch to the unprivileged handler */
+ "BLX lr \n"
+ /* Request SVC to reconfigure the environment of the interrupted
+ * partition
+ */
+ "SVC %[SVC_RET] \n"
+ /* restore callee saved registers and return */
+ "POP {r4} \n"
+ "MOV r12, r4 \n"
+ "POP {r4-r7} \n"
+ "MOV r8, r4 \n"
+ "MOV r9, r5 \n"
+ "MOV r10, r6 \n"
+ "MOV r11, r7 \n"
+ "POP {r4-r7, pc} \n"
+ : : [SVC_REQ] "I" (TFM_SVC_DEPRIV_REQ)
+ , [SVC_RET] "I" (TFM_SVC_DEPRIV_RET)
+ : "r0");
+}
#endif
/**
@@ -145,19 +192,19 @@
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- ".syntax unified\n"
- "MOVS r0, #4 \n" /* Check store SP in thread mode to r0 */
- "MOV r1, lr \n"
- "TST r0, r1 \n"
- "BEQ handler \n"
- "MRS r0, PSP \n" /* Coming from thread mode */
- "B sp_stored \n"
- "handler: \n"
- "BX lr \n" /* Coming from handler mode */
- "sp_stored: \n"
- "MOV r1, lr \n"
- "BL SVCHandler_main \n"
- "BX r0 \n"
+ ".syntax unified \n"
+ "MRS r2, MSP \n"
+ "MOVS r1, #4 \n"
+ "MOV r3, lr \n"
+ "MOV r0, r2 \n"
+ "TST r1, r3 \n"
+ "BEQ handler \n"
+ /* If SVC was made from thread mode, overwrite r0 with PSP */
+ "MRS r0, PSP \n"
+ "handler: \n"
+ "MOV r1, lr \n"
+ "BL SVCHandler_main \n"
+ "BX r0 \n"
);
}
diff --git a/secure_fw/core/arch/tfm_arch_v8m_main.c b/secure_fw/core/arch/tfm_arch_v8m_main.c
index b27650d..3035d3c 100644
--- a/secure_fw/core/arch/tfm_arch_v8m_main.c
+++ b/secure_fw/core/arch/tfm_arch_v8m_main.c
@@ -108,6 +108,39 @@
[SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
+
+__attribute__((section("SFN"), naked))
+void priv_irq_handler_main(uint32_t partition_id,
+ uint32_t unpriv_handler,
+ uint32_t irq_signal,
+ uint32_t irq_line)
+{
+ __ASM(
+ /* Save the callee saved registers*/
+ "PUSH {r4-r12, lr} \n"
+ /* Request SVC to configure environment for the unpriv IRQ handler */
+ "SVC %[SVC_REQ] \n"
+ /* clear the callee saved registers to prevent information leak */
+ "MOV r4, #0 \n"
+ "MOV r5, #0 \n"
+ "MOV r6, #0 \n"
+ "MOV r7, #0 \n"
+ "MOV r8, #0 \n"
+ "MOV r9, #0 \n"
+ "MOV r10, #0 \n"
+ "MOV r11, #0 \n"
+ /* Branch to the unprivileged handler */
+ "BLX lr \n"
+ /* Request SVC to reconfigure the environment of the interrupted
+ * partition
+ */
+ "SVC %[SVC_RET] \n"
+ /* restore callee saved registers and return */
+ "POP {r4-r12, pc} \n"
+ : : [SVC_REQ] "I" (TFM_SVC_DEPRIV_REQ)
+ , [SVC_RET] "I" (TFM_SVC_DEPRIV_RET)
+ : "r0");
+}
#endif
/**
@@ -152,13 +185,15 @@
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- "TST lr, #4 \n" /* Check store SP in thread mode to r0 */
- "IT EQ \n"
- "BXEQ lr \n"
- "MRS r0, PSP \n"
- "MOV r1, lr \n"
- "BL SVCHandler_main \n"
- "BX r0 \n"
+ "MRS r2, MSP \n"
+ /* Check store SP in thread mode to r0 */
+ "TST lr, #4 \n"
+ "ITE EQ \n"
+ "MOVEQ r0, r2 \n"
+ "MRSNE r0, PSP \n"
+ "MOV r1, lr \n"
+ "BL SVCHandler_main \n"
+ "BX r0 \n"
);
}
diff --git a/secure_fw/core/ipc/include/tfm_utils.h b/secure_fw/core/ipc/include/tfm_utils.h
index 18163a0..01462bc 100644
--- a/secure_fw/core/ipc/include/tfm_utils.h
+++ b/secure_fw/core/ipc/include/tfm_utils.h
@@ -26,6 +26,4 @@
#define TFM_GET_CONTAINER_PTR(ptr, type, member) \
(type *)((unsigned long)(ptr) - offsetof(type, member))
-int32_t tfm_bitcount(uint32_t n);
-
#endif
diff --git a/secure_fw/core/ipc/tfm_spm.c b/secure_fw/core/ipc/tfm_spm.c
index c10bcc8..4f45070 100644
--- a/secure_fw/core/ipc/tfm_spm.c
+++ b/secure_fw/core/ipc/tfm_spm.c
@@ -22,6 +22,7 @@
#include "tfm_pools.h"
#include "tfm_spm.h"
#include "tfm_spm_signal_defs.h"
+#include "tfm_irq_signal_defs.h"
#include "tfm_thread.h"
#include "region_defs.h"
#include "tfm_nspm.h"
diff --git a/secure_fw/core/ipc/tfm_svcalls.c b/secure_fw/core/ipc/tfm_svcalls.c
index c02a5b8..07df935 100644
--- a/secure_fw/core/ipc/tfm_svcalls.c
+++ b/secure_fw/core/ipc/tfm_svcalls.c
@@ -22,8 +22,6 @@
#include "tfm_memory_utils.h"
#include "spm_api.h"
-#define PSA_TIMEOUT_MASK PSA_BLOCK
-
/************************* SVC handler for PSA Client APIs *******************/
uint32_t tfm_svcall_psa_framework_version(void)
diff --git a/secure_fw/core/ipc/tfm_utils.c b/secure_fw/core/ipc/tfm_utils.c
index 591e243..dd15494 100644
--- a/secure_fw/core/ipc/tfm_utils.c
+++ b/secure_fw/core/ipc/tfm_utils.c
@@ -12,20 +12,3 @@
while (1)
;
}
-
-int32_t tfm_bitcount(uint32_t n)
-{
- int32_t count = 0;
- uint8_t tmp;
-
- while (n) {
- tmp = n & 0xFF;
- while (tmp) {
- count += tmp & 0x1;
- tmp >>= 1;
- }
- n >>= 8;
- }
-
- return count;
-}
diff --git a/secure_fw/core/secure_utilities.h b/secure_fw/core/secure_utilities.h
index ce03b47..769d390 100644
--- a/secure_fw/core/secure_utilities.h
+++ b/secure_fw/core/secure_utilities.h
@@ -56,4 +56,6 @@
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
#endif
+int32_t tfm_bitcount(uint32_t n);
+
#endif /* __SECURE_UTILITIES_H__ */
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index 5ba4585..30dca20 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -16,6 +16,8 @@
#include "secure_utilities.h"
#include "secure_fw/spm/spm_api.h"
#include "secure_fw/include/tfm_spm_services_api.h"
+#include "tfm_irq_signal_defs.h"
+#include "tfm_irq_list.h"
#ifdef TFM_PSA_API
#include "psa_client.h"
#include "psa_service.h"
@@ -82,6 +84,8 @@
int32_t tfm_core_init(void)
{
+ size_t i;
+
/* Enables fault handlers */
enable_fault_handlers();
@@ -110,6 +114,15 @@
* secure peripherals
*/
nvic_interrupt_target_state_cfg();
+
+ for (i = 0; i < tfm_core_irq_signals_count; ++i) {
+ tfm_spm_hal_set_secure_irq_priority(
+ tfm_core_irq_signals[i].irq_line,
+ tfm_core_irq_signals[i].irq_priority);
+ tfm_spm_hal_set_irq_target_state(tfm_core_irq_signals[i].irq_line,
+ TFM_IRQ_TARGET_STATE_SECURE);
+ }
+
/* Enable secure peripherals interrupts */
nvic_interrupt_enable();
diff --git a/secure_fw/core/tfm_func_api.c b/secure_fw/core/tfm_func_api.c
index ffbd957..dcbce48 100644
--- a/secure_fw/core/tfm_func_api.c
+++ b/secure_fw/core/tfm_func_api.c
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <string.h>
+#include <stdint.h>
#include <stdbool.h>
#include <arm_cmse.h>
#include "tfm_secure_api.h"
@@ -17,8 +18,12 @@
#include "region_defs.h"
#include "tfm_api.h"
#include "tfm_arch.h"
+#include "platform/include/tfm_spm_hal.h"
+#include "tfm_irq_list.h"
+#include "psa_service.h"
#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
+#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
#ifndef TFM_LVL
#error TFM_LVL is not defined!
@@ -100,6 +105,42 @@
return dst;
}
+/**
+ * \brief Create a stack frame that sets the execution environment to thread
+ * mode on exception return.
+ *
+ * \param[in] svc_ctx The stacked SVC context
+ * \param[in] unpriv_handler The unprivileged IRQ handler to be called
+ * \param[in] dst A pointer where the context is to be created. (the
+ * pointer is considered to be a stack pointer, and
+ * the frame is created below it)
+ *
+ * \return A pointer pointing at the created stack frame.
+ */
+static int32_t *prepare_partition_irq_ctx(
+ const struct tfm_exc_stack_t *svc_ctx,
+ sfn_t unpriv_handler,
+ int32_t *dst)
+{
+ int i;
+
+ /* XPSR = as was when called, but make sure it's thread mode */
+ *(--dst) = svc_ctx->XPSR & 0xFFFFFE00;
+ /* ReturnAddress = resume to the privileged handler code, but execute it
+ * unprivileged.
+ */
+ *(--dst) = svc_ctx->RetAddr;
+ /* LR = start address */
+ *(--dst) = (int32_t)unpriv_handler;
+
+ /* R12, R0-R3 unused arguments */
+ for (i = 0; i < 5; ++i) {
+ *(--dst) = 0;
+ }
+
+ return dst;
+}
+
static void restore_caller_ctx(
const struct tfm_exc_stack_t *svc_ctx,
struct tfm_exc_stack_t *target_ctx)
@@ -259,9 +300,10 @@
}
if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
+ curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
- /* Recursion is not permitted! */
+ /* Active partitions cannot be called! */
return TFM_ERROR_PARTITION_NON_REENTRANT;
} else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
/* The partition to be called is not in a proper state */
@@ -271,6 +313,27 @@
}
/**
+ * \brief Check whether the partitions for the secure function call are in a
+ * proper state
+ *
+ * \param[in] called_partition_state State of the partition to be called
+ *
+ * \return \ref TFM_SUCCESS if the check passes, error otherwise.
+ */
+static int32_t check_irq_partition_state(
+ enum spm_part_state_t called_partition_state)
+{
+ if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
+ called_partition_state == SPM_PARTITION_STATE_RUNNING ||
+ called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
+ called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
+ return TFM_SUCCESS;
+ }
+ return TFM_SECURE_LOCK_FAILED;
+}
+
+/**
* \brief Calculate the address where the iovec parameters are to be saved for
* the called partition.
*
@@ -438,6 +501,89 @@
return TFM_SUCCESS;
}
+static int32_t tfm_start_partition_for_irq_handling(
+ uint32_t excReturn,
+ struct tfm_exc_stack_t *svc_ctx)
+{
+ uint32_t handler_partition_id = svc_ctx->R0;
+ sfn_t unpriv_handler = (sfn_t)svc_ctx->R1;
+ uint32_t irq_signal = svc_ctx->R2;
+ uint32_t irq_line = svc_ctx->R3;
+ int32_t res;
+ uint32_t psp = __get_PSP();
+#if (TFM_LVL != 1)
+ uint32_t handler_partition_psplim;
+#endif
+ uint32_t handler_partition_psp;
+ enum spm_part_state_t handler_partition_state;
+ uint32_t interrupted_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *handler_part_data;
+ uint32_t handler_partition_idx;
+
+ handler_partition_idx = get_partition_idx(handler_partition_id);
+ handler_part_data = tfm_spm_partition_get_runtime_data(
+ handler_partition_idx);
+ handler_partition_state = handler_part_data->partition_state;
+
+ res = check_irq_partition_state(handler_partition_state);
+ if (res != TFM_SUCCESS) {
+ return res;
+ }
+
+ /* set mask for the partition */
+ tfm_spm_partition_set_signal_mask(
+ handler_partition_idx,
+ handler_part_data->signal_mask | irq_signal);
+
+ tfm_spm_hal_disable_irq(irq_line);
+
+ /* save the current context of the interrupted partition */
+ tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
+
+#if (TFM_LVL != 1)
+ /* Save the psp as it was when the interrupt happened */
+ tfm_spm_partition_set_stack(interrupted_partition_idx, psp);
+
+ handler_partition_psp = handler_part_data->stack_ptr;
+ handler_partition_psplim =
+ tfm_spm_partition_get_stack_bottom(handler_partition_idx);
+#else /* TFM_LVL != 1 */
+ handler_partition_psp = psp;
+#endif /* TFM_LVL != 1 */
+
+ /* save the current context of the handler partition */
+ tfm_spm_partition_push_handler_ctx(handler_partition_idx);
+
+ /* Store caller for the partition */
+ tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
+ interrupted_partition_idx);
+
+#if TFM_LVL == 3
+ /* Dynamic partitioning is only done is TFM level 3 */
+ tfm_spm_partition_sandbox_deconfig(interrupted_partition_idx);
+
+ /* Configure partition execution environment */
+ if (tfm_spm_partition_sandbox_config(handler_partition_idx) != SPM_ERR_OK) {
+ ERROR_MSG("Failed to configure sandbox for partition!");
+ tfm_secure_api_error_handler();
+ }
+#endif /* TFM_LVL == 3 */
+
+ psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
+ (int32_t *)handler_partition_psp);
+ __set_PSP(psp);
+#if (TFM_LVL != 1)
+ __set_PSPLIM(handler_partition_psplim);
+#endif /* TFM_LVL != 1 */
+ tfm_spm_partition_set_state(interrupted_partition_idx,
+ SPM_PARTITION_STATE_SUSPENDED);
+ tfm_spm_partition_set_state(handler_partition_idx,
+ SPM_PARTITION_STATE_HANDLING_IRQ);
+
+ return TFM_SUCCESS;
+}
+
static int32_t tfm_return_from_partition(uint32_t *excReturn)
{
uint32_t current_partition_idx =
@@ -565,6 +711,79 @@
return TFM_SUCCESS;
}
+static int32_t tfm_return_from_partition_irq_handling(uint32_t *excReturn)
+{
+ uint32_t handler_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *handler_part_data;
+#if TFM_LVL != 1
+ const struct spm_partition_runtime_data_t *interrupted_part_data;
+ uint32_t interrupted_partition_psplim;
+#endif /* TFM_LVL != 1 */
+ uint32_t interrupted_partition_idx;
+ uint32_t psp = __get_PSP();
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
+
+ if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+ handler_part_data = tfm_spm_partition_get_runtime_data(
+ handler_partition_idx);
+ interrupted_partition_idx = handler_part_data->caller_partition_idx;
+
+ if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+#if TFM_LVL != 1
+ interrupted_part_data = tfm_spm_partition_get_runtime_data(
+ interrupted_partition_idx);
+
+#if TFM_LVL == 3
+ /* Deconfigure completed partition environment */
+ tfm_spm_partition_sandbox_deconfig(handler_partition_idx);
+
+ /* Configure the caller partition environment */
+ if (tfm_spm_partition_sandbox_config(interrupted_partition_idx)
+ != SPM_ERR_OK) {
+ ERROR_MSG("Failed to configure sandbox for partition!");
+ tfm_secure_api_error_handler();
+ }
+#endif /* TFM_LVL == 3 */
+
+ /* Restore caller context */
+ *excReturn = svc_ctx->RetAddr;
+
+ if (psp+sizeof(struct tfm_exc_stack_t) != handler_part_data->stack_ptr) {
+ ERROR_MSG("The interrupt handler unfolded its stack improperly!");
+ tfm_secure_api_error_handler();
+ }
+
+ psp = interrupted_part_data->stack_ptr;
+#else /* TFM_LVL != 1 */
+ /* For level 1, modify PSP, so that the SVC stack frame disappears,
+ * and return to the privileged handler using the stack frame still on the
+ * MSP stack.
+ */
+ *excReturn = svc_ctx->RetAddr;
+ psp += sizeof(struct tfm_exc_stack_t);
+#endif /* TFM_LVL != 1 */
+
+ tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
+ tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
+
+#if TFM_LVL != 1
+ interrupted_partition_psplim =
+ tfm_spm_partition_get_stack_bottom(interrupted_partition_idx);
+
+ __set_PSPLIM(interrupted_partition_psplim);
+#endif /* TFM_LVL != 1 */
+ __set_PSP(psp);
+
+ return TFM_SUCCESS;
+}
+
static int32_t tfm_check_sfn_req_integrity(const struct tfm_sfn_req_s *desc_ptr)
{
if ((desc_ptr == NULL) ||
@@ -720,8 +939,12 @@
uint32_t caller_partition_flags =
tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
- if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
+ if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
/* This handler shouldn't be called from outside partition context.
+ * Also if the current partition is handling IRQ, the caller partition
+ * index might not be valid;
* Partitions are only allowed to run while S domain is locked.
*/
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
@@ -802,8 +1025,12 @@
tfm_spm_partition_get_runtime_data(running_partition_idx);
int res = 0;
- if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
+ if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
/* This handler shouldn't be called from outside partition context.
+ * Also if the current partition is handling IRQ, the caller partition
+ * index might not be valid;
* Partitions are only allowed to run while S domain is locked.
*/
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
@@ -954,6 +1181,29 @@
return EXC_RETURN_SECURE_FUNCTION;
}
+/* This SVC handler is called, if a thread mode execution environment is to
+ * be set up, to run an unprivileged IRQ handler
+ */
+uint32_t tfm_core_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
+{
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)svc_args;
+
+ int32_t res;
+
+ if (excReturn & EXC_RETURN_STACK_PROCESS) {
+ /* FixMe: error severity TBD */
+ ERROR_MSG("Partition request SVC called with PSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
+ if (res != TFM_SUCCESS) {
+ /* FixMe: consider possible fault scenarios */
+ return excReturn;
+ }
+ return EXC_RETURN_SECURE_FUNCTION;
+}
+
/* This SVC handler is called when sfn returns */
uint32_t tfm_core_partition_return_handler(uint32_t lr)
{
@@ -997,6 +1247,38 @@
return lr;
}
+/* This SVC handler is called if a deprivileged IRQ handler was executed, and
+ * the execution environment is to be set back for the privileged handler mode
+ */
+uint32_t tfm_core_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
+{
+ struct tfm_exc_stack_t *irq_svc_ctx =
+ (struct tfm_exc_stack_t *)irq_svc_args;
+
+ if (!(lr & EXC_RETURN_STACK_PROCESS)) {
+ /* Partition request SVC called with MSP active.
+ * FixMe: error severity TBD
+ */
+ ERROR_MSG("Partition request SVC called with MSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ int32_t res;
+
+ res = tfm_return_from_partition_irq_handling(&lr);
+ if (res != TFM_SUCCESS) {
+ /* Unlock errors indicate ctx database corruption or unknown anomalies
+ * Halt execution
+ */
+ ERROR_MSG("Secure API error during unlock!");
+ tfm_secure_api_error_handler();
+ }
+
+ irq_svc_ctx->RetAddr = lr;
+
+ return EXC_RETURN_SECURE_HANDLER;
+}
+
void tfm_core_set_buffer_area_handler(uint32_t *args)
{
/* r0 is stored in args[0] in exception stack frame
@@ -1016,8 +1298,13 @@
/* tfm_core_set_buffer_area() returns int32_t */
int32_t *res_ptr = (int32_t *)&args[0];
- if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
- /* This handler should only be called from a secure partition. */
+ if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
+ /* This handler shouldn't be called from outside partition context.
+ * Also if the current partition is handling IRQ, the caller partition
+ * index might not be valid;
+ */
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
return;
}
@@ -1046,3 +1333,149 @@
return;
}
+/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
+/**
+ * \brief Return the IRQ line number associated with a signal
+ *
+ * \param[in] partition_id The ID of the partition in which we look for the
+ * signal
+ * \param[in] signal The signal we do the query for
+ *
+ * \retval >=0 The IRQ line number associated with a signal in the partition
+ * \retval <0 error
+ */
+static int32_t get_irq_line_for_signal(int32_t partition_id,
+ psa_signal_t signal)
+{
+ size_t i;
+
+ for (i = 0; i < tfm_core_irq_signals_count; ++i) {
+ if (tfm_core_irq_signals[i].partition_id == partition_id &&
+ tfm_core_irq_signals[i].signal_value == signal) {
+ return tfm_core_irq_signals[i].irq_line;
+ }
+ }
+ return -1;
+}
+
+/* FIXME: tfm_core_psa_eoi, tfm_core_enable_irq_handler and
+ * tfm_core_disable_irq_handler function has an implementation in
+ * tfm_svcalls.c for the IPC model.
+ * The two implementations should be merged as part of restructuring common code
+ * among library and IPC model.
+ */
+void tfm_core_enable_irq_handler(uint32_t *svc_args)
+{
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->R0;
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ uint32_t running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ int32_t irq_line;
+
+ /* Only a single signal is allowed */
+ if (tfm_bitcount(irq_signal) != 1) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_enable_irq(irq_line);
+}
+
+void tfm_core_disable_irq_handler(uint32_t *svc_args)
+{
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->R0;
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ uint32_t running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ int32_t irq_line;
+
+ /* Only a single signal is allowed */
+ if (tfm_bitcount(irq_signal) != 1) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_disable_irq(irq_line);
+}
+
+void tfm_core_psa_wait(uint32_t *svc_args)
+{
+ /* Look for partition that is ready for run */
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)svc_args;
+ uint32_t running_partition_idx;
+ const struct spm_partition_runtime_data_t *curr_part_data;
+
+ psa_signal_t signal_mask = svc_ctx->R0;
+ uint32_t timeout = svc_ctx->R1;
+
+ /*
+ * Timeout[30:0] are reserved for future use.
+ * SPM must ignore the value of RES.
+ */
+ timeout &= PSA_TIMEOUT_MASK;
+
+ running_partition_idx = tfm_spm_partition_get_running_partition_idx();
+ curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
+
+ if (timeout == PSA_BLOCK) {
+ /* FIXME: Scheduling is not available in library model, and busy wait is
+ * also not possible as this code is running in SVC context, and it
+ * cannot be pre-empted by interrupts. So do nothing here for now
+ */
+ (void) signal_mask;
+ }
+
+ svc_ctx->R0 = curr_part_data->signal_mask;
+}
+
+void tfm_core_psa_eoi(uint32_t *svc_args)
+{
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->R0;
+ uint32_t signal_mask;
+ uint32_t running_partition_idx;
+ uint32_t running_partition_id;
+ const struct spm_partition_runtime_data_t *curr_part_data;
+ int32_t irq_line;
+
+ running_partition_idx = tfm_spm_partition_get_running_partition_idx();
+ running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
+
+ /* Only a single signal is allowed */
+ if (tfm_bitcount(irq_signal) != 1) {
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_clear_pending_irq(irq_line);
+ tfm_spm_hal_enable_irq(irq_line);
+
+ signal_mask = curr_part_data->signal_mask & ~irq_signal;
+ tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
+}
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index 89b0008..5be8ba7 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -12,10 +12,14 @@
#include "tfm_svc.h"
#include "tfm_secure_api.h"
#include "region_defs.h"
+#include "spm_partition_defs.h"
#include "tfm_api.h"
#include "tfm_internal.h"
#include "tfm_memory_utils.h"
#include "tfm_arch.h"
+#include "tfm_irq_signal_defs.h"
+#include "tfm_peripherals_def.h"
+#include "tfm_irq_list.h"
#ifdef TFM_PSA_API
#include <stdbool.h>
#include "tfm_svcalls.h"
@@ -29,7 +33,13 @@
extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
#endif
-uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr)
+
+/* Include the definitions of the privileged IRQ handlers, and the declarations
+ * of the unprivileged handlers.
+ */
+#include "tfm_secure_irq_handlers.inc"
+
+uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr, uint32_t *msp)
{
uint8_t svc_number;
/*
@@ -95,6 +105,24 @@
case TFM_SVC_SET_SHARE_AREA:
tfm_core_set_buffer_area_handler(svc_args);
break;
+ case TFM_SVC_DEPRIV_REQ:
+ lr = tfm_core_depriv_req_handler(svc_args, lr);
+ break;
+ case TFM_SVC_DEPRIV_RET:
+ lr = tfm_core_depriv_return_handler(msp, lr);
+ break;
+ case TFM_SVC_PSA_WAIT:
+ tfm_core_psa_wait(svc_args);
+ break;
+ case TFM_SVC_PSA_EOI:
+ tfm_core_psa_eoi(svc_args);
+ break;
+ case TFM_SVC_ENABLE_IRQ:
+ tfm_core_enable_irq_handler(svc_args);
+ break;
+ case TFM_SVC_DISABLE_IRQ:
+ tfm_core_disable_irq_handler(svc_args);
+ break;
#endif
case TFM_SVC_PRINT:
printf("\033[1;34m[Sec Thread] %s\033[0m\r\n", (char *)svc_args[0]);
diff --git a/secure_fw/core/tfm_internal.h b/secure_fw/core/tfm_internal.h
index dad36ad..d73b078 100644
--- a/secure_fw/core/tfm_internal.h
+++ b/secure_fw/core/tfm_internal.h
@@ -97,4 +97,36 @@
*/
void tfm_core_validate_boot_data(void);
+/**
+ * \brief Handle deprivileged request
+ */
+extern uint32_t tfm_core_depriv_req_handler(uint32_t *svc_args,
+ uint32_t excReturn);
+
+/**
+ * \brief Handle request to return to privileged
+ */
+uint32_t tfm_core_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr);
+
+/**
+ * \brief Handle IRQ enable request
+ */
+void tfm_core_enable_irq_handler(uint32_t *svc_args);
+
+/**
+ * \brief Handle IRQ disable request
+ */
+void tfm_core_disable_irq_handler(uint32_t *svc_args);
+
+/**
+ * \brief Handle signal wait request
+ */
+void tfm_core_psa_wait(uint32_t *svc_args);
+
+/**
+ * \brief Handle request to record IRQ processed
+ */
+void tfm_core_psa_eoi(uint32_t *svc_args);
+
+
#endif /* __TFM_INTERNAL_H__ */
diff --git a/secure_fw/core/tfm_irq_list.h b/secure_fw/core/tfm_irq_list.h
new file mode 100644
index 0000000..3dcfd2f
--- /dev/null
+++ b/secure_fw/core/tfm_irq_list.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_IRQ_LIST_H__
+#define __TFM_IRQ_LIST_H__
+
+#include "psa_service.h"
+
+#define TFM_DEFAULT_SECURE_IRQ_PRIOTITY 128
+
+struct tfm_core_irq_signal_data_t {
+ int32_t partition_id;
+ psa_signal_t signal_value;
+ int32_t irq_line;
+ uint32_t irq_priority;
+};
+
+extern const struct tfm_core_irq_signal_data_t tfm_core_irq_signals[];
+extern const size_t tfm_core_irq_signals_count;
+
+#endif /* __TFM_IRQ_LIST_H__ */
diff --git a/secure_fw/core/tfm_irq_signal_defs.h b/secure_fw/core/tfm_irq_signal_defs.h
new file mode 100644
index 0000000..e851776
--- /dev/null
+++ b/secure_fw/core/tfm_irq_signal_defs.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_IRQ_SIGNAL_DEFS_H__
+#define __TFM_IRQ_SIGNAL_DEFS_H__
+
+
+#endif /* __TFM_IRQ_SIGNAL_DEFS_H__ */
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 104958e..a27aa8a 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -37,6 +37,23 @@
*/
int32_t tfm_secure_lock;
+int32_t tfm_bitcount(uint32_t n)
+{
+ int32_t count = 0;
+ uint8_t tmp;
+
+ while (n) {
+ tmp = n & 0xFF;
+ while (tmp) {
+ count += tmp & 0x1;
+ tmp >>= 1;
+ }
+ n >>= 8;
+ }
+
+ return count;
+}
+
/**
* \brief Check whether a memory range is inside a memory region.
*
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 5a35fc4..d3b20c4 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -14,6 +14,7 @@
#include "tfm_core.h"
#include "tfm_api.h"
#include "bl2/include/tfm_boot_status.h"
+#include "psa_service.h"
/*!
* \def __tfm_secure_gateway_attributes__
@@ -130,6 +131,9 @@
uint32_t ns_caller,
uint32_t privileged);
+void tfm_enable_irq(psa_signal_t irq_signal);
+void tfm_disable_irq(psa_signal_t irq_signal);
+
#ifdef TFM_PSA_API
/* The following macros are only valid if secure services can be called
* using veneer functions. This is not the case if IPC messaging is enabled
diff --git a/secure_fw/core/tfm_secure_irq_handlers.inc b/secure_fw/core/tfm_secure_irq_handlers.inc
new file mode 100644
index 0000000..5ff583a
--- /dev/null
+++ b/secure_fw/core/tfm_secure_irq_handlers.inc
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+
+#include "secure_fw/services/tfm_partition_defs.inc"
+
+/* Definitions of the signals of the IRQs */
+const struct tfm_core_irq_signal_data_t tfm_core_irq_signals[] = {
+};
+
+const size_t tfm_core_irq_signals_count = sizeof(tfm_core_irq_signals) /
+ sizeof(*tfm_core_irq_signals);
+
+extern void priv_irq_handler_main(uint32_t partition_id,
+ uint32_t unpriv_handler,
+ uint32_t irq_signal,
+ uint32_t irq_line);
+
+/* Forward declarations of unpriv IRQ handlers*/
+
+/* Definitions of privileged IRQ handlers */
diff --git a/secure_fw/core/tfm_secure_irq_handlers.inc.template b/secure_fw/core/tfm_secure_irq_handlers.inc.template
new file mode 100644
index 0000000..b28407b
--- /dev/null
+++ b/secure_fw/core/tfm_secure_irq_handlers.inc.template
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+{{utilities.donotedit_warning}}
+{% macro _irq_record(partition_name, signal, line, priority) -%}
+{ {{ partition_name }}_ID, {{ signal }}, {{ line }}, {{ priority }} },
+{%- endmacro %}
+
+#include "secure_fw/services/tfm_partition_defs.inc"
+
+/* Definitions of the signals of the IRQs */
+const struct tfm_core_irq_signal_data_t tfm_core_irq_signals[] = {
+{% for manifest in manifests %}
+ {% if manifest.manifest.irqs %}
+ {% if manifest.attr.conditional %}
+#ifdef {{manifest.attr.conditional}}
+ {% endif %}
+ {% for handler in manifest.manifest.irqs %}
+ {% set irq_data = namespace() %}
+ {% if handler.line_num %}
+ {% set irq_data.line = handler.line_num %}
+ {% elif handler.line_name %}
+ {% set irq_data.line = handler.line_name %}
+ {% else %}
+#error "Neither line_num nor line_name is provided for 'irqs' in partition {{manifest.manifest.name}}"
+ {% endif %}
+ {% if handler.tfm_irq_priority %}
+ {% set irq_data.priority = handler.tfm_irq_priority %}
+ {% else %}
+ {% set irq_data.priority = "TFM_DEFAULT_SECURE_IRQ_PRIOTITY" %}
+ {% endif %}
+ {{ _irq_record(manifest.manifest.name, handler.signal, irq_data.line, irq_data.priority) }}
+ {% endfor %}
+ {% if manifest.attr.conditional %}
+#endif /* {{manifest.attr.conditional}} */
+ {% endif %}
+ {% endif %}
+{% endfor %}
+};
+
+const size_t tfm_core_irq_signals_count = sizeof(tfm_core_irq_signals) /
+ sizeof(*tfm_core_irq_signals);
+
+extern void priv_irq_handler_main(uint32_t partition_id,
+ uint32_t unpriv_handler,
+ uint32_t irq_signal,
+ uint32_t irq_line);
+
+/* Forward declarations of unpriv IRQ handlers*/
+{% for manifest in manifests %}
+ {% if manifest.manifest.irqs %}
+ {% if manifest.attr.conditional %}
+#ifdef {{manifest.attr.conditional}}
+ {% endif %}
+ {% for handler in manifest.manifest.irqs %}
+extern void {{handler.signal}}_isr(void);
+ {% endfor %}
+ {% if manifest.attr.conditional %}
+#endif /* {{manifest.attr.conditional}} */
+ {% endif %}
+
+ {% endif %}
+{% endfor %}
+
+/* Definitions of privileged IRQ handlers */
+{% for manifest in manifests %}
+ {% if manifest.manifest.irqs %}
+ {% if manifest.attr.conditional %}
+#ifdef {{manifest.attr.conditional}}
+ {% endif %}
+ {% for handler in manifest.manifest.irqs %}
+ {% if handler.line_num %}
+void irq_{{handler.line_num}}_Handler(void)
+ {% elif handler.line_name %}
+void {{handler.line_name}}_Handler(void)
+ {% else %}
+#error "Neither line_num nor line_name is provided for 'irqs' in partition {{manifest.manifest.name}}"
+ {% endif %}
+{
+ {% if handler.line_num %}
+ priv_irq_handler_main({{manifest.manifest.name}}_ID,
+ (uint32_t){{handler.signal}}_isr,
+ {{handler.signal}},
+ {{handler.line_num}});
+ {% elif handler.line_name %}
+ priv_irq_handler_main({{manifest.manifest.name}}_ID,
+ (uint32_t){{handler.signal}}_isr,
+ {{handler.signal}},
+ {{handler.line_name}});
+ {% else %}
+#error "Neither line_num nor line_name is provided for 'irqs' in partition {{manifest.manifest.name}}"
+ {% endif %}
+}
+
+ {% endfor %}
+ {% if manifest.attr.conditional %}
+#endif /* {{manifest.attr.conditional}} */
+ {% endif %}
+
+ {% endif %}
+{% endfor %}
diff --git a/secure_fw/core/tfm_spm_services.c b/secure_fw/core/tfm_spm_services.c
index fabffbd..f580833 100644
--- a/secure_fw/core/tfm_spm_services.c
+++ b/secure_fw/core/tfm_spm_services.c
@@ -12,6 +12,7 @@
#include "tfm_internal.h"
#include "secure_fw/include/tfm_spm_services_api.h"
#include "spm_api.h"
+#include "psa_service.h"
uint8_t *tfm_scratch_area;
uint32_t tfm_scratch_area_size;
@@ -99,3 +100,58 @@
"BX lr\n"
: : "I" (TFM_SVC_GET_BOOT_DATA));
}
+
+__attribute__((naked))
+void tfm_enable_irq(psa_signal_t irq_signal)
+{
+ __ASM("SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_ENABLE_IRQ));
+}
+
+__attribute__((naked))
+void tfm_disable_irq(psa_signal_t irq_signal)
+{
+ __ASM("SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_DISABLE_IRQ));
+}
+
+#ifndef TFM_PSA_API
+
+__attribute__((naked))
+static psa_signal_t psa_wait_internal(psa_signal_t signal_mask,
+ uint32_t timeout)
+{
+ __ASM("SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_PSA_WAIT));
+}
+
+psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
+{
+ /* FIXME: By using the 'WFI' instruction this function blocks until an
+ * interrupt happens. It is necessary to do this here as tfm_core_psa_wait
+ * runs with the priority of the SVC, so it cannot be interrupted, so
+ * waiting in it for the required interrupt to happen is not an option.
+ */
+ psa_signal_t actual_signal_mask;
+
+ while (1) {
+ actual_signal_mask = psa_wait_internal(signal_mask, timeout);
+ if ((actual_signal_mask & signal_mask) != 0) {
+ return actual_signal_mask;
+ }
+ __WFI();
+ }
+}
+
+__attribute__((naked))
+void psa_eoi(psa_signal_t irq_signal)
+{
+ __ASM("SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_PSA_EOI));
+}
+
+#endif
diff --git a/secure_fw/core/tfm_svc.h b/secure_fw/core/tfm_svc.h
index e0c1102..d52e3d3 100644
--- a/secure_fw/core/tfm_svc.h
+++ b/secure_fw/core/tfm_svc.h
@@ -20,6 +20,12 @@
TFM_SVC_SPM_REQUEST,
TFM_SVC_PRINT,
TFM_SVC_GET_BOOT_DATA,
+ TFM_SVC_DEPRIV_REQ,
+ TFM_SVC_DEPRIV_RET,
+ TFM_SVC_ENABLE_IRQ,
+ TFM_SVC_DISABLE_IRQ,
+ TFM_SVC_PSA_WAIT,
+ TFM_SVC_PSA_EOI,
#ifdef TFM_PSA_API
TFM_SVC_IPC_REQUEST,
TFM_SVC_SCHEDULE,
@@ -31,7 +37,6 @@
TFM_SVC_PSA_CALL,
TFM_SVC_PSA_CLOSE,
/* PSA Service SVC */
- TFM_SVC_PSA_WAIT,
TFM_SVC_PSA_GET,
TFM_SVC_PSA_SET_RHANDLE,
TFM_SVC_PSA_READ,
@@ -40,7 +45,6 @@
TFM_SVC_PSA_REPLY,
TFM_SVC_PSA_NOTIFY,
TFM_SVC_PSA_CLEAR,
- TFM_SVC_PSA_EOI,
#endif
} tfm_svc_number_t;
diff --git a/secure_fw/services/tfm_partition_list.inc b/secure_fw/services/tfm_partition_list.inc
index 2cc4818..90344e2 100644
--- a/secure_fw/services/tfm_partition_list.inc
+++ b/secure_fw/services/tfm_partition_list.inc
@@ -7,19 +7,23 @@
/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
+#include "tfm_partition_defs.inc"
+
#ifndef __TFM_PARTITION_LIST_INC__
#define __TFM_PARTITION_LIST_INC__
/******** TFM_SP_STORAGE ********/
+#define TFM_PARTITION_TFM_SP_STORAGE_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_STORAGE, 0
| SPM_PART_FLAG_IPC
- , "PSA-ROT", 0x00000100, NORMAL);
+ , "PSA-ROT", TFM_SP_STORAGE_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_STORAGE, tfm_sst_req_mngr_init);
#ifdef TFM_PARTITION_AUDIT_LOG
/******** TFM_SP_AUDIT_LOG ********/
+#define TFM_PARTITION_TFM_SP_AUDIT_LOG_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_AUDIT_LOG, 0
- , "PSA-ROT", 0x00000101, NORMAL);
+ , "PSA-ROT", TFM_SP_AUDIT_LOG_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_AUDIT_LOG, audit_core_init);
#ifdef AUDIT_UART_REDIRECTION
PARTITION_ADD_PERIPHERAL(TFM_SP_AUDIT_LOG, TFM_PERIPHERAL_UART1);
@@ -27,63 +31,71 @@
#endif /* TFM_PARTITION_AUDIT_LOG */
/******** TFM_SP_CRYPTO ********/
+#define TFM_PARTITION_TFM_SP_CRYPTO_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_CRYPTO, 0
| SPM_PART_FLAG_IPC
- , "PSA-ROT", 0x00000102, NORMAL);
+ , "PSA-ROT", TFM_SP_CRYPTO_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_CRYPTO, tfm_crypto_init);
#ifdef TFM_PARTITION_PLATFORM
/******** TFM_SP_PLATFORM ********/
+#define TFM_PARTITION_TFM_SP_PLATFORM_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_PLATFORM, 0
- , "PSA-ROT", 0x00000102, NORMAL);
+ , "PSA-ROT", TFM_SP_PLATFORM_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_PLATFORM, platform_sp_init);
#endif /* TFM_PARTITION_PLATFORM */
/******** TFM_SP_INITIAL_ATTESTATION ********/
+#define TFM_PARTITION_TFM_SP_INITIAL_ATTESTATION_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_INITIAL_ATTESTATION, 0
| SPM_PART_FLAG_IPC
- , "PSA-ROT", 0x00000103, NORMAL);
+ , "PSA-ROT", TFM_SP_INITIAL_ATTESTATION_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_INITIAL_ATTESTATION, attest_partition_init);
#ifdef TFM_PARTITION_TEST_CORE
/******** TFM_SP_CORE_TEST ********/
+#define TFM_PARTITION_TFM_SP_CORE_TEST_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_CORE_TEST, 0
| SPM_PART_FLAG_IPC
- , "APPLICATION-ROT", 0x00000002, NORMAL);
+ , "APPLICATION-ROT", TFM_SP_CORE_TEST_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_CORE_TEST, core_test_init);
PARTITION_ADD_PERIPHERAL(TFM_SP_CORE_TEST, TFM_PERIPHERAL_FPGA_IO);
#endif /* TFM_PARTITION_TEST_CORE */
#ifdef TFM_PARTITION_TEST_CORE
/******** TFM_SP_CORE_TEST_2 ********/
+#define TFM_PARTITION_TFM_SP_CORE_TEST_2_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_CORE_TEST_2, 0
| SPM_PART_FLAG_IPC
- , "APPLICATION-ROT", 0x00000003, NORMAL);
+ , "APPLICATION-ROT", TFM_SP_CORE_TEST_2_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_CORE_TEST_2, core_test_2_init);
#endif /* TFM_PARTITION_TEST_CORE */
#ifdef TFM_PARTITION_TEST_SECURE_SERVICES
/******** TFM_SP_SECURE_TEST_PARTITION ********/
+#define TFM_PARTITION_TFM_SP_SECURE_TEST_PARTITION_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_SECURE_TEST_PARTITION, 0
| SPM_PART_FLAG_IPC
- , "PSA-ROT", 0x00000005, NORMAL);
+ , "PSA-ROT", TFM_SP_SECURE_TEST_PARTITION_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_SECURE_TEST_PARTITION, tfm_secure_client_service_init);
PARTITION_ADD_PERIPHERAL(TFM_SP_SECURE_TEST_PARTITION, TFM_PERIPHERAL_STD_UART);
#endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
#ifdef TFM_PARTITION_TEST_CORE_IPC
/******** TFM_SP_IPC_SERVICE_TEST ********/
+#define TFM_PARTITION_TFM_SP_IPC_SERVICE_TEST_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_IPC_SERVICE_TEST, 0
| SPM_PART_FLAG_IPC
- , "PSA-ROT", 0x00000007, HIGH);
+ , "PSA-ROT", TFM_SP_IPC_SERVICE_TEST_ID, HIGH);
PARTITION_ADD_INIT_FUNC(TFM_SP_IPC_SERVICE_TEST, ipc_service_test_main);
#endif /* TFM_PARTITION_TEST_CORE_IPC */
#ifdef TFM_PARTITION_TEST_CORE_IPC
/******** TFM_SP_IPC_CLIENT_TEST ********/
+#define TFM_PARTITION_TFM_SP_IPC_CLIENT_TEST_IRQ_COUNT 0
PARTITION_DECLARE(TFM_SP_IPC_CLIENT_TEST, 0
| SPM_PART_FLAG_IPC
- , "APPLICATION-ROT", 0x00000006, NORMAL);
+ , "APPLICATION-ROT", TFM_SP_IPC_CLIENT_TEST_ID, NORMAL);
PARTITION_ADD_INIT_FUNC(TFM_SP_IPC_CLIENT_TEST, ipc_client_test_main);
#endif /* TFM_PARTITION_TEST_CORE_IPC */
diff --git a/secure_fw/services/tfm_partition_list.inc.template b/secure_fw/services/tfm_partition_list.inc.template
index e314c23..02be6d7 100644
--- a/secure_fw/services/tfm_partition_list.inc.template
+++ b/secure_fw/services/tfm_partition_list.inc.template
@@ -7,6 +7,8 @@
{{utilities.donotedit_warning}}
+#include "tfm_partition_defs.inc"
+
#ifndef __TFM_PARTITION_LIST_INC__
#define __TFM_PARTITION_LIST_INC__
@@ -15,11 +17,16 @@
#ifdef {{manifest.attr.conditional}}
{% endif %}
/******** {{manifest.manifest.name}} ********/
+ {% if manifest.manifest.irqs %}
+#define TFM_PARTITION_{{manifest.manifest.name}}_IRQ_COUNT {{manifest.manifest.irqs | length() }}
+ {% else %}
+#define TFM_PARTITION_{{manifest.manifest.name}}_IRQ_COUNT 0
+ {% endif %}
PARTITION_DECLARE({{manifest.manifest.name}}, 0
{% if manifest.attr.tfm_partition_ipc %}
| SPM_PART_FLAG_IPC
{% endif %}
- , "{{manifest.manifest.type}}", {{manifest.manifest.id}}, {{manifest.manifest.priority}});
+ , "{{manifest.manifest.type}}", {{manifest.manifest.name}}_ID, {{manifest.manifest.priority}});
PARTITION_ADD_INIT_FUNC({{manifest.manifest.name}}, {{manifest.manifest.entry_point}});
{% if manifest.manifest.mmio_regions %}
{% for region in manifest.manifest.mmio_regions %}
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index 78999a8..e138190 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -27,6 +27,24 @@
TFM_INIT_FAILURE,
} sp_error_type_t;
+/* The size of this struct must be multiple of 4 bytes as it is stacked to an
+ * uint32_t[] array
+ */
+struct interrupted_ctx_stack_frame_t {
+#if TFM_LVL != 1
+ uint32_t stack_ptr;
+#endif
+ uint32_t partition_state;
+};
+
+/* The size of this struct must be multiple of 4 bytes as it is stacked to an
+ * uint32_t[] array
+ */
+struct handler_ctx_stack_frame_t {
+ uint32_t partition_state;
+ uint32_t caller_partition_idx;
+};
+
/*
* This function is called when a secure partition causes an error.
* In case of an error in the error handling, a non-zero value have to be
@@ -88,6 +106,10 @@
{
struct spm_partition_desc_t *part_ptr;
enum spm_err_t err;
+ static uint32_t ns_interrupt_ctx_stack[
+ sizeof(struct interrupted_ctx_stack_frame_t)/sizeof(uint32_t)] = {0};
+ static uint32_t tfm_core_interrupt_ctx_stack[
+ sizeof(struct interrupted_ctx_stack_frame_t)/sizeof(uint32_t)] = {0};
(void)tfm_memset (&g_spm_partition_db, 0, sizeof(g_spm_partition_db));
@@ -131,6 +153,7 @@
#endif
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
+ part_ptr->runtime_data.ctx_stack_ptr = ns_interrupt_ctx_stack;
tfm_nspm_configure_clients();
++g_spm_partition_db.partition_count;
@@ -144,6 +167,7 @@
part_ptr->static_data.partition_flags =
SPM_PART_FLAG_APP_ROT | SPM_PART_FLAG_PSA_ROT;
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
+ part_ptr->runtime_data.ctx_stack_ptr = tfm_core_interrupt_ctx_stack;
++g_spm_partition_db.partition_count;
err = add_user_defined_partitions();
@@ -199,6 +223,77 @@
return SPM_ERR_PARTITION_NOT_AVAILABLE;
}
}
+
+void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
+{
+ struct spm_partition_runtime_data_t *runtime_data =
+ &g_spm_partition_db.partitions[partition_idx].runtime_data;
+ struct interrupted_ctx_stack_frame_t *stack_frame =
+ (struct interrupted_ctx_stack_frame_t *)
+ runtime_data->ctx_stack_ptr;
+
+ stack_frame->partition_state = runtime_data->partition_state;
+#if TFM_LVL != 1
+ stack_frame->stack_ptr = runtime_data->stack_ptr;
+#endif
+ runtime_data->ctx_stack_ptr +=
+ sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
+
+}
+
+void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
+{
+ struct spm_partition_runtime_data_t *runtime_data =
+ &g_spm_partition_db.partitions[partition_idx].runtime_data;
+ struct interrupted_ctx_stack_frame_t *stack_frame;
+
+ runtime_data->ctx_stack_ptr -=
+ sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
+ stack_frame = (struct interrupted_ctx_stack_frame_t *)
+ runtime_data->ctx_stack_ptr;
+ tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
+ stack_frame->partition_state = 0;
+#if TFM_LVL != 1
+ tfm_spm_partition_set_stack(partition_idx, stack_frame->stack_ptr);
+ stack_frame->stack_ptr = 0;
+#endif
+}
+
+void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
+{
+ struct spm_partition_runtime_data_t *runtime_data =
+ &g_spm_partition_db.partitions[partition_idx].runtime_data;
+ struct handler_ctx_stack_frame_t *stack_frame =
+ (struct handler_ctx_stack_frame_t *)
+ runtime_data->ctx_stack_ptr;
+
+ stack_frame->partition_state = runtime_data->partition_state;
+ stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
+
+ runtime_data->ctx_stack_ptr +=
+ sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
+}
+
+void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
+{
+ struct spm_partition_runtime_data_t *runtime_data =
+ &g_spm_partition_db.partitions[partition_idx].runtime_data;
+ struct handler_ctx_stack_frame_t *stack_frame;
+
+ runtime_data->ctx_stack_ptr -=
+ sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
+
+ stack_frame = (struct handler_ctx_stack_frame_t *)
+ runtime_data->ctx_stack_ptr;
+
+ tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
+ stack_frame->partition_state = 0;
+ tfm_spm_partition_set_caller_partition_idx(
+ partition_idx, stack_frame->caller_partition_idx);
+ stack_frame->caller_partition_idx = 0;
+
+}
+
#endif /* !defined(TFM_PSA_API) */
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
@@ -306,7 +401,8 @@
{
g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
state;
- if (state == SPM_PARTITION_STATE_RUNNING) {
+ if (state == SPM_PARTITION_STATE_RUNNING ||
+ state == SPM_PARTITION_STATE_HANDLING_IRQ) {
g_spm_partition_db.running_partition_idx = partition_idx;
}
}
@@ -318,6 +414,13 @@
caller_partition_idx = caller_partition_idx;
}
+void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
+ uint32_t signal_mask)
+{
+ g_spm_partition_db.partitions[partition_idx].runtime_data.
+ signal_mask = signal_mask;
+}
+
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id)
{
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index a15434d..d707346 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -32,6 +32,7 @@
SPM_PARTITION_STATE_UNINIT = 0,
SPM_PARTITION_STATE_IDLE,
SPM_PARTITION_STATE_RUNNING,
+ SPM_PARTITION_STATE_HANDLING_IRQ,
SPM_PARTITION_STATE_SUSPENDED,
SPM_PARTITION_STATE_BLOCKED,
SPM_PARTITION_STATE_CLOSED
@@ -74,6 +75,16 @@
*/
struct iovec_args_t iovec_args;
psa_outvec *orig_outvec;
+ uint32_t *ctx_stack_ptr;
+ /*
+ * FIXME: There is a 'signal_mask' defined in the structure
+ * 'tfm_spm_ipc_partition_t'. It should be eliminated, and the IPC
+ * implementation should use the 'signal_mask' define in this structure.
+ * However currently the content of 'spm_partition_runtime_data_t' structure
+ * is not maintained by the IPC implementation. This is to be fixed with the
+ * effort of restructuring common code among library and IPC model.
+ */
+ uint32_t signal_mask;
};
@@ -215,6 +226,46 @@
#ifndef TFM_PSA_API
/**
+ * \brief Save interrupted partition context on ctx stack
+ *
+ * \param[in] partition_idx Partition index
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note This function doesn't whether the ctx stack overflows.
+ */
+void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx);
+
+/**
+ * \brief Restores interrupted partition context on ctx stack
+ *
+ * \param[in] partition_idx Partition index
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note This function doesn't whether the ctx stack underflows.
+ */
+void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx);
+
+/**
+ * \brief Save handler partition context on ctx stack
+ *
+ * \param[in] partition_idx Partition index
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note This function doesn't whether the ctx stack overflows.
+ */
+void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx);
+
+/**
+ * \brief Restores handler partition context on ctx stack
+ *
+ * \param[in] partition_idx Partition index
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ * \note This function doesn't whether the ctx stack underflows.
+ */
+void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx);
+
+/**
* \brief Get the current runtime data of a partition
*
* \param[in] partition_idx Partition index
@@ -329,6 +380,17 @@
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_cleanup_context(uint32_t partition_idx);
+
+/**
+ * \brief Set the signal mask for a given partition
+ *
+ * \param[in] partition_idx Partition index
+ * \param[in] signal_mask The signal mask to be set for the partition
+ *
+ * \note This function doesn't check if any of the partition_idxs are valid.
+ */
+void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
+ uint32_t signal_mask);
#endif /* !defined(TFM_PSA_API) */
/**
diff --git a/secure_fw/spm/spm_db_setup.h b/secure_fw/spm/spm_db_setup.h
index db06154..31696dc 100644
--- a/secure_fw/spm/spm_db_setup.h
+++ b/secure_fw/spm/spm_db_setup.h
@@ -56,22 +56,43 @@
} while (0)
#endif
+/* The max size of the context stack can be calculated as a function of the IRQ
+ * count of the secure partition:
+ *
+ * max_stack_size = intr_ctx_size + (IRQ_CNT * (intr_ctx_size + hndl_ctx_size))
+ *
+ * where:
+ * intr_ctx: Frame pushed when the partition is interrupted
+ * hndl_ctx: Frame pushed when the partition is handling an interrupt
+ */
+#define DECLARE_CONTEXT_STACK(partition) \
+ static uint32_t ctx_stack_ptr_##partition[ \
+ (sizeof(struct interrupted_ctx_stack_frame_t) + \
+ (TFM_PARTITION_##partition##_IRQ_COUNT) * ( \
+ sizeof(struct interrupted_ctx_stack_frame_t) + \
+ sizeof(struct handler_ctx_stack_frame_t) \
+ )) / sizeof(uint32_t)]
+
#if TFM_LVL == 1
-#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
- do { \
- data.partition_state = SPM_PARTITION_STATE_UNINIT; \
+#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
+ do { \
+ DECLARE_CONTEXT_STACK(partition); \
+ data.partition_state = SPM_PARTITION_STATE_UNINIT; \
+ data.ctx_stack_ptr = ctx_stack_ptr_##partition; \
} while (0)
#else
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
do { \
- data.partition_state = SPM_PARTITION_STATE_UNINIT; \
+ DECLARE_CONTEXT_STACK(partition); \
+ data.partition_state = SPM_PARTITION_STATE_UNINIT; \
/* The top of the stack is reserved for the iovec */ \
/* parameters of the service called. That's why in */ \
/* data.stack_ptr we extract sizeof(struct iovec_args_t) */ \
/* from the limit. */ \
- data.stack_ptr = \
+ data.stack_ptr = \
PART_REGION_ADDR(partition, _STACK$$ZI$$Limit - \
sizeof(struct iovec_args_t)); \
+ data.ctx_stack_ptr = ctx_stack_ptr_##partition; \
} while (0)
#endif
diff --git a/tools/tfm_generated_file_list.yaml b/tools/tfm_generated_file_list.yaml
index d28a6b6..053de9e 100644
--- a/tools/tfm_generated_file_list.yaml
+++ b/tools/tfm_generated_file_list.yaml
@@ -45,6 +45,11 @@
"name": "Secure Veneers H file",
"short_name": "tfm_veneers_h",
"output": "interface/include/tfm_veneers.h"
- }
+ },
+ {
+ "name": "Secure IRQ handlers",
+ "short_name": "tfm_secure_irq_handlers",
+ "output": "secure_fw/core/tfm_secure_irq_handlers.inc"
+ },
]
}