SPM: Partial implementation of PSA interrupt control APIs
This patch implements two of the Secure Partition APIs for
interrupt control defined by FF-M v1.1:
- psa_irq_enable
- psa_irq_disable
Implement only these two for SLIH for the time being.
Change-Id: Ia1103b2d70f1406e2ad0100d856f9e11568c2430
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/interface/include/psa/service.h b/interface/include/psa/service.h
index 94eb082..8cd6556 100644
--- a/interface/include/psa/service.h
+++ b/interface/include/psa/service.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -49,6 +49,9 @@
/* Store a set of one or more Secure Partition signals */
typedef uint32_t psa_signal_t;
+/* A type used to temporarily store a previous interrupt state. */
+typedef uint32_t psa_irq_status_t;
+
/**
* Describe a message received by an RoT Service after calling \ref psa_get().
*/
@@ -260,6 +263,40 @@
*/
void psa_panic(void);
+/**
+ * \brief Enable an interrupt.
+ *
+ * \param[in] irq_signal The signal for the interrupt to be enabled.
+ * This must have a single bit set, which must be the
+ * signal value for an interrupt in the calling Secure
+ * Partition.
+ *
+ * \retval void
+ * \retval "PROGRAMMER ERROR" If one or more of the following are true:
+ * \ref irq_signal is not an interrupt signal.
+ * \ref irq_signal indicates more than one signal.
+ */
+void psa_irq_enable(psa_signal_t irq_signal);
+
+/**
+ * \brief Disable an interrupt and return the status of the interrupt prior to
+ * being disabled by this call.
+ *
+ * \param[in] irq_signal The signal for the interrupt to be disabled.
+ * This must have a single bit set, which must be the
+ * signal value for an interrupt in the calling Secure
+ * Partition.
+ *
+ * \retval 0 The interrupt was disabled prior to this call.
+ * 1 The interrupt was enabled prior to this call.
+ * \retval "PROGRAMMER ERROR" If one or more of the following are true:
+ * \ref irq_signal is not an interrupt signal.
+ * \ref irq_signal indicates more than one signal.
+ *
+ * \note The current implementation always return 1. Do not use the return.
+ */
+psa_irq_status_t psa_irq_disable(psa_signal_t irq_signal);
+
#ifdef __cplusplus
}
#endif
diff --git a/interface/src/psa/psa_service.c b/interface/src/psa/psa_service.c
index ece17d0..7ae3bd1 100644
--- a/interface/src/psa/psa_service.c
+++ b/interface/src/psa/psa_service.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -102,3 +102,19 @@
"BX LR \n"
: : "I" (TFM_SVC_PSA_PANIC));
}
+
+__attribute__((naked))
+void psa_irq_enable(psa_signal_t irq_signal)
+{
+ __ASM volatile("SVC %0 \n"
+ "BX LR \n"
+ : : "I" (TFM_SVC_PSA_IRQ_ENABLE));
+}
+
+__attribute__((naked))
+psa_irq_status_t psa_irq_disable(psa_signal_t irq_signal)
+{
+ __ASM volatile("SVC %0 \n"
+ "BX LR \n"
+ : : "I" (TFM_SVC_PSA_IRQ_DISABLE));
+}
diff --git a/secure_fw/include/tfm/tfm_core_svc.h b/secure_fw/include/tfm/tfm_core_svc.h
index 8eed63e..18743e0 100644
--- a/secure_fw/include/tfm/tfm_core_svc.h
+++ b/secure_fw/include/tfm/tfm_core_svc.h
@@ -46,6 +46,10 @@
#if (TFM_SPM_LOG_LEVEL > TFM_SPM_LOG_LEVEL_SILENCE)
TFM_SVC_OUTPUT_UNPRIV_STRING,
#endif
+ /* Secure Partition API for interrupt control */
+ TFM_SVC_PSA_IRQ_ENABLE,
+ TFM_SVC_PSA_IRQ_DISABLE,
+
TFM_SVC_PLATFORM_BASE = 50 /* leave room for additional Core handlers */
} tfm_svc_number_t;
diff --git a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
index c0b880f..c3d4333 100644
--- a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
@@ -112,6 +112,11 @@
case TFM_SVC_OUTPUT_UNPRIV_STRING:
return tfm_hal_output_spm_log((const char *)ctx[0], ctx[1]);
#endif
+ case TFM_SVC_PSA_IRQ_ENABLE:
+ tfm_spm_irq_enable(ctx);
+ break;
+ case TFM_SVC_PSA_IRQ_DISABLE:
+ return tfm_spm_irq_disable(ctx);
default:
#ifdef PLATFORM_SVC_HANDLERS
return (platform_svc_handlers(svc_num, ctx, lr));
diff --git a/secure_fw/spm/ffm/psa_client_service_apis.c b/secure_fw/spm/ffm/psa_client_service_apis.c
index 235ee8b..20ac5be 100644
--- a/secure_fw/spm/ffm/psa_client_service_apis.c
+++ b/secure_fw/spm/ffm/psa_client_service_apis.c
@@ -15,6 +15,7 @@
#include "spm_func.h"
#endif
#include "tfm_core_utils.h"
+#include "tfm_hal_defs.h"
#include "tfm_hal_platform.h"
#include "ffm/spm_error_base.h"
#include "tfm_rpc.h"
@@ -621,3 +622,47 @@
*/
tfm_hal_system_reset();
}
+
+void tfm_spm_irq_enable(uint32_t *args)
+{
+ struct partition_t *partition;
+ psa_signal_t irq_signal;
+ uint32_t irq_line;
+
+ irq_signal = (psa_signal_t)args[0];
+
+ partition = tfm_spm_get_running_partition();
+ if (!partition) {
+ tfm_core_panic();
+ }
+
+ irq_line = get_irq_line_for_signal(partition->p_static->pid, irq_signal);
+ if (irq_line < 0) {
+ tfm_core_panic();
+ }
+
+ tfm_spm_hal_enable_irq((IRQn_Type)irq_line);
+}
+
+psa_irq_status_t tfm_spm_irq_disable(uint32_t *args)
+{
+ struct partition_t *partition;
+ psa_signal_t irq_signal;
+ uint32_t irq_line;
+
+ irq_signal = (psa_signal_t)args[0];
+
+ partition = tfm_spm_get_running_partition();
+ if (!partition) {
+ tfm_core_panic();
+ }
+
+ irq_line = get_irq_line_for_signal(partition->p_static->pid, irq_signal);
+ if (irq_line < 0) {
+ tfm_core_panic();
+ }
+
+ tfm_spm_hal_disable_irq((IRQn_Type)irq_line);
+
+ return 1;
+}
diff --git a/secure_fw/spm/ffm/psa_client_service_apis.h b/secure_fw/spm/ffm/psa_client_service_apis.h
index 9940960..acbe373 100644
--- a/secure_fw/spm/ffm/psa_client_service_apis.h
+++ b/secure_fw/spm/ffm/psa_client_service_apis.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -265,4 +265,33 @@
*/
void tfm_spm_psa_panic(void);
+/**
+ * \brief SVC handler for \ref psa_irq_enable.
+ *
+ * \param[in] args Include all input arguments: irq_signal.
+ *
+ * \retval void
+ * \retval "Does not return" The call is invalid, if one or more of the
+ * following are true:
+ * - irq_signal does not belong to the calling
+ * partition.
+ * - irq_signal indicates more than one signal.
+ */
+void tfm_spm_irq_enable(uint32_t *args);
+
+/**
+ * \brief SVC handler for \ref psa_irq_disable.
+ *
+ * \param[in] args Include all input arguments: irq_signal.
+ *
+ * \retval 0 The interrupt was disabled prior to this call
+ * 1 The interrupt was enabled prior to this call
+ * \retval "Does not return" The call is invalid, if one or more of the
+ * following are true:
+ * - irq_signal does not belong to the calling
+ * partition.
+ * - irq_signal indicates more than one signal.
+ */
+psa_irq_status_t tfm_spm_irq_disable(uint32_t *args);
+
#endif /* __PSA_CLIENT_SERVICE_APIS_H__ */