Build: Follow the 'source_structure.rst'
This is the first patch to follow the first commit of source structure
document. The items under the 'secure_fw' folder are re-organized:
- Create/Move some folders/files to follow document.
- Rename some folders to foll, for example, 'secure_fw/services' to
'secure_fw/partitions'.
- Update affected files to make it work.
This is a big change, to make the structure meet the basic shape of
the structure document defined, and make it easier to be understood
for users. Staging changes are not applicable so they are combined
into one - and because it is not the final shape yet, so:
- Upcoming updates on the 'secure_fw' folder would follow up soon.
- Fine-tune about the 'source_structure.rst' would come, too.
Change-Id: I5c11175e0a4579cd9b42d3e3519dbffb87334d0b
Signed-off-by: Ken Liu <ken.liu@arm.com>
diff --git a/secure_fw/spm/runtime/spm_api.c b/secure_fw/spm/runtime/spm_api.c
new file mode 100644
index 0000000..a72b402
--- /dev/null
+++ b/secure_fw/spm/runtime/spm_api.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* All the APIs defined in this file are common for library and IPC model. */
+
+#include <stdio.h>
+#include <string.h>
+#include "tfm/spm_api.h"
+#include "tfm_spm_hal.h"
+#include "tfm_memory_utils.h"
+#include "tfm/spm_db.h"
+#include "tfm_internal.h"
+#include "tfm_api.h"
+#include "tfm_nspm.h"
+#include "tfm_core.h"
+#include "tfm_peripherals_def.h"
+#include "tfm/spm_partition_defs.h"
+#include "region.h"
+
+#define NON_SECURE_INTERNAL_PARTITION_DB_IDX 0
+#define TFM_CORE_INTERNAL_PARTITION_DB_IDX 1
+
+/* Define SPM DB structure */
+#include "tfm_spm_db.inc"
+
+uint32_t get_partition_idx(uint32_t partition_id)
+{
+ uint32_t i;
+
+ if (partition_id == INVALID_PARTITION_ID) {
+ return SPM_INVALID_PARTITION_IDX;
+ }
+
+ for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
+ if (g_spm_partition_db.partitions[i].static_data->partition_id ==
+ partition_id) {
+ return i;
+ }
+ }
+ return SPM_INVALID_PARTITION_IDX;
+}
+
+enum spm_err_t tfm_spm_db_init(void)
+{
+ uint32_t i;
+
+ /* This function initialises partition db */
+
+ /* For the non secure Execution environment */
+#ifndef TFM_PSA_API
+ tfm_nspm_configure_clients();
+#endif
+
+ for (i = 0; i < g_spm_partition_db.partition_count; i++) {
+#ifndef TFM_PSA_API
+ g_spm_partition_db.partitions[i].runtime_data.partition_state =
+ SPM_PARTITION_STATE_UNINIT;
+ g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
+ SPM_INVALID_PARTITION_IDX;
+ g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
+ TFM_INVALID_CLIENT_ID;
+ g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
+ ctx_stack_list[i];
+#endif /* !defined(TFM_PSA_API) */
+ g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
+ g_spm_partition_db.partitions[i].platform_data_list =
+ platform_data_list_list[i];
+#ifdef TFM_PSA_API
+ g_spm_partition_db.partitions[i].memory_data = &memory_data_list[i];
+#endif
+ }
+ g_spm_partition_db.is_init = 1;
+
+ return SPM_ERR_OK;
+}
+
+uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].static_data->
+ partition_id;
+}
+
+uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
+{
+ return g_spm_partition_db.partitions[partition_idx].static_data->
+ partition_flags;
+}
+
+uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
+{
+ if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
+ return TFM_PARTITION_PRIVILEGED_MODE;
+ } else {
+ return TFM_PARTITION_UNPRIVILEGED_MODE;
+ }
+}
+
+bool tfm_is_partition_privileged(uint32_t partition_idx)
+{
+ uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
+
+ return tfm_spm_partition_get_privileged_mode(flags) ==
+ TFM_PARTITION_PRIVILEGED_MODE;
+}
+
+__attribute__((section("SFN")))
+void tfm_spm_partition_change_privilege(uint32_t privileged)
+{
+ CONTROL_Type ctrl;
+
+ ctrl.w = __get_CONTROL();
+
+ if (privileged == TFM_PARTITION_PRIVILEGED_MODE) {
+ ctrl.b.nPRIV = 0;
+ } else {
+ ctrl.b.nPRIV = 1;
+ }
+
+ __set_CONTROL(ctrl.w);
+}
diff --git a/secure_fw/spm/runtime/tfm_core_mem_check.c b/secure_fw/spm/runtime/tfm_core_mem_check.c
new file mode 100644
index 0000000..17ab074
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_core_mem_check.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arm_cmse.h>
+#include "region_defs.h"
+#include "tfm/spm_api.h"
+#include "tfm_api.h"
+
+/**
+ * \brief Check whether the current partition has access to a memory range
+ *
+ * This function assumes, that the current MPU configuration is set for the
+ * partition to be checked. The flags should contain information of the
+ * execution mode of the partition code (priv/unpriv), and access type
+ * (read/write) as specified in "ARMv8-M Security Extensions: Requirements on
+ * Development Tools" chapter "Address range check intrinsic"
+ *
+ * \param[in] p The start address of the range to check
+ * \param[in] s The size of the range to check
+ * \param[in] flags The flags to pass to the cmse_check_address_range func
+ *
+ * \return TFM_SUCCESS if the partition has access to the memory range,
+ * TFM_ERROR_GENERIC otherwise.
+ */
+static enum tfm_status_e has_access_to_region(const void *p, size_t s,
+ int flags)
+{
+ int32_t range_access_allowed_by_mpu;
+
+ /* Use the TT instruction to check access to the partition's regions*/
+ range_access_allowed_by_mpu =
+ cmse_check_address_range((void *)p, s, flags) != NULL;
+
+ if (range_access_allowed_by_mpu) {
+ return TFM_SUCCESS;
+ }
+
+ return TFM_ERROR_GENERIC;
+}
+
+enum tfm_status_e tfm_core_has_read_access_to_region(const void *p, size_t s,
+ bool ns_caller,
+ uint32_t privileged)
+{
+ int flags = CMSE_MPU_READ;
+
+ /* In case of NS caller, only force unprivileged check, if the non secure
+ * Thread mode is unprivileged
+ */
+ if (ns_caller) {
+ CONTROL_Type ctrl;
+
+ ctrl.w = __TZ_get_CONTROL_NS();
+ if (ctrl.b.nPRIV == 1) {
+ privileged = TFM_PARTITION_UNPRIVILEGED_MODE;
+ } else {
+ privileged = TFM_PARTITION_PRIVILEGED_MODE;
+ }
+ }
+
+ if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+ flags |= CMSE_MPU_UNPRIV;
+ }
+
+ if (ns_caller) {
+ flags |= CMSE_NONSECURE;
+ }
+
+ return has_access_to_region(p, s, flags);
+}
+
+enum tfm_status_e tfm_core_has_write_access_to_region(const void *p, size_t s,
+ bool ns_caller,
+ uint32_t privileged)
+{
+ int flags = CMSE_MPU_READWRITE;
+
+ /* In case of NS caller, only force unprivileged check, if the non secure
+ * Thread mode is unprivileged
+ */
+ if (ns_caller) {
+ CONTROL_Type ctrl;
+
+ ctrl.w = __TZ_get_CONTROL_NS();
+ if (ctrl.b.nPRIV == 1) {
+ privileged = TFM_PARTITION_UNPRIVILEGED_MODE;
+ } else {
+ privileged = TFM_PARTITION_PRIVILEGED_MODE;
+ }
+ }
+
+ if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
+ flags |= CMSE_MPU_UNPRIV;
+ }
+
+ if (ns_caller) {
+ flags |= CMSE_NONSECURE;
+ }
+
+ return has_access_to_region(p, s, flags);
+}
diff --git a/secure_fw/spm/runtime/tfm_core_utils.c b/secure_fw/spm/runtime/tfm_core_utils.c
new file mode 100644
index 0000000..ba9a4ea
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_core_utils.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include "tfm_utils.h"
+#include "tfm_core_utils.h"
+
+union tfm_core_addr_t {
+ uintptr_t uint_addr;
+ uint8_t *p_byte;
+ uint32_t *p_word;
+};
+
+void *tfm_core_util_memcpy(void *dest, const void *src, size_t n)
+{
+ union tfm_core_addr_t p_dest;
+ union tfm_core_addr_t p_src;
+
+ TFM_CORE_ASSERT(dest != src);
+
+ p_dest.p_byte = (uint8_t *)dest;
+ p_src.p_byte = (uint8_t *)src;
+
+ /*
+ * Check src and dest address value to see if word-copy is applicable.
+ * If applicable, use byte-copy for the first several unaligned bytes,
+ * and then, word-copy for aligned memory.
+ */
+ if (!((p_dest.uint_addr ^ p_src.uint_addr) & (sizeof(uint32_t) - 1))) {
+ while (n && (p_dest.uint_addr & (sizeof(uint32_t) - 1))) {
+ *p_dest.p_byte++ = *p_src.p_byte++;
+ n--;
+ }
+
+ while (n >= sizeof(uint32_t)) {
+ *p_dest.p_word++ = *p_src.p_word++;
+ n -= sizeof(uint32_t);
+ }
+ }
+
+ /*
+ * Word-copy is not applicable, use byte-copy for the remaining
+ * unaligned memory.
+ */
+ while (n--) {
+ *p_dest.p_byte++ = *p_src.p_byte++;
+ }
+
+ return dest;
+}
+
+void *tfm_core_util_memset(void *s, int c, size_t n)
+{
+ union tfm_core_addr_t p_mem;
+ uint32_t quad_pattern;
+
+ p_mem.p_byte = (uint8_t *)s;
+ quad_pattern = (((uint8_t)c) << 24) | (((uint8_t)c) << 16) |
+ (((uint8_t)c) << 8) | ((uint8_t)c);
+
+ while (n && (p_mem.uint_addr & (sizeof(uint32_t) - 1))) {
+ *p_mem.p_byte++ = (uint8_t)c;
+ n--;
+ }
+
+ while (n >= sizeof(uint32_t)) {
+ *p_mem.p_word++ = quad_pattern;
+ n -= sizeof(uint32_t);
+ }
+
+ while (n--) {
+ *p_mem.p_byte++ = (uint8_t)c;
+ }
+
+ return s;
+}
diff --git a/secure_fw/spm/runtime/tfm_secure_api.c b/secure_fw/spm/runtime/tfm_secure_api.c
new file mode 100644
index 0000000..eecb62e
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_secure_api.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include "secure_utilities.h"
+#include "tfm_secure_api.h"
+
+/* This is the "Big Lock" on the secure side, to guarantee single entry
+ * to SPE
+ */
+int32_t tfm_secure_lock;
+
+bool tfm_is_one_bit_set(uint32_t n)
+{
+ return ((n && !(n & (n-1))) ? true : false);
+}
+
+enum tfm_status_e check_address_range(const void *p, size_t s,
+ uintptr_t region_start,
+ uintptr_t region_limit)
+{
+ int32_t range_in_region;
+
+ /* Check for overflow in the range parameters */
+ if ((uintptr_t)p > UINTPTR_MAX - s) {
+ return TFM_ERROR_GENERIC;
+ }
+
+ /* We trust the region parameters, and don't check for overflow */
+
+ /* Calculate the result */
+ range_in_region = ((uintptr_t)p >= region_start) &&
+ ((uintptr_t)((char *) p + s - 1) <= region_limit);
+ if (range_in_region) {
+ return TFM_SUCCESS;
+ } else {
+ return TFM_ERROR_GENERIC;
+ }
+}
+
+void tfm_secure_api_error_handler(void)
+{
+ ERROR_MSG("Security violation when calling secure API");
+ tfm_core_panic();
+}
+
+#ifndef TFM_PSA_API
+int32_t tfm_core_partition_request(uint32_t id, bool is_ns, void *fn,
+ int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
+{
+ int32_t args[4] = {arg1, arg2, arg3, arg4};
+ struct tfm_sfn_req_s desc, *desc_ptr = &desc;
+
+ desc.sp_id = id;
+ desc.sfn = (sfn_t) fn;
+ desc.args = args;
+ desc.ns_caller = is_ns;
+
+ if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
+ /* The veneer of a secure service had been called from Handler mode.
+ * This violates TF-M's programming model, and is considered an
+ * unrecoverable error.
+ */
+ tfm_core_panic();
+ } else {
+ if (desc.ns_caller) {
+ return tfm_core_sfn_request(desc_ptr);
+ } else {
+ return tfm_spm_sfn_request_thread_mode(desc_ptr);
+ }
+ }
+ return TFM_ERROR_GENERIC;
+}
+#endif
diff --git a/secure_fw/spm/runtime/tfm_spm_db.inc b/secure_fw/spm/runtime/tfm_spm_db.inc
new file mode 100644
index 0000000..afc9c79
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_spm_db.inc
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SPM_DB_INC__
+#define __TFM_SPM_DB_INC__
+
+#ifdef TFM_PSA_API
+#include "tfm_spm_db_ipc.inc"
+#else
+#include "tfm_spm_db_func.inc"
+#endif
+
+#endif /* __TFM_SPM_DB_INC__ */
\ No newline at end of file
diff --git a/secure_fw/spm/runtime/tfm_spm_services.c b/secure_fw/spm/runtime/tfm_spm_services.c
new file mode 100644
index 0000000..2a04c6e
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_spm_services.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arm_cmse.h>
+
+#include "tfm/tfm_core_svc.h"
+#include "tfm_secure_api.h"
+#include "tfm_internal.h"
+#include "secure_fw/include/tfm/tfm_spm_services_api.h"
+#include "tfm/spm_api.h"
+#include "psa/service.h"
+
+#ifndef TFM_PSA_API
+nsfptr_t ns_entry;
+
+void jump_to_ns_code(void)
+{
+ /* Calls the non-secure Reset_Handler to jump to the non-secure binary */
+ ns_entry();
+}
+
+__attribute__((naked))
+int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
+{
+ __ASM volatile(
+ "SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_GET_CALLER_CLIENT_ID));
+}
+
+__attribute__((naked))
+int32_t tfm_core_validate_secure_caller(void)
+{
+ __ASM volatile(
+ "SVC %0\n"
+ "BX lr\n"
+ : : "I" (TFM_SVC_VALIDATE_SECURE_CALLER));
+}
+
+#endif
+
+__attribute__((naked))
+int32_t tfm_spm_request(void)
+{
+ __ASM volatile(
+ "SVC %0\n"
+ "BX lr\n"
+ : : "I" (TFM_SVC_SPM_REQUEST));
+}
+
+__attribute__((naked))
+int32_t tfm_spm_request_reset_vote(void)
+{
+ __ASM volatile(
+ "MOVS R0, %0\n"
+ "B tfm_spm_request\n"
+ : : "I" (TFM_SPM_REQUEST_RESET_VOTE));
+}
+
+__attribute__((naked))
+int32_t tfm_core_get_boot_data(uint8_t major_type,
+ struct tfm_boot_data *boot_status,
+ uint32_t len)
+{
+ __ASM volatile(
+ "SVC %0\n"
+ "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/spm/runtime/tfm_utils.c b/secure_fw/spm/runtime/tfm_utils.c
new file mode 100644
index 0000000..c1d9d35
--- /dev/null
+++ b/secure_fw/spm/runtime/tfm_utils.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <inttypes.h>
+#include "tfm_utils.h"
+#include "tfm_spm_hal.h"
+
+void tfm_core_panic(void)
+{
+ /*
+ * FixMe: In the first stage, the SPM will restart the entire system when a
+ * programmer error is detected in either the SPE or NSPE.
+ * In the next stage, the specified error codes are also sent to any NSPE
+ * management firmware. The NSPE management firmware can then decide to pass
+ * those error codes back to the calling task or to use its own
+ * functionality for terminating an execution context.
+ */
+ tfm_spm_hal_system_reset();
+}