psa: Remove S-mode only code

Remove all PSA S-mode only code, as it is unused. Only PSA S targets
would use the code, and we've removed those targets in a previous
commit.

Ensure all tests for S-mode code we are deleting is also removed, even
if that code would run in NS-mode. Keep any tests that also test our PSA
emulation support (for single v7-M targets).

Signed-off-by: Jaeden Amero <jaeden.amero@arm.com>
pull/12737/head
Jaeden Amero 2020-03-17 12:02:55 +00:00 committed by Jaeden Amero
parent 6b3a9cb4fa
commit fcf427ac11
91 changed files with 5 additions and 15131 deletions

View File

@ -1,49 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_HAL_SPM_FAULT_FUNCTIONS__
#define __MBED_HAL_SPM_FAULT_FUNCTIONS__
#include "cmsis_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
// Retruns the value of the LR register
// Used to determine which stack the exception happend in
__STATIC_FORCEINLINE uint32_t __get_LR(void);
// This function is required as we need a symbol/address
// to jump to from fault handler.
void do_nothing(void);
// Test exception handler
static void hard_fault_handler_test();
// Using naked function as it will not be executed from beginning to the end.
// The execution flow expected to be interrupted by exception and we will
// return to other function.
// compiler will not produce prolog and epilog code for naked function
// and thus will preserve stack in un-corrupted state
__attribute__((naked)) void call_mem(uint32_t addr);
#ifdef __cplusplus
}
#endif
#endif // __MBED_HAL_SPM_FAULT_FUNCTIONS__

View File

@ -1,162 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(COMPONENT_PSA_SRV_IPC)
#error [NOT_SUPPORTED] Test supported only on PSA targets
#else
#if (defined(__ARMCC_VERSION) || defined( __ICCARM__ ))
#error [NOT_SUPPORTED] this test is supported on GCC only
#else
#if DOMAIN_NS == 1
#error [NOT_SUPPORTED] Cannot run on M23/M33 core as SecureFault is implemented in secure-side and cant be remapped
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "cmsis.h"
#include "spm_api.h"
#include <stdlib.h>
#include "fault_functions.h"
using namespace utest::v1;
#define HARDFAULT_IRQn ((IRQn_Type)-13)
#define EXC_RETURN_RETURN_STACK_MSK ((uint32_t)(0x00000004))
#define PC_INDEX_IN_STACK_FRAME 6
volatile uint32_t fault_occurred;
uint32_t real_hard_fault_handler;
__STATIC_FORCEINLINE uint32_t __get_LR(void)
{
uint32_t result;
__ASM volatile("MOV %0, lr" : "=r"(result));
return (result);
}
void do_nothing(void)
{
__NOP();
}
static void hard_fault_handler_test()
{
fault_occurred++;
// LR is set EXC_RETURN
// lowest bits identify PSP vs MSP stack used for stacking
uint32_t lr = __get_LR();
uint32_t sp;
if (lr & EXC_RETURN_RETURN_STACK_MSK) {
sp = __get_PSP();
} else {
sp = __get_MSP();
}
// Overwrite return address.
// Fake return to a our special function since current
// instruction under test will always fail due to memory protection
((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing;
}
__attribute__((naked)) void call_mem(uint32_t addr)
{
// Only first instruction will be executed in positive flow,
// since exception will be generated for invalid memory access.
// Other instructions are for calling do_nothing function according to AAPCS.
__ASM(
"LDR r3, [r0]\n"
"BX lr\n"
);
}
static void test_memory(uint32_t addr, uint32_t expected_fatal_count)
{
call_mem(addr);
// Although call_mem is a "naked" function, it is called using AAPCS.
// Thus we can assume LR will point to next instruction, and caller save registers are backed up
TEST_ASSERT_EQUAL(expected_fatal_count, fault_occurred);
}
static void secure_ram_fault_test(void)
{
test_memory(PSA_SECURE_RAM_START, 1);
}
static void secure_flash_fault_test(void)
{
test_memory(PSA_SECURE_ROM_START, 1);
}
static void non_secure_ram_fault_test(void)
{
test_memory(PSA_NON_SECURE_RAM_START, 0);
}
static void non_secure_flash_fault_test(void)
{
test_memory(PSA_NON_SECURE_ROM_START, 0);
}
utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case)
{
// Save old hard fault handler and replace it with a new one
// NOTE: only works when VTOR is set to RAM
real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn);
NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
fault_occurred = 0;
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
{
// Restore real hard fault handler
NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler);
return greentea_case_teardown_handler(source, passed, failed, reason);
}
Case cases[] = {
Case("SPM - Access non-secure RAM", fault_override_setup, non_secure_ram_fault_test, fault_override_teardown),
Case("SPM - Access non-secure Flash", fault_override_setup, non_secure_flash_fault_test, fault_override_teardown),
Case("SPM - Access secure RAM", fault_override_setup, secure_ram_fault_test, fault_override_teardown),
Case("SPM - Access secure Flash", fault_override_setup, secure_flash_fault_test, fault_override_teardown)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif // DOMAIN_NS == 1
#endif // (defined(__ARMCC_VERSION) || defined( __ICCARM__ ))
#endif // !defined(COMPONENT_PSA_SRV_IPC)

View File

@ -1,556 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "psa/crypto.h"
#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C)) || (!defined(COMPONENT_PSA_SRV_IPC)))
#error [NOT_SUPPORTED] These tests can run only on SPM-enabled targets and where Mbed Crypto is ON - skipping.
#else
#include <stdio.h>
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "entropy.h"
#include "entropy_poll.h"
#include "test_partition_proxy.h"
#include "psa/lifecycle.h"
using namespace utest::v1;
#if defined(MBEDTLS_ENTROPY_NV_SEED) || defined(COMPONENT_PSA_SRV_IPC)
#if !defined(MAX)
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \
MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
void inject_entropy()
{
uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = { 0 };
for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) {
seed[i] = i;
}
mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE);
}
#endif // defined(MBEDTLS_ENTROPY_NV_SEED) || defined(COMPONENT_PSA_SRV_IPC)
static psa_status_t create_and_generate_key_via_test_partition(
const psa_key_attributes_t *attributes,
psa_key_handle_t *key_handle,
uint8_t close_key)
{
TEST_ASSERT_EQUAL(PSA_SUCCESS,
test_partition_crypto_generate_key(attributes,
key_handle));
TEST_ASSERT_NOT_EQUAL(0, *key_handle);
if (close_key) {
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_close_key(*key_handle));
}
return (PSA_SUCCESS);
}
void test_open_other_partition_key(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
static const psa_algorithm_t key_alg = PSA_ALG_CBC_NO_PADDING;
static const size_t key_bits = 128;
psa_key_handle_t key_handle = 0;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle, 1));
/* via test partition - reopen the key created by the test partition */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* via test partition - close the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_close_key(key_handle));
/* try to open the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, psa_open_key(key_id, &key_handle));
/* via test partition - reopen the key created by the test partition and keep it open */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_create_key_same_id_different_partitions(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_key_usage_t key_usage_remote = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT,
key_usage_local = PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY;
static const psa_algorithm_t key_alg = PSA_ALG_CBC_NO_PADDING;
static const size_t key_bits_remote = 128,
key_bits_local = 256;
psa_key_handle_t key_handle_remote = 0,
key_handle_local = 0;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage_remote);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits_remote);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle_remote, 1));
psa_reset_key_attributes(&attributes);
/* create a key, generate key material and close from current partition (i.e. NSPE) */
psa_set_key_usage_flags(&attributes, key_usage_local);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits_local);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_generate_key(&attributes, &key_handle_local));
TEST_ASSERT_NOT_EQUAL(0, key_handle_local);
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_close_key(key_handle_local));
/* via test partition - reopen the key created by the test partition */
key_handle_remote = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle_remote));
TEST_ASSERT_NOT_EQUAL(0, key_handle_remote);
/* reopen the key created from the current partition (NSPE) */
key_handle_local = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_open_key(key_id, &key_handle_local));
TEST_ASSERT_NOT_EQUAL(0, key_handle_local);
/* via test partition - get key info for the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS,
test_partition_crypto_get_key_attributes(key_handle_remote,
&attributes));
TEST_ASSERT_EQUAL(key_type, psa_get_key_type(&attributes));
TEST_ASSERT_EQUAL(key_bits_remote, psa_get_key_bits(&attributes));
TEST_ASSERT_EQUAL(key_usage_remote, psa_get_key_usage_flags(&attributes));
TEST_ASSERT_EQUAL(key_alg, psa_get_key_algorithm(&attributes));
/* get key attributes for key created by the current partition (NSPE) */
attributes = psa_key_attributes_init();
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_get_key_attributes(key_handle_local, &attributes));
TEST_ASSERT_EQUAL(key_type, psa_get_key_type(&attributes));
TEST_ASSERT_EQUAL(key_bits_local, psa_get_key_bits(&attributes));
TEST_ASSERT_EQUAL(key_usage_local, psa_get_key_usage_flags(&attributes));
TEST_ASSERT_EQUAL(key_alg, psa_get_key_algorithm(&attributes));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle_remote));
/* destroy the key created by the current partition (NSPE) */
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_destroy_key(key_handle_local));
}
void test_use_other_partition_key_manage_key(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_algorithm_t key_alg = PSA_ALG_CBC_NO_PADDING;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_EXPORT;
static const size_t key_bits = 128;
static const uint8_t key_data[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};
psa_key_handle_t key_handle = 0;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
uint8_t output[sizeof(key_data)] = { 0 };
size_t len;
/* via test partition - generate a persistent key and close the key */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_generate_key(&attributes, &key_handle));
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_close_key(key_handle));
/* via test partition - reopen the key created by the test partition and keep it open */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to work with the handle created for a key created by the test partition */
attributes = psa_key_attributes_init();
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_get_key_attributes(key_handle, &attributes));
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_close_key(key_handle));
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_destroy_key(key_handle));
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_export_key(key_handle, output, sizeof(output), &len));
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_export_public_key(key_handle, output, sizeof(output), &len));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
/* via test partition - import key data for the key created by the test partition */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
test_partition_crypto_import_key(
&attributes, key_data, sizeof(key_data), &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_mac(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_algorithm_t key_alg = PSA_ALG_CBC_NO_PADDING;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY;
static const size_t key_bits = 128;
psa_key_handle_t key_handle = 0;
psa_mac_operation_t operation;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle, 1));
/* via test partition - reopen the key created by the test partition */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to setup mac sign operation using the key that was created by the test partition */
operation = psa_mac_operation_init();
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_mac_sign_setup(&operation, key_handle, key_alg));
/* try to setup mac verify operation using the key that was created by the test partition */
operation = psa_mac_operation_init();
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_mac_verify_setup(&operation, key_handle, key_alg));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_cipher(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_algorithm_t key_alg = PSA_ALG_CBC_NO_PADDING;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY;
static const size_t key_bits = 128;
psa_key_handle_t key_handle = 0;
psa_cipher_operation_t operation;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle, 1));
/* via test partition - reopen the key created by the test partition */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to setup cipher encrypt operation using the key that was created by the test partition */
operation = psa_cipher_operation_init();
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_cipher_encrypt_setup(&operation, key_handle, key_alg));
/* try to setup cipher decrypt operation using the key that was created by the test partition */
operation = psa_cipher_operation_init();
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_cipher_decrypt_setup(&operation, key_handle, key_alg));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_aead(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_AES;
static const psa_algorithm_t key_alg = PSA_ALG_GCM;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
static const size_t key_bits = 128;
static const uint8_t nonce[16] = { 0 };
uint8_t plain_text[] = "encrypt me!";
uint8_t cipher_text[PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_alg, sizeof(plain_text))] = { 0 };
psa_key_handle_t key_handle = 0;
size_t len;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle, 1));
/* via test partition - reopen the key created by the test partition */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to aead encrypt using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_aead_encrypt(key_handle, key_alg, nonce, sizeof(nonce), NULL, 0,
plain_text, sizeof(plain_text),
cipher_text, sizeof(cipher_text), &len));
/* try to aead decrypt using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_aead_decrypt(key_handle, key_alg, nonce, sizeof(nonce), NULL, 0,
cipher_text, sizeof(cipher_text),
plain_text, sizeof(plain_text), &len));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_asymmetric_sign_verify(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1);
static const psa_algorithm_t key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY;
static const size_t key_bits = 256;
static const uint8_t input[] = "hello world!";
uint8_t signature[PSA_ECDSA_SIGNATURE_SIZE(key_bits)] = { 0 };
psa_key_handle_t key_handle = 0;
size_t len;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - create a key, generate key material and close */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, key_bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
create_and_generate_key_via_test_partition(&attributes, &key_handle, 1));
/* via test partition - reopen the key created by the test partition */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to asymmetric sign using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_sign_hash(key_handle, key_alg, input, sizeof(input),
signature, sizeof(signature), &len));
/* try to asymmetric verify using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_verify_hash(key_handle, key_alg, input, sizeof(input),
signature, sizeof(signature)));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_asymmetric_encrypt_decrypt(void)
{
static const psa_key_id_t key_id = 999;
static const psa_key_type_t key_type = PSA_KEY_TYPE_RSA_KEY_PAIR;
static const psa_algorithm_t key_alg = PSA_ALG_RSA_PKCS1V15_CRYPT;
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
static const uint8_t input[] = "encrypt me!";
static const uint8_t key_data[] = {
0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xee, 0x2b,
0x13, 0x1d, 0x6b, 0x18, 0x18, 0xa9, 0x4c, 0xa8, 0xe9, 0x1c, 0x42, 0x38,
0x7e, 0xb1, 0x5a, 0x7c, 0x27, 0x1f, 0x57, 0xb8, 0x9e, 0x73, 0x36, 0xb1,
0x44, 0xd4, 0x53, 0x5b, 0x16, 0xc8, 0x30, 0x97, 0xec, 0xde, 0xfb, 0xbb,
0x92, 0xd1, 0xb5, 0x31, 0x3b, 0x5a, 0x37, 0x21, 0x4d, 0x0e, 0x8f, 0x25,
0x92, 0x2d, 0xca, 0x77, 0x8b, 0x42, 0x4b, 0x25, 0x29, 0x5f, 0xc8, 0xa1,
0xa7, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x41, 0x00, 0x97, 0x8a,
0xc8, 0xea, 0xdb, 0x0d, 0xc6, 0x03, 0x53, 0x47, 0xd6, 0xab, 0xa8, 0x67,
0x12, 0x15, 0xff, 0x21, 0x28, 0x33, 0x85, 0x39, 0x6f, 0x78, 0x97, 0xc0,
0x4b, 0xaf, 0x5e, 0x2a, 0x83, 0x5f, 0x3b, 0x53, 0xef, 0x80, 0xa8, 0x2e,
0xd3, 0x6a, 0xe6, 0x87, 0xa9, 0x25, 0x38, 0x0b, 0x55, 0xa0, 0xc7, 0x3e,
0xb8, 0x56, 0x56, 0xe9, 0x89, 0xdc, 0xf0, 0xed, 0x7f, 0xb4, 0x88, 0x70,
0x24, 0xe1, 0x02, 0x21, 0x00, 0xfd, 0xad, 0x8e, 0x1c, 0x68, 0x53, 0x56,
0x3f, 0x8b, 0x92, 0x1d, 0x2d, 0x11, 0x24, 0x62, 0xae, 0x7d, 0x6b, 0x17,
0x60, 0x82, 0xd2, 0xba, 0x43, 0xe8, 0x7e, 0x1a, 0x37, 0xfc, 0x1a, 0x8b,
0x33, 0x02, 0x21, 0x00, 0xf0, 0x59, 0x2c, 0xf4, 0xc5, 0x5b, 0xa4, 0x43,
0x07, 0xb1, 0x89, 0x81, 0xbc, 0xdb, 0xda, 0x37, 0x6c, 0x51, 0xe5, 0x90,
0xff, 0xa5, 0x34, 0x5b, 0xa8, 0x66, 0xf6, 0x96, 0x2d, 0xca, 0x94, 0xdd,
0x02, 0x20, 0x19, 0x95, 0xf1, 0xa9, 0x67, 0xd4, 0x4f, 0xf4, 0xa4, 0xcd,
0x1d, 0xe8, 0x37, 0xbc, 0x65, 0xbf, 0x97, 0xa2, 0xbf, 0x7e, 0xda, 0x73,
0x0a, 0x9a, 0x62, 0xce, 0xa5, 0x32, 0x54, 0x59, 0x11, 0x05, 0x02, 0x20,
0x27, 0xf9, 0x6c, 0xf4, 0xb8, 0xee, 0x68, 0xff, 0x8d, 0x04, 0x06, 0x2e,
0xc1, 0xce, 0x7f, 0x18, 0xc0, 0xb7, 0x4e, 0x4b, 0x33, 0x79, 0xb2, 0x9f,
0x9b, 0xfe, 0xa3, 0xfc, 0x8e, 0x59, 0x27, 0x31, 0x02, 0x21, 0x00, 0xce,
0xfa, 0x6d, 0x22, 0x04, 0x96, 0xb4, 0x3f, 0xeb, 0x83, 0x19, 0x42, 0x55,
0xd8, 0xfb, 0x93, 0x0a, 0xfc, 0xf4, 0x6f, 0x36, 0x60, 0x6e, 0x3a, 0xa0,
0xeb, 0x7a, 0x93, 0xad, 0x88, 0xc1, 0x0c
};
uint8_t encrypted[64] = { 0 };
uint8_t decrypted[sizeof(input)] = { 0 };
psa_key_handle_t key_handle = 0;
size_t len;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - import key data for the key created by the test partition */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, 512);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
test_partition_crypto_import_key(
&attributes, key_data, sizeof(key_data), &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* via test partition - close the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_close_key(key_handle));
/* via test partition - reopen the key created by the test partition and keep it open */
key_handle = 0;
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_open_key(key_id, &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to asymmetric encrypt using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_asymmetric_encrypt(key_handle, key_alg, input, sizeof(input),
NULL, 0, encrypted, sizeof(encrypted), &len));
/* try to asymmetric decrypt using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE, psa_asymmetric_decrypt(key_handle, key_alg,
encrypted, sizeof(encrypted), NULL, 0,
decrypted, sizeof(decrypted), &len));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
void test_use_other_partition_key_derivation_setup(void)
{
static const psa_key_id_t key_id = 999;
static const psa_algorithm_t key_alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
static const psa_key_usage_t key_usage = PSA_KEY_USAGE_DERIVE;
static const psa_key_type_t key_type = PSA_KEY_TYPE_DERIVE;
static const uint8_t key_data[] = {
0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xee, 0x2b,
0x13, 0x1d, 0x6b, 0x18, 0x18, 0xa9, 0x4c, 0xa8, 0xe9, 0x1c, 0x42, 0x38
};
psa_key_handle_t key_handle = 0;
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
size_t bits = 192;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
/* via test partition - import key data for the key created by the test partition */
psa_set_key_usage_flags(&attributes, key_usage);
psa_set_key_algorithm(&attributes, key_alg);
psa_set_key_bits(&attributes, bits);
psa_set_key_type(&attributes, key_type);
psa_set_key_id(&attributes, key_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS,
test_partition_crypto_import_key(
&attributes, key_data, sizeof(key_data), &key_handle));
TEST_ASSERT_NOT_EQUAL(0, key_handle);
/* try to setup key derivation using the key that was created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, psa_key_derivation_setup(&operation, key_alg));
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_HANDLE,
psa_key_derivation_input_key(
&operation, PSA_KEY_DERIVATION_INPUT_SECRET, key_handle));
/* via test partition - destroy the key created by the test partition */
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_partition_crypto_destroy_key(key_handle));
}
utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case)
{
psa_status_t status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
status = psa_crypto_init();
#if defined(MBEDTLS_ENTROPY_NV_SEED) || defined(COMPONENT_PSA_SRV_IPC)
if (status == PSA_ERROR_INSUFFICIENT_ENTROPY) {
inject_entropy();
status = psa_crypto_init();
}
#endif
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed,
const size_t failed, const failure_t failure)
{
psa_status_t status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
mbedtls_psa_crypto_free();
return greentea_case_teardown_handler(source, passed, failed, failure);
}
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(120, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("open other partition's key",
case_setup_handler, test_open_other_partition_key, case_teardown_handler),
Case("create key with same id different partitions",
case_setup_handler, test_create_key_same_id_different_partitions, case_teardown_handler),
Case("use other partition's key - key manage",
case_setup_handler, test_use_other_partition_key_manage_key, case_teardown_handler),
Case("use other partition's key - mac",
case_setup_handler, test_use_other_partition_key_mac, case_teardown_handler),
Case("use other partition's key - cipher",
case_setup_handler, test_use_other_partition_key_cipher, case_teardown_handler),
Case("use other partition's key - aead",
case_setup_handler, test_use_other_partition_key_aead, case_teardown_handler),
Case("use other partition's key - asymmetric sign verify",
case_setup_handler, test_use_other_partition_key_asymmetric_sign_verify, case_teardown_handler),
Case("use other partition's key - asymmetric encrypt decrypt",
case_setup_handler, test_use_other_partition_key_asymmetric_encrypt_decrypt, case_teardown_handler),
Case("use other partition's key - key derivation setup",
case_setup_handler, test_use_other_partition_key_derivation_setup, case_teardown_handler),
};
Specification specification(test_setup, cases);
int main(void)
{
return !Harness::run(specification);
}
#endif // ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C)) || (!defined(COMPONENT_PSA_SRV_IPC)))

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "psa/client.h"
#include "psa_manifest/sid.h"
#include "test_partition_proxy.h"
#define MINOR_VER 1
static psa_status_t invoke_ipc_call(uint32_t sid, psa_invec *in_vec, size_t in_vec_size,
psa_outvec *out_vec, size_t out_vec_size)
{
psa_status_t status;
psa_handle_t handle = psa_connect(sid, MINOR_VER);
if (handle <= 0) {
return (PSA_ERROR_COMMUNICATION_FAILURE);
}
status = psa_call(handle, in_vec, in_vec_size, out_vec, out_vec_size);
psa_close(handle);
return (status);
}
psa_status_t test_partition_crypto_get_key_attributes(
psa_key_handle_t key_handle, psa_key_attributes_t *attributes)
{
psa_invec in_vec = { &key_handle, sizeof(key_handle) };
psa_outvec out_vec[1] = {
{ attributes, sizeof(*attributes) }
};
psa_status_t status = invoke_ipc_call(CRYPTO_GET_KEY_ATTRIBUTES, &in_vec, 1, out_vec, 1);
return (status);
}
psa_status_t test_partition_crypto_generate_key(
const psa_key_attributes_t *attributes, psa_key_handle_t *key_handle)
{
psa_invec in_vec[] = {
{ attributes, sizeof(*attributes) },
};
psa_outvec out_vec[] = {
{ key_handle, sizeof(*key_handle) },
};
psa_status_t status = invoke_ipc_call(CRYPTO_GENERATE_KEY, in_vec, 1, out_vec, 1);
return (status);
}
psa_status_t test_partition_crypto_open_key(psa_key_id_t key_id, psa_key_handle_t *key_handle)
{
psa_invec in_vec = { &key_id, sizeof(key_id) };
psa_outvec out_vec = { key_handle, sizeof(*key_handle) };
psa_status_t status = invoke_ipc_call(CRYPTO_OPEN_KEY, &in_vec, 1, &out_vec, 1);
return (status);
}
psa_status_t test_partition_crypto_close_key(psa_key_handle_t key_handle)
{
psa_invec in_vec = { &key_handle, sizeof(key_handle) };
psa_status_t status = invoke_ipc_call(CRYPTO_CLOSE_KEY, &in_vec, 1, NULL, 0);
return (status);
}
psa_status_t test_partition_crypto_destroy_key(psa_key_handle_t key_handle)
{
psa_invec in_vec = { &key_handle, sizeof(key_handle) };
psa_status_t status = invoke_ipc_call(CRYPTO_DESTROY_KEY, &in_vec, 1, NULL, 0);
return (status);
}
psa_status_t test_partition_crypto_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_data,
size_t key_data_size,
psa_key_handle_t *key_handle)
{
psa_invec in_vec[] = {
{ attributes, sizeof(*attributes) },
{ key_data, key_data_size },
};
psa_outvec out_vec[] = {
{ key_handle, sizeof(*key_handle) },
};
psa_status_t status = invoke_ipc_call(CRYPTO_IMPORT_KEY, in_vec, 2, out_vec, 1);
return (status);
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TEST_PARTITION_PROXY_H
#define TEST_PARTITION_PROXY_H
#include "psa/crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
psa_status_t test_partition_crypto_get_key_attributes(
psa_key_handle_t key_handle, psa_key_attributes_t *attributes);
psa_status_t test_partition_crypto_generate_key(
const psa_key_attributes_t *attributes, psa_key_handle_t *key_handle);
psa_status_t test_partition_crypto_open_key(
psa_key_id_t key_id, psa_key_handle_t *key_handle);
psa_status_t test_partition_crypto_close_key(psa_key_handle_t key_handle);
psa_status_t test_partition_crypto_destroy_key(psa_key_handle_t key_handle);
psa_status_t test_partition_crypto_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_data,
size_t key_data_size,
psa_key_handle_t *key_handle);
#ifdef __cplusplus
}
#endif
#endif /* TEST_PARTITION_PROXY_H */

View File

@ -1,193 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include "mbed_spm_partitions.h"
#include "psa/client.h"
#include "psa/service.h"
#include "psa/crypto.h"
typedef psa_status_t (*SignalHandler)(psa_msg_t *);
static void read_input_param_from_message(psa_msg_t *msg, uint8_t param_index, void *param_ptr)
{
size_t bytes_read = psa_read(msg->handle, param_index, param_ptr, msg->in_size[param_index]);
if (bytes_read != msg->in_size[param_index]) {
SPM_PANIC("SPM read length mismatch");
}
}
static psa_status_t crypto_generate_key(psa_msg_t *msg)
{
psa_status_t status;
psa_key_handle_t key_handle = 0;
psa_key_type_t key_type = 0;
size_t key_bits = 0;
psa_key_attributes_t attributes;
read_input_param_from_message(msg, 0, &attributes);
status = psa_generate_key(&attributes, &key_handle);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &key_handle, sizeof(key_handle));
}
return (status);
}
static psa_status_t crypto_open_key(psa_msg_t *msg)
{
psa_status_t status;
psa_key_id_t key_id;
psa_key_handle_t key_handle;
read_input_param_from_message(msg, 0, &key_id);
status = psa_open_key(key_id, &key_handle);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &key_handle, sizeof(key_handle));
}
return (status);
}
static psa_status_t crypto_close_key(psa_msg_t *msg)
{
psa_status_t status;
psa_key_handle_t key_handle;
read_input_param_from_message(msg, 0, &key_handle);
status = psa_close_key(key_handle);
return (status);
}
static psa_status_t crypto_destroy_key(psa_msg_t *msg)
{
psa_status_t status;
psa_key_handle_t key_handle;
read_input_param_from_message(msg, 0, &key_handle);
status = psa_destroy_key(key_handle);
return (status);
}
static psa_status_t crypto_get_key_attributes(psa_msg_t *msg)
{
psa_status_t status;
psa_key_handle_t key_handle;
psa_key_attributes_t attributes;
read_input_param_from_message(msg, 0, &key_handle);
status = psa_get_key_attributes(key_handle, &attributes);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &attributes, sizeof(attributes));
}
return (status);
}
static psa_status_t crypto_import_key(psa_msg_t *msg)
{
psa_status_t status;
psa_key_handle_t key_handle;
psa_key_attributes_t attributes;
uint8_t *key_data;
size_t key_data_size = msg->in_size[1];
read_input_param_from_message(msg, 0, &attributes);
key_data = calloc(1, key_data_size);
if (key_data == NULL) {
return (PSA_ERROR_INSUFFICIENT_MEMORY);
}
read_input_param_from_message(msg, 1, key_data);
status = psa_import_key(&attributes, key_data, key_data_size, &key_handle);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &key_handle, sizeof(key_handle));
}
free(key_data);
return (status);
}
static void message_handler(psa_msg_t *msg, SignalHandler handler)
{
psa_status_t status = 0;
switch (msg->type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
status = handler(msg);
break;
}
default: {
SPM_PANIC("Unexpected message type %d!", (int)(msg->type));
break;
}
}
psa_reply(msg->handle, status);
}
void test_partition_main(void)
{
psa_signal_t signal;
psa_msg_t msg = {0};
while (1) {
signal = psa_wait(CRYPTO_ACL_TEST_WAIT_ANY_SID_MSK, PSA_BLOCK);
if (signal & CRYPTO_GENERATE_KEY_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_GENERATE_KEY_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_generate_key);
}
if (signal & CRYPTO_OPEN_KEY_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_OPEN_KEY_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_open_key);
}
if (signal & CRYPTO_CLOSE_KEY_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_CLOSE_KEY_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_close_key);
}
if (signal & CRYPTO_DESTROY_KEY_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_DESTROY_KEY_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_destroy_key);
}
if (signal & CRYPTO_GET_KEY_ATTRIBUTES_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_GET_KEY_ATTRIBUTES_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_get_key_attributes);
}
if (signal & CRYPTO_IMPORT_KEY_MSK) {
if (PSA_SUCCESS != psa_get(CRYPTO_IMPORT_KEY_MSK, &msg)) {
continue;
}
message_handler(&msg, crypto_import_key);
}
}
}

View File

@ -1,65 +0,0 @@
{
"name": "CRYPTO_ACL_TEST",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000080",
"entry_point": "test_partition_main",
"stack_size": "0x200",
"heap_size": "0x400",
"services": [
{
"name": "CRYPTO_GENERATE_KEY",
"identifier": "0x00000201",
"signal": "CRYPTO_GENERATE_KEY_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "CRYPTO_OPEN_KEY",
"identifier": "0x00000202",
"signal": "CRYPTO_OPEN_KEY_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "CRYPTO_CLOSE_KEY",
"identifier": "0x00000203",
"signal": "CRYPTO_CLOSE_KEY_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "CRYPTO_DESTROY_KEY",
"identifier": "0x00000205",
"signal": "CRYPTO_DESTROY_KEY_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "CRYPTO_GET_KEY_ATTRIBUTES",
"identifier": "0x00000206",
"signal": "CRYPTO_GET_KEY_ATTRIBUTES_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "CRYPTO_IMPORT_KEY",
"identifier": "0x00000208",
"signal": "CRYPTO_IMPORT_KEY_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
}
],
"extern_sids": [
"PSA_KEY_MNG_ID"
],
"source_files": [
"COMPONENT_SPE/test_partition.c"
]
}

View File

@ -1,487 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMPONENT_PSA_SRV_IPC
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
#else
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "psa/client.h"
#include "psa_manifest/sid.h"
#if defined(TARGET_TFM)
#define MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS TFM_CONN_HANDLE_MAX_NUM
#define PSA_MAX_IOVEC 4
#endif
using namespace utest::v1;
#define MINOR_VER 0
#define DROP_CONN_MINOR_VER 5
#define CLIENT_RSP_BUF_SIZE 128
#define OFFSET_POS 1
#define INVALID_SID 0x00001A020
typedef struct th_struct {
psa_handle_t handle;
psa_invec *iovec_temp;
uint8_t *expected;
uint8_t expected_size;
} th_struct_t;
/* ------------------------------------- Functions ----------------------------------- */
static psa_handle_t client_ipc_tests_connect(uint32_t sid, uint32_t minor_version)
{
psa_handle_t handle = psa_connect(sid, minor_version);
TEST_ASSERT_TRUE(handle > 0);
return handle;
}
static void client_ipc_tests_call(
psa_handle_t handle,
psa_invec *iovec_temp,
size_t tx_len,
size_t rx_len,
uint8_t *expected,
uint8_t expected_size
)
{
psa_status_t status = PSA_SUCCESS;
uint8_t *response_buf = (uint8_t *)malloc(CLIENT_RSP_BUF_SIZE * sizeof(uint8_t));
memset(response_buf, 0, CLIENT_RSP_BUF_SIZE);
psa_outvec resp = {NULL, rx_len};
if (rx_len > 0) {
resp.base = response_buf;
}
status = psa_call(handle,
(tx_len ? iovec_temp : NULL),
tx_len,
(rx_len ? &resp : NULL),
(rx_len ? 1 : 0)
);
if (expected) {
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, response_buf, expected_size);
}
free(response_buf);
TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status);
}
static void client_ipc_tests_close(psa_handle_t handle)
{
psa_close(handle);
}
//Testing iovec 0 sent as NULL
void iovec_0_NULL()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
uint8_t expect_size = 5;
uint8_t off = 2;
uint8_t meta_iovec[2] = {expect_size, off};
uint8_t buff1[] = {1, 2, 3, 4, 5};
uint8_t expected_buff[] = {1, 2, 3, 4, 5};
psa_invec iovec_temp[PSA_MAX_IOVEC - 1] = {
{NULL, 0},
{meta_iovec, sizeof(meta_iovec)},
{buff1, sizeof(buff1)}
};
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
client_ipc_tests_close(handle);
}
//Testing iovec 1 sent as NULL
void iovec_1_NULL()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
uint8_t expect_size = 2;
uint8_t off = 3;
uint8_t meta_iovec[2] = {expect_size, off};
uint8_t buff1[] = {1, 2, 3, 4, 5};
uint8_t expected_buff[] = {2, 3};
psa_invec iovec_temp[PSA_MAX_IOVEC - 1] = {{meta_iovec, sizeof(meta_iovec)},
{NULL, 0},
{buff1, sizeof(buff1)}
};
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
client_ipc_tests_close(handle);
}
//Testing iovec 2 sent as NULL
void iovec_2_NULL()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
uint8_t expect_size = 2;
uint8_t off = 3;
uint8_t meta_iovec[2] = {expect_size, off};
uint8_t buff1[] = {1, 2, 3, 4, 5};
uint8_t expected_buff[] = {2, 3};
psa_invec iovec_temp[PSA_MAX_IOVEC - 1] = {{meta_iovec, sizeof(meta_iovec)},
{buff1, sizeof(buff1)},
{NULL, 0}
};
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
client_ipc_tests_close(handle);
}
// Testing in_vec[i] sent with size 0 and base not NULL
void in_vec_base_not_NULL_size_0()
{
uint8_t dummy_buff[] = {1, 2, 3, 4, 5};
psa_invec iovec_temp[1] = { {dummy_buff, 0} };
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
client_ipc_tests_call(handle, iovec_temp, 1, 0, NULL, 0);
client_ipc_tests_close(handle);
}
// Testing in_len is 0 but in_vec is not NULL
void in_len_0_in_vec_not_NULL()
{
uint8_t dummy_buff[] = {1, 2, 3, 4, 5};
psa_invec iovec_temp[1] = { {dummy_buff, sizeof(dummy_buff)} };
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
client_ipc_tests_call(handle, iovec_temp, 0, 0, NULL, 0);
client_ipc_tests_close(handle);
}
// Testing out_len is 0 but out_vec is not NULL
void out_len_0_outvec_not_NULL()
{
psa_status_t status = PSA_SUCCESS;
uint8_t dummy_res[10] = {0};
psa_outvec outvec_temp[1] = {{dummy_res, sizeof(dummy_res)}};
uint8_t dummy_buff[] = {1, 2, 3, 4, 5};
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
psa_invec in_vec_temp[2] = { {dummy_buff, sizeof(dummy_buff)},
{dummy_buff, sizeof(dummy_buff)}
};
status = psa_call(handle, in_vec_temp, 2, outvec_temp, 0);
TEST_ASSERT_EQUAL_INT32(PSA_SUCCESS, status);
client_ipc_tests_close(handle);
}
//Testing rx_buff sent as NULL and rx_len as 0
void rx_buff_null()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
uint8_t expect_size = 0, off = 2;
uint8_t meta_iovec[2] = {expect_size, off};
uint8_t buff1[] = {1, 2, 3, 4, 5}, buff2[] = {6};
psa_invec iovec_temp[PSA_MAX_IOVEC - 1] = {{meta_iovec, sizeof(meta_iovec)},
{buff1, sizeof(buff1)},
{buff2, sizeof(buff2)}
};
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, 0, NULL, 0);
client_ipc_tests_close(handle);
}
//Testing tx_buff sent as NULL and tx_len as 0
void tx_buff_null()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
client_ipc_tests_call(handle, NULL, 0, CLIENT_RSP_BUF_SIZE, NULL, 0);
client_ipc_tests_close(handle);
}
//Testing rx_buff and tx_null sent as NULL and rx_len and tx_len as 0
void rx_tx_null()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
client_ipc_tests_call(handle, NULL, 0, 0, NULL, 0);
client_ipc_tests_close(handle);
}
//Testing multiple subsequent calls to the same SID
void multiple_call()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
uint8_t expect_size = 2, off = 2;
uint8_t meta_iovec[2] = {expect_size, off};
uint8_t buff1[] = {1, 2, 3};
uint8_t buff2[] = {4, 5, 6};
uint8_t expected_buff[] = {1, 2};
psa_invec iovec_temp[PSA_MAX_IOVEC - 1] = {{meta_iovec, sizeof(meta_iovec)},
{buff1, sizeof(buff1)},
{buff2, sizeof(buff2)}
};
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
meta_iovec[1] = 3; //off
iovec_temp[0].base = meta_iovec;
expected_buff[0] = 2;
expected_buff[1] = 3;
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
meta_iovec[1] = 4; //off
iovec_temp[0].base = meta_iovec;
expected_buff[0] = 3;
expected_buff[1] = 4;
client_ipc_tests_call(handle, iovec_temp, PSA_MAX_IOVEC - 1, CLIENT_RSP_BUF_SIZE, expected_buff, sizeof(expected_buff));
client_ipc_tests_close(handle);
}
static void set_struct(th_struct_t *thr_attr, psa_handle_t handle, psa_invec *iovec_temp, uint8_t *expect, uint8_t expected_size)
{
thr_attr->handle = handle;
thr_attr->iovec_temp = iovec_temp;
thr_attr->expected = expect;
thr_attr->expected_size = expected_size;
}
static void call_diff_handle(th_struct_t *thr_attr)
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
client_ipc_tests_call(handle,
thr_attr->iovec_temp,
PSA_MAX_IOVEC - 1,
CLIENT_RSP_BUF_SIZE,
thr_attr->expected,
thr_attr->expected_size);
osDelay(10);
client_ipc_tests_close(handle);
}
//Testing multiple parallel calls to the same SID with different handles
void multi_thread_diff_handles()
{
Thread T1(osPriorityNormal, 512);
Thread T2(osPriorityNormal, 512);
Thread T3(osPriorityNormal, 512);
th_struct_t thr_attr[] = {{0}, {0}, {0}};
uint8_t meta_iovec_1[] = { 2, //expect_size
2 //off
};
uint8_t buff1[] = {1, 2, 3};
uint8_t buff2[] = {4, 5, 6};
uint8_t expected_buff_1[] = {1, 2};
psa_invec iovec_temp_1[PSA_MAX_IOVEC - 1] = {{meta_iovec_1, sizeof(meta_iovec_1)},
{buff1, sizeof(buff1)},
{buff2, sizeof(buff2)}
};
set_struct(&thr_attr[0], 0, iovec_temp_1, expected_buff_1, sizeof(expected_buff_1));
osStatus err = T1.start(callback(call_diff_handle, (th_struct_t *)&thr_attr[0]));
if (err) {
TEST_FAIL_MESSAGE("creating thread failed!");
}
uint8_t meta_iovec_2[] = { 2, //expect_size
3 //off
};
uint8_t expected_buff_2[] = {2, 3};
psa_invec iovec_temp_2[PSA_MAX_IOVEC - 1] = {{meta_iovec_2, sizeof(meta_iovec_2)},
{buff1, sizeof(buff1)},
{buff2, sizeof(buff2)}
};
set_struct(&thr_attr[1], 0, iovec_temp_2, expected_buff_2, sizeof(expected_buff_2));
err = T2.start(callback(call_diff_handle, (th_struct_t *)&thr_attr[1]));
if (err) {
TEST_FAIL_MESSAGE("creating thread failed!");
}
uint8_t meta_iovec_3[] = { 2, //expect_size
4 //off
};
uint8_t expected_buff_3[] = {3, 4};
psa_invec iovec_temp_3[PSA_MAX_IOVEC - 1] = {{meta_iovec_3, sizeof(meta_iovec_3)},
{buff1, sizeof(buff1)},
{buff2, sizeof(buff2)}
};
set_struct(&thr_attr[2], 0, iovec_temp_3, expected_buff_3, sizeof(expected_buff_3));
err = T3.start(callback(call_diff_handle, (th_struct_t *)&thr_attr[2]));
if (err) {
TEST_FAIL_MESSAGE("creating thread failed!");
}
err = T1.join();
if (err) {
TEST_FAIL_MESSAGE("joining thread failed!");
}
err = T2.join();
if (err) {
TEST_FAIL_MESSAGE("joining thread failed!");
}
err = T3.join();
if (err) {
TEST_FAIL_MESSAGE("joining thread failed!");
}
}
//Testing exceeding num of max channels allowed by psa_connect
void exceed_num_of_max_channels()
{
int i = 0;
psa_handle_t handle[MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS + 1] = {0};
for (i = 0; i < MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS + 1; i++) {
if (i != MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS) {
handle[i] = client_ipc_tests_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
} else {
handle[i] = psa_connect(CLIENT_TESTS_PART1_ROT_SRV1, MINOR_VER);
TEST_ASSERT_EQUAL_INT32(PSA_CONNECTION_REFUSED, handle[i]);
}
}
for (i = 0; i < MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS; i++) {
client_ipc_tests_close(handle[i]);
}
}
void client_close_null_handle()
{
client_ipc_tests_close(PSA_NULL_HANDLE);
}
void drop_connection()
{
psa_handle_t handle = client_ipc_tests_connect(CLIENT_TESTS_PART1_DROP_CONN, DROP_CONN_MINOR_VER);
psa_status_t status = psa_call(handle, NULL, 0, NULL, 0);
TEST_ASSERT_EQUAL_INT(PSA_DROP_CONNECTION, status);
status = PSA_SUCCESS;
status = psa_call(handle, NULL, 0, NULL, 0);
TEST_ASSERT_EQUAL_INT(PSA_DROP_CONNECTION, status);
client_ipc_tests_close(handle);
}
void verify_psa_framework_version()
{
uint32_t ff_version = psa_framework_version();
TEST_ASSERT_EQUAL_INT(PSA_FRAMEWORK_VERSION, ff_version);
}
void psa_version_existing()
{
uint32_t rot_version = psa_version(CLIENT_TESTS_PART1_DROP_CONN);
TEST_ASSERT_EQUAL_INT(DROP_CONN_MINOR_VER, rot_version);
}
void psa_version_non_existing()
{
uint32_t rot_version = psa_version(INVALID_SID);
TEST_ASSERT_EQUAL_INT(PSA_VERSION_NONE, rot_version);
}
void psa_version_secure_access_only()
{
uint32_t rot_version = psa_version(CLIENT_TESTS_PART1_SECURE_CLIENTS_ONLY);
TEST_ASSERT_EQUAL_INT(PSA_VERSION_NONE, rot_version);
}
// Test cases
Case cases[] = {
Case("Testing client iovec_0_NULL", iovec_0_NULL),
Case("Testing client iovec_1_NULL", iovec_1_NULL),
Case("Testing client iovec_2_NULL", iovec_2_NULL),
Case("Testing client in_vec 0 base not NULL size 0", in_vec_base_not_NULL_size_0),
Case("Testing client in_len 0 in_vec not NULL", in_len_0_in_vec_not_NULL),
Case("Testing client out_len is 0 but out_vec is not NULL", out_len_0_outvec_not_NULL),
Case("Testing client rx_buff_null", rx_buff_null),
Case("Testing client tx_buff_null", tx_buff_null),
Case("Testing client rx_tx_null", rx_tx_null),
Case("Testing client multiple_call from a single thread", multiple_call),
Case("Testing client close on NULL handle", client_close_null_handle),
Case("Testing DROP_CONNECTION State", drop_connection),
Case("Testing client psa_framework_version() API", verify_psa_framework_version),
Case("Testing client psa_version() API on existing SID", psa_version_existing),
Case("Testing client psa_version() API on non-existing SID", psa_version_non_existing),
Case("Testing client psa_version() API to a service that is not NSPE callable", psa_version_secure_access_only),
Case("Testing client multiple calls on different channels to the same SID", multi_thread_diff_handles),
};
utest::v1::status_t test_setup(const size_t number_of_cases)
{
// Setup Greentea using a reasonable timeout in seconds
GREENTEA_SETUP(60, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Specification specification(test_setup, cases);
int main()
{
Harness::run(specification);
return 0;
}
#endif // COMPONENT_PSA_SRV_IPC

View File

@ -1,97 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#define MSG_BUF_SIZE 128
uint8_t data[MSG_BUF_SIZE] = {0};
void client_part_main(void *ptr)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
while (1) {
signals = psa_wait(CLIENT_TESTS_PART1_WAIT_ANY_SID_MSK, PSA_BLOCK);
if (signals & PART1_ROT_SRV1_MSK) {
if (PSA_SUCCESS != psa_get(PART1_ROT_SRV1_MSK, &msg)) {
continue;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
break;
case PSA_IPC_CALL: {
memset(data, 0, sizeof(data));
if (msg.in_size[0] + msg.in_size[1] + msg.in_size[2] > 1) {
size_t offset = psa_read(msg.handle, 0, (void *)data, msg.in_size[0]);
offset += psa_read(msg.handle, 1, (void *)(data + offset), msg.in_size[1]);
psa_read(msg.handle, 2, (void *)(data + offset), msg.in_size[2]);
}
if (msg.out_size[0] > 0) {
uint8_t resp_size = data[0];
uint8_t resp_offset = data[1];
psa_write(msg.handle, 0, (const void *)(data + resp_offset), resp_size);
}
break;
}
default: {
SPM_PANIC("Invalid msg type");
}
}
psa_reply(msg.handle, PSA_SUCCESS);
} else if (signals & DROP_CONN_MSK) {
if (PSA_SUCCESS != psa_get(DROP_CONN_MSK, &msg)) {
continue;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
psa_reply(msg.handle, PSA_SUCCESS);
break;
case PSA_IPC_CALL:
psa_reply(msg.handle, PSA_DROP_CONNECTION);
break;
default:
SPM_PANIC("Invalid msg type");
}
} else if (signals & SECURE_CLIENTS_ONLY_MSK) {
if (PSA_SUCCESS != psa_get(SECURE_CLIENTS_ONLY_MSK, &msg)) {
continue;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
case PSA_IPC_CALL:
psa_reply(msg.handle, PSA_SUCCESS);
break;
default:
SPM_PANIC("Invalid msg type");
}
} else {
SPM_PANIC("Received invalid signal %lu", signals);
}
}
}

View File

@ -1,37 +0,0 @@
{
"name": "CLIENT_TESTS_PART1",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000001",
"entry_point": "client_part_main",
"stack_size": "0x400",
"heap_size": "0x400",
"services": [{
"name": "CLIENT_TESTS_PART1_ROT_SRV1",
"identifier": "0x00001A05",
"signal": "PART1_ROT_SRV1_MSK",
"non_secure_clients": true,
"minor_version": 5,
"minor_policy": "RELAXED"
},
{
"name": "CLIENT_TESTS_PART1_DROP_CONN",
"identifier": "0x00001A06",
"signal": "DROP_CONN_MSK",
"non_secure_clients": true,
"minor_version": 5,
"minor_policy": "RELAXED"
},
{
"name": "CLIENT_TESTS_PART1_SECURE_CLIENTS_ONLY",
"identifier": "0x00001A07",
"signal": "SECURE_CLIENTS_ONLY_MSK",
"non_secure_clients": false,
"minor_version": 5,
"minor_policy": "RELAXED"
}
],
"source_files": [
"COMPONENT_SPE/client_tests_partition.c"
]
}

View File

@ -1,276 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMPONENT_PSA_SRV_IPC
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
#else
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "psa/client.h"
#include "server_tests.h"
#include "psa_manifest/sid.h"
#if defined(TARGET_TFM)
#define PSA_MAX_IOVEC 4
#endif
using namespace utest::v1;
#define TEST_ROT_SRV_MINOR 12
#define OUT_BUFFER_SIZE 60
psa_handle_t control_handle = 0;
char test_str[] = "abcdefghijklmnopqrstuvwxyz";
char cross_part_buf[] = "Hello and welcome SPM";
PSA_TEST_CLIENT(identity_during_connect)
{
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
psa_close(test_handle);
}
PSA_TEST_CLIENT(identity_during_call)
{
psa_status_t status = PSA_SUCCESS;
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, NULL, 0, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(msg_size_assertion)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data[PSA_MAX_IOVEC] = {
{test_str, 4},
{test_str + 5, 6},
{test_str + 13, 1},
{NULL, 0}
};
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, data, PSA_MAX_IOVEC, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(reject_connection)
{
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT_EQUAL(PSA_CONNECTION_REFUSED, test_handle);
}
PSA_TEST_CLIENT(read_at_outofboud_offset)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data = { test_str, sizeof(test_str) };
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, &data, 1, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(msg_read_truncation)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data[3] = {
{test_str, 4},
{test_str + 5, 6},
{test_str + 13, 1}
};
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, data, 3, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(skip_zero)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data = { test_str, sizeof(test_str) };
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, &data, 1, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(skip_some)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data = { test_str, sizeof(test_str) };
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, &data, 1, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(skip_more_than_left)
{
psa_status_t status = PSA_SUCCESS;
psa_invec data = { test_str, 8 };
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
status = psa_call(test_handle, &data, 1, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
PSA_TEST_CLIENT(rhandle_factorial)
{
uint32_t secure_value = 0;
uint32_t value = 1;
psa_status_t status = PSA_SUCCESS;
psa_outvec resp = { &secure_value, sizeof(secure_value) };
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT(test_handle > 0);
for (uint32_t i = 1; i <= 5; i++) {
value *= i;
status = psa_call(test_handle, NULL, 0, &resp, 1);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(value, secure_value);
}
psa_close(test_handle);
}
PSA_TEST_CLIENT(cross_partition_call)
{
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
size_t in_len = strlen(cross_part_buf);
TEST_ASSERT_MESSAGE(test_handle > 0, "psa_connect() failed");
psa_invec iovec = { cross_part_buf, in_len };
uint8_t *response_buf = (uint8_t *)malloc(sizeof(uint8_t) * OUT_BUFFER_SIZE);
memset(response_buf, 0, OUT_BUFFER_SIZE);
psa_outvec resp = { response_buf, OUT_BUFFER_SIZE };
psa_status_t status = psa_call(test_handle, &iovec, 1, &resp, 1);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL_STRING_LEN("MPS emoclew dna olleHMPS emoclew dna olleH", response_buf, in_len * 2);
free(response_buf);
psa_close(test_handle);
}
// Test a common DOORBELL scenario
PSA_TEST_CLIENT(doorbell_test)
{
psa_handle_t test_handle = psa_connect(SERVER_TESTS_PART1_TEST, TEST_ROT_SRV_MINOR);
TEST_ASSERT_MESSAGE(test_handle > 0, "psa_connect() failed");
psa_status_t status = psa_call(test_handle, NULL, 0, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_close(test_handle);
}
utest::v1::status_t spm_setup(const size_t number_of_cases)
{
control_handle = psa_connect(SERVER_TESTS_PART1_CONTROL, 0);
if (control_handle < 0) {
error("Could not open a connection with SERVER_TESTS_PART1_CONTROL ROT_SRV");
}
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
void spm_teardown(const size_t passed, const size_t failed, const failure_t failure)
{
psa_close(control_handle);
greentea_test_teardown_handler(passed, failed, failure);
}
utest::v1::status_t spm_case_setup(const Case *const source, const size_t index_of_case)
{
psa_status_t status = PSA_SUCCESS;
test_action_t action = START_TEST;
psa_invec data = {&action, sizeof(action)};
status = psa_call(control_handle, &data, 1, NULL, 0);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t spm_case_teardown(const Case *const source, const size_t passed, const size_t failed, const failure_t reason)
{
psa_status_t status = PSA_SUCCESS;
psa_status_t test_status = PSA_SUCCESS;
test_action_t action = GET_TEST_RESULT;
psa_invec data = {&action, sizeof(action)};
psa_outvec resp = {&test_status, sizeof(test_status)};
status = psa_call(control_handle, &data, 1, &resp, 1);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(PSA_SUCCESS, test_status);
return greentea_case_teardown_handler(source, passed, failed, reason);
}
#define SPM_UTEST_CASE(desc, test) Case(desc, spm_case_setup, PSA_TEST_CLIENT_NAME(test), spm_case_teardown)
Case cases[] = {
SPM_UTEST_CASE("Get identity during connect", identity_during_connect),
SPM_UTEST_CASE("Get identity during call", identity_during_call),
SPM_UTEST_CASE("Assert msg size", msg_size_assertion),
SPM_UTEST_CASE("Reject on connect", reject_connection),
SPM_UTEST_CASE("Read at an out of bound offset", read_at_outofboud_offset),
SPM_UTEST_CASE("Read msg with size bigger than message", msg_read_truncation),
SPM_UTEST_CASE("Make sure skip with 0 byte number skips nothing", skip_zero),
SPM_UTEST_CASE("Skip a few bytes while reading a message", skip_some),
SPM_UTEST_CASE("Try to skip more bytes than left while reading", skip_more_than_left),
SPM_UTEST_CASE("Test rhandle implementation by calculating the factorial function", rhandle_factorial),
SPM_UTEST_CASE("Test a call flow between 2 secure partitions", cross_partition_call),
};
//Declare your test specification with a custom setup handler
Specification specification(spm_setup, cases, spm_teardown);
int main(int, char **)
{
Harness::run(specification);
return 0;
}
#endif // COMPONENT_PSA_SRV_IPC

View File

@ -1,57 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SERVER_TESTS_H__
#define __SERVER_TESTS_H__
typedef enum {
START_TEST = 1,
GET_TEST_RESULT = 2
} test_action_t;
typedef struct factorial_data {
uint32_t count;
uint32_t val;
} factorial_data_t;
typedef psa_status_t (*psa_test_server_side_func)(psa_status_t *);
#define PSA_TEST_ERROR (-1L)
#define PSA_TEST_CLIENT_NAME(name) psa_test_client_side_ ## name
#define PSA_TEST_SERVER_NAME(name) psa_test_server_side_ ## name
#define PSA_TEST_CLIENT(name) void PSA_TEST_CLIENT_NAME(name) (void)
#define PSA_TEST_SERVER(name) psa_status_t PSA_TEST_SERVER_NAME(name) (psa_status_t *status_ptr)
#define PSA_TEST(name) \
PSA_TEST_CLIENT(name); \
PSA_TEST_SERVER(name); \
PSA_TEST(identity_during_connect)
PSA_TEST(identity_during_call)
PSA_TEST(get_msg_twice)
PSA_TEST(msg_size_assertion)
PSA_TEST(reject_connection)
PSA_TEST(read_at_outofboud_offset)
PSA_TEST(msg_read_truncation)
PSA_TEST(skip_zero)
PSA_TEST(skip_some)
PSA_TEST(skip_more_than_left)
PSA_TEST(rhandle_factorial)
PSA_TEST(cross_partition_call)
PSA_TEST(doorbell_test)
#endif /* __SERVER_TESTS_H__ */

View File

@ -1,93 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "string.h"
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#include "server_tests.h"
extern psa_test_server_side_func test_list[];
static size_t num_of_tests = 0;
static void init_num_of_tests()
{
size_t i = 0;
while (test_list[i] != NULL) {
i++;
}
num_of_tests = i;
}
void server_part1_main(void *ptr)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
psa_status_t test_status = PSA_SUCCESS; // status of the api calls during the test
psa_status_t test_result = PSA_SUCCESS; // result of the critical section of the test
test_action_t action;
uint32_t test_idx = 0;
init_num_of_tests();
while (1) {
signals = psa_wait(CONTROL_MSK, PSA_BLOCK);
if (0 == (signals & CONTROL_MSK)) {
SPM_PANIC("returned from psa_wait without CONTROL_ROT_SRV bit on signals=(0x%08x)\n", signals);
}
if (PSA_SUCCESS != psa_get(CONTROL_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
switch (msg.type) {
case PSA_IPC_CALL:
if (msg.in_size[0] == 0) {
SPM_PANIC("got a zero message size to SERVER_TESTS_PART1_CONTROL ROT_SRV\n");
}
if (psa_read(msg.handle, 0, &action, sizeof(action)) != sizeof(action)) {
SPM_PANIC("could not read the entire test payload structure\n");
}
switch (action) {
case START_TEST:
if ((test_idx >= num_of_tests) || (test_list[test_idx] == NULL)) {
SPM_PANIC("Invalid test ID was sent!\n");
}
psa_reply(msg.handle, PSA_SUCCESS);
test_status = test_list[test_idx](&test_result);
break;
case GET_TEST_RESULT:
test_idx++;
psa_write(msg.handle, 0, &test_result, sizeof(test_result));
psa_reply(msg.handle, test_status);
break;
default:
SPM_PANIC("Got illegal Value in test action");
}
break;
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
psa_reply(msg.handle, PSA_SUCCESS);
break;
default:
SPM_PANIC("Unexpected message type %lu!", msg.type);
}
}
}

View File

@ -1,101 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
void server_part2_main(void *ptr)
{
psa_signal_t signals = 0;
size_t len = 0;
char *str = NULL;
psa_msg_t msg = {0};
while (1) {
signals = psa_wait(SERVER_TESTS_PART2_WAIT_ANY_SID_MSK, PSA_BLOCK);
if (0 == (signals & SERVER_TESTS_PART2_WAIT_ANY_SID_MSK)) {
SPM_PANIC("returned from psa_wait without ROT_SRV_REVERSE_MSK or ROT_SRV_DB_TST_MSK bit on\n");
}
if (signals & ROT_SRV_REVERSE_MSK) {
if (PSA_SUCCESS != psa_get(ROT_SRV_REVERSE_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
switch (msg.type) {
case PSA_IPC_CALL: {
if ((msg.in_size[0] + msg.in_size[1] + msg.in_size[2]) == 0) {
SPM_PANIC("got a zero message size to REVERSE ROT_SRV\n");
}
len = msg.in_size[0];
str = (char *)malloc(sizeof(char) * len);
if (NULL == str) {
SPM_PANIC("memory allocation failure\n");
}
psa_read(msg.handle, 0, str, len);
for (size_t i = 0; i < len / 2; i ++) {
char a = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = a;
}
psa_write(msg.handle, 0, str, len);
free(str);
str = NULL;
break;
}
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
break;
default:
SPM_PANIC("Unexpected message type %lu!", msg.type);
break;
}
psa_reply(msg.handle, PSA_SUCCESS);
} else { // -- Doorbell test
if (PSA_SUCCESS != psa_get(ROT_SRV_DB_TST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
switch (msg.type) {
case PSA_IPC_CALL: {
int32_t caller_part_id = msg.client_id;
// Doorbell contract is valid only between secure partitions
if (caller_part_id < 0) {
SPM_PANIC("Caller partition is non secure\n");
}
// In doorbell scenario the server first calls psa_reply()
psa_reply(msg.handle, PSA_SUCCESS);
// After work is done, ring the doorbell
psa_notify(caller_part_id);
break;
}
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT:
psa_reply(msg.handle, PSA_SUCCESS);
break;
default:
SPM_PANIC("Unexpected message type %lu!", msg.type);
break;
}
}
}
}

View File

@ -1,702 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "string.h"
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#include "server_tests.h"
#include "psa_manifest/sid.h"
/**
* Process a generic connect message to SERVER_TESTS_PART1_TEST ROT_SRV.
* @return PSA_SUCCESS or negative error code if failed.
*/
static psa_status_t process_connect_request(void)
{
psa_status_t res = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
res = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CONNECT) {
res = ((res != PSA_SUCCESS) ? res : PSA_TEST_ERROR);
}
psa_reply(msg.handle, res);
return res;
}
/**
* Process a generic disconnect message to SERVER_TESTS_PART1_TEST ROT_SRV.
* @return PSA_SUCCESS or negative error code if failed.
*/
static psa_status_t process_disconnect_request(void)
{
psa_status_t res = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
res = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_DISCONNECT) {
res = ((res != PSA_SUCCESS) ? res : PSA_TEST_ERROR);
}
psa_reply(msg.handle, PSA_SUCCESS);
return res;
}
PSA_TEST_SERVER(identity_during_connect)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
int32_t identity = 0;
psa_signal_t signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CONNECT) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
identity = msg.client_id;
*status_ptr = (identity == -1) ? PSA_SUCCESS : PSA_TEST_ERROR;
psa_reply(msg.handle, PSA_SUCCESS);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(identity_during_call)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
int32_t identity = 0;
psa_signal_t signals = 0;
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
identity = msg.client_id;
*status_ptr = (identity == -1) ? PSA_SUCCESS : PSA_TEST_ERROR;
psa_reply(msg.handle, PSA_SUCCESS);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(msg_size_assertion)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = 0;
size_t read_size = 0;
char *buff = malloc(sizeof(char) * 11);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
memset(buff, 0, 11);
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
for (size_t i = 0; i < PSA_MAX_IOVEC; i++) {
read_size += psa_read(msg.handle, i, buff + read_size, msg.in_size[i]);
}
if (((msg.in_size[0] + msg.in_size[1] + msg.in_size[2] + msg.in_size[3]) != 11) ||
(read_size != 11) ||
(strncmp(buff, "abcdfghijkn", 11) != 0)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
free(buff);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(reject_connection)
{
psa_status_t res = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
res = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CONNECT) {
res = ((res != PSA_SUCCESS) ? res : PSA_TEST_ERROR);
}
psa_reply(msg.handle, PSA_CONNECTION_REFUSED);
*status_ptr = res;
return res;
}
PSA_TEST_SERVER(read_at_outofboud_offset)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
uint32_t buff = 52;
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
size_t read_size = psa_read(msg.handle, 1, &buff, sizeof(buff));
if ((0 != read_size) || (52 != buff)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(msg_read_truncation)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = 0;
size_t read_size = 0;
char *buff = malloc(sizeof(char) * 11);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
memset(buff, 0, 11);
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
read_size = psa_read(msg.handle, 1, buff, 11);
if ((msg.in_size[1] != read_size) ||
((msg.in_size[0] + msg.in_size[1] + msg.in_size[2]) != 11) ||
(buff[6] != 0) ||
(strncmp(buff, "fghijk", 6) != 0)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
disconnect_status = process_disconnect_request();
free(buff);
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(skip_zero)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = 0;
size_t read_size = 0;
size_t skip_size = 0;
char *buff = malloc(sizeof(char) * 11);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
skip_size = psa_skip(msg.handle, 0, 0);
read_size = psa_read(msg.handle, 0, buff, 11);
if ((skip_size != 0) ||
(read_size != 11) ||
(strncmp(buff, "abcdefghijk", 11)) != 0) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
disconnect_status = process_disconnect_request();
free(buff);
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(skip_some)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = 0;
size_t read_size1 = 0;
size_t read_size2 = 0;
size_t skip_size = 0;
char *buff = malloc(sizeof(char) * 11);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
read_size1 = psa_read(msg.handle, 0, buff, 3);
skip_size = psa_skip(msg.handle, 0, 5);
read_size2 = psa_read(msg.handle, 0, buff + 3, 8);
if ((read_size1 != 3) ||
(skip_size != 5) ||
(read_size2 != 8) ||
(strncmp(buff, "abcijklmnop", 11) != 0)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
disconnect_status = process_disconnect_request();
free(buff);
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(skip_more_than_left)
{
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_msg_t msg = {0};
psa_signal_t signals = 0;
size_t read_size1 = 0;
size_t read_size2 = 0;
size_t skip_size = 0;
char *buff = malloc(sizeof(char) * 8);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (msg.type != PSA_IPC_CALL) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
read_size1 = psa_read(msg.handle, 0, buff, 5);
skip_size = psa_skip(msg.handle, 0, 4);
read_size2 = psa_read(msg.handle, 0, buff + 5, 2);
if ((read_size1 != 5) ||
(skip_size != 3) ||
(read_size2 != 0) ||
(strncmp(buff, "abcde", 5) != 0)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
psa_reply(msg.handle, test_status);
disconnect_status = process_disconnect_request();
free(buff);
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
PSA_TEST_SERVER(rhandle_factorial)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
factorial_data_t *num = NULL;
factorial_data_t *asserted_ptr = NULL;
uint32_t connect_count = 0;
uint32_t call_count = 0;
uint32_t disconnect_count = 0;
while (1) {
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if (0 == (signals & TEST_MSK)) {
SPM_PANIC("returned from psa_wait without TEST_MSK bit on\n");
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
switch (msg.type) {
case PSA_IPC_CONNECT:
if (NULL != msg.rhandle) {
SPM_PANIC("got rhandle on connect message\n");
}
num = (factorial_data_t *)malloc(sizeof(factorial_data_t));
if (NULL == num) {
SPM_PANIC("memory allocation failure\n");
}
num->count = 0;
num->val = 1;
psa_set_rhandle(msg.handle, num);
asserted_ptr = num;
connect_count++;
break;
case PSA_IPC_CALL:
if (msg.in_size[0] + msg.in_size[1] + msg.in_size[2] > 0) {
SPM_PANIC("ROT_SRV_FACTORIAL ROT_SRV should not get any params\n");
}
if (NULL == msg.rhandle) {
SPM_PANIC("got NULL rhandle on call message\n");
}
if (asserted_ptr != msg.rhandle) {
SPM_PANIC("rhandle value changed between calls\n");
}
num = (factorial_data_t *)msg.rhandle;
num->count++;
num->val *= num->count;
psa_write(msg.handle, 0, &(num->val), sizeof(num->val));
call_count++;
break;
case PSA_IPC_DISCONNECT:
if (NULL == msg.rhandle) {
SPM_PANIC("got NULL rhandle on disconnect message\n");
}
if (asserted_ptr != msg.rhandle) {
SPM_PANIC("rhandle value changed between calls\n");
}
// Setting rhandle during disconnection should have no effect
uint8_t my_rhandle = 10;
psa_set_rhandle(msg.handle, &my_rhandle);
free(msg.rhandle);
disconnect_count++;
break;
default:
SPM_PANIC("Unexpected message type %lu!", msg.type);
}
num = NULL;
psa_reply(msg.handle, PSA_SUCCESS);
if (disconnect_count > 0) {
break;
}
}
if ((connect_count != 1) ||
(call_count != 5) ||
(disconnect_count != 1)) {
*status_ptr = PSA_TEST_ERROR;
} else {
*status_ptr = PSA_SUCCESS;
}
return *status_ptr;
}
PSA_TEST_SERVER(cross_partition_call)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_status_t partition_call_status = PSA_SUCCESS;
uint32_t data_read = 0;
uint32_t str_len = 0;
char *buff = malloc(sizeof(char) * 60);
if (NULL == buff) {
SPM_PANIC("memory allocation failure\n");
}
memset(buff, 0, 60);
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
free(buff);
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if ((msg.in_size[0] + msg.in_size[1] + msg.in_size[2]) == 0) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
str_len = msg.in_size[0];
data_read = psa_read(msg.handle, 0, buff, str_len);
if (data_read != 21) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
memcpy(buff + str_len, buff, str_len);
data_read *= 2;
psa_invec data = { buff, data_read };
psa_outvec resp = { buff, data_read };
psa_handle_t conn_handle = psa_connect(SERVER_TESTS_PART2_ROT_SRV_REVERSE, 5);
if (conn_handle <= 0) {
partition_call_status = PSA_TEST_ERROR;
}
if (partition_call_status == PSA_SUCCESS) {
partition_call_status = psa_call(conn_handle, &data, 1, &resp, 1);
}
*status_ptr = partition_call_status;
if (partition_call_status == PSA_SUCCESS) {
psa_close(conn_handle);
}
if (PSA_SUCCESS == partition_call_status) {
psa_write(msg.handle, 0, buff, data_read);
}
psa_reply(msg.handle, partition_call_status);
free(buff);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
// Test a common DOORBELL scenario
PSA_TEST_SERVER(doorbell_test)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
psa_status_t test_status = PSA_SUCCESS;
psa_status_t disconnect_status = PSA_SUCCESS;
psa_status_t partition_call_status = PSA_SUCCESS;
test_status = process_connect_request();
if (test_status != PSA_SUCCESS) {
return test_status;
}
signals = psa_wait(TEST_MSK, PSA_BLOCK);
if ((signals & TEST_MSK) == 0) {
test_status = PSA_TEST_ERROR;
}
if (PSA_SUCCESS != psa_get(TEST_MSK, &msg)) {
SPM_PANIC("psa_get() failed\n");
}
if (((msg.in_size[0] + msg.in_size[1] + msg.in_size[2]) != 0) || (msg.out_size[0] != 0)) {
test_status = ((test_status != PSA_SUCCESS) ? test_status : PSA_TEST_ERROR);
}
// -- Connection with partition2 - START
psa_handle_t conn_handle = psa_connect(SERVER_TESTS_PART2_ROT_SRV_DB_TST, 5);
if (conn_handle <= 0) {
partition_call_status = PSA_TEST_ERROR;
}
if (partition_call_status == PSA_SUCCESS) {
partition_call_status = psa_call(conn_handle, NULL, 0, NULL, 0);
}
if (partition_call_status == PSA_SUCCESS) {
// Wait for doorball notification - Only after that call psa_reply() for the client called you
signals = psa_wait(PSA_DOORBELL, PSA_BLOCK);
if ((signals & PSA_DOORBELL) == 0) {
partition_call_status = PSA_TEST_ERROR;
}
}
if (partition_call_status == PSA_SUCCESS) {
psa_clear();
psa_close(conn_handle);
}
// -- Connection with partition2 - END
*status_ptr = partition_call_status;
psa_reply(msg.handle, partition_call_status);
disconnect_status = process_disconnect_request();
test_status = (test_status != PSA_SUCCESS) ? test_status : disconnect_status;
return test_status;
}
psa_test_server_side_func test_list[] = {
PSA_TEST_SERVER_NAME(identity_during_connect),
PSA_TEST_SERVER_NAME(identity_during_call),
PSA_TEST_SERVER_NAME(msg_size_assertion),
PSA_TEST_SERVER_NAME(reject_connection),
PSA_TEST_SERVER_NAME(read_at_outofboud_offset),
PSA_TEST_SERVER_NAME(msg_read_truncation),
PSA_TEST_SERVER_NAME(skip_zero),
PSA_TEST_SERVER_NAME(skip_some),
PSA_TEST_SERVER_NAME(skip_more_than_left),
PSA_TEST_SERVER_NAME(rhandle_factorial),
PSA_TEST_SERVER_NAME(cross_partition_call),
NULL
};

View File

@ -1,57 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __UVISOR_MBED_SPM_SERVER_TESTS_H__
#define __UVISOR_MBED_SPM_SERVER_TESTS_H__
typedef enum {
START_TEST = 1,
GET_TEST_RESULT = 2
} test_action_t;
typedef struct factorial_data {
uint32_t count;
uint32_t val;
} factorial_data_t;
typedef psa_status_t (*psa_test_server_side_func)(psa_status_t *);
#define PSA_TEST_ERROR (-1L)
#define PSA_TEST_CLIENT_NAME(name) psa_test_client_side_ ## name
#define PSA_TEST_SERVER_NAME(name) psa_test_server_side_ ## name
#define PSA_TEST_CLIENT(name) void PSA_TEST_CLIENT_NAME(name) (void)
#define PSA_TEST_SERVER(name) psa_status_t PSA_TEST_SERVER_NAME(name) (psa_status_t *status_ptr)
#define PSA_TEST(name) \
PSA_TEST_CLIENT(name); \
PSA_TEST_SERVER(name); \
PSA_TEST(identity_during_connect)
PSA_TEST(identity_during_call)
PSA_TEST(get_msg_twice)
PSA_TEST(msg_size_assertion)
PSA_TEST(reject_connection)
PSA_TEST(read_at_outofboud_offset)
PSA_TEST(msg_read_truncation)
PSA_TEST(skip_zero)
PSA_TEST(skip_some)
PSA_TEST(skip_more_than_left)
PSA_TEST(rhandle_factorial)
PSA_TEST(cross_partition_call)
PSA_TEST(doorbell_test)
#endif /* __UVISOR_MBED_SPM_SERVER_TESTS_H__ */

View File

@ -1,34 +0,0 @@
{
"name": "SERVER_TESTS_PART1",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000002",
"entry_point": "server_part1_main",
"stack_size": "0x400",
"heap_size": "0x400",
"services": [{
"name": "SERVER_TESTS_PART1_CONTROL",
"identifier": "0x00001A01",
"signal": "CONTROL_MSK",
"non_secure_clients": true,
"minor_version": 5,
"minor_policy": "RELAXED"
},
{
"name": "SERVER_TESTS_PART1_TEST",
"identifier": "0x00001A02",
"signal": "TEST_MSK",
"non_secure_clients": true,
"minor_version": 12,
"minor_policy": "STRICT"
}
],
"extern_sids": [
"SERVER_TESTS_PART2_ROT_SRV_REVERSE",
"SERVER_TESTS_PART2_ROT_SRV_DB_TST"
],
"source_files": [
"COMPONENT_SPE/server_tests_partition1.c",
"COMPONENT_SPE/tests.c"
]
}

View File

@ -1,30 +0,0 @@
{
"name": "SERVER_TESTS_PART2",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000003",
"entry_point": "server_part2_main",
"stack_size": "0x400",
"heap_size": "0x400",
"services": [{
"name": "SERVER_TESTS_PART2_ROT_SRV_REVERSE",
"identifier": "0x00001A03",
"signal": "ROT_SRV_REVERSE_MSK",
"non_secure_clients": false,
"minor_version": 5,
"minor_policy": "STRICT"
},
{
"name": "SERVER_TESTS_PART2_ROT_SRV_DB_TST",
"identifier": "0x00001A04",
"signal": "ROT_SRV_DB_TST_MSK",
"non_secure_clients": false,
"minor_version": 5,
"minor_policy": "STRICT"
}
],
"source_files": [
"COMPONENT_SPE/server_tests_partition2.c",
"COMPONENT_SPE/tests.c"
]
}

View File

@ -1,96 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMPONENT_PSA_SRV_IPC
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
#else
/* -------------------------------------- Includes ----------------------------------- */
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "psa/client.h"
#include "psa_manifest/sid.h"
#include <string.h>
#if defined(TARGET_TFM)
#define PSA_MAX_IOVEC 4
#endif
using namespace utest::v1;
/* ------------------------------------ Definitions ---------------------------------- */
#define CLIENT_MINOR_VERSION 0
#define CLIENT_RSP_BUF_SIZE 20
#define CLIENT_TX_MSG "Hello and welcome SPM"
#define CLIENT_EXPECTED_RESPONSE "Response1"
/* ------------------------------------ Client Code ---------------------------------- */
char msg_buf[] = CLIENT_TX_MSG;
void example_main(void)
{
psa_handle_t conn_handle = psa_connect(SMOKE_TESTS_PART1_ROT_SRV1, CLIENT_MINOR_VERSION);
TEST_ASSERT_MESSAGE(conn_handle > 0, "psa_connect() failed");
psa_invec iovec[PSA_MAX_IOVEC - 1] = {
{ msg_buf, 6 },
{ msg_buf + 6, 12 },
{ msg_buf + 18, 4 }
};
uint8_t *response_buf = (uint8_t *)malloc(sizeof(uint8_t) * CLIENT_RSP_BUF_SIZE);
memset(response_buf, 0, CLIENT_RSP_BUF_SIZE);
psa_outvec outvec = {response_buf, CLIENT_RSP_BUF_SIZE};
psa_status_t status = psa_call(conn_handle, iovec, PSA_MAX_IOVEC - 1, &outvec, 1);
TEST_ASSERT_MESSAGE(PSA_SUCCESS == status, "psa_call() failed");
TEST_ASSERT_EQUAL_STRING(CLIENT_EXPECTED_RESPONSE, response_buf);
free(response_buf);
psa_close(conn_handle);
}
// --------------------------------- Test Framework ---------------------------------- */
utest::v1::status_t greentea_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("example", example_main)
};
// Declare your test specification with a custom setup handler
Specification specification(greentea_setup, cases);
int main(int, char **)
{
// Run the test specification
Harness::run(specification);
return 0;
}
#endif // COMPONENT_PSA_SRV_IPC

View File

@ -1,122 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// -------------------------------------- Includes -----------------------------------
#include <string.h>
#include <stdlib.h>
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
// ------------------------------------ Definitions ----------------------------------
#define SERVER_READ_MSG_BUF_SIZE 30
#define SERVER_RSP_BUF_SIZE 20
#define ACTUAL_MSG_SIZE 22
// ---------------------------------- Global Variables -------------------------------
const char SERVER_EXPECTED_READ_MSG[] = "Hello and welcome SPM";
const char WRITE_MSG_BUF[] = "Response1";
// ------------------------------ Partition's Main Thread ----------------------------
void smoke_part_main(void *ptr)
{
uint32_t signals = 0;
int32_t client_id = 0;
psa_msg_t msg = {0};
while (1) {
signals = psa_wait(ROT_SRV1_MSK, PSA_BLOCK);
if ((signals & ROT_SRV1_MSK) != ROT_SRV1_MSK) {
SPM_PANIC("Received unknown signal (0x%08lx)\n", signals);
}
if (PSA_SUCCESS != psa_get(ROT_SRV1_MSK, &msg)) {
continue;
}
if (msg.handle != PSA_NULL_HANDLE) {
client_id = msg.client_id;
if (client_id != -1) {
SPM_PANIC("Received message from unexpected source (0x%08lx)\n", client_id);
}
}
switch (msg.type) {
case PSA_IPC_CALL: {
if (
((msg.in_size[0] + msg.in_size[1] + msg.in_size[2] + msg.in_size[3]) != ACTUAL_MSG_SIZE) ||
(msg.out_size[0] != SERVER_RSP_BUF_SIZE)
) {
SPM_PANIC("Received message does not comply with message convention");
}
char *read_msg_buf = malloc(sizeof(char) * SERVER_READ_MSG_BUF_SIZE);
if (NULL == read_msg_buf) {
SPM_PANIC("Failed to allocate Memory");
}
memset(read_msg_buf, 0, SERVER_READ_MSG_BUF_SIZE);
char *read_ptr = read_msg_buf;
for (size_t i = 0; i < PSA_MAX_IOVEC - 1; i++) {
uint32_t bytes_read = psa_read(msg.handle, i, read_ptr, msg.in_size[i]);
if (bytes_read != msg.in_size[i]) {
SPM_PANIC("Expected to read %zu, got %lu", msg.in_size[i], bytes_read);
}
read_ptr += bytes_read;
}
int cmp_res = strcmp(SERVER_EXPECTED_READ_MSG, read_msg_buf);
if (cmp_res != 0) {
SPM_PANIC("psa_read() - Bad reading!!");
}
psa_write(msg.handle, 0, WRITE_MSG_BUF, strlen(WRITE_MSG_BUF) + 1);
free(read_msg_buf);
read_msg_buf = NULL;
read_ptr = NULL;
break;
}
case PSA_IPC_DISCONNECT:
// Fallthrough
case PSA_IPC_CONNECT: {
if (
(msg.out_size[0] != 0) || (msg.out_size[1] != 0) ||
(msg.out_size[2] != 0) || (msg.out_size[3] != 0) ||
(msg.in_size[0] != 0) || (msg.in_size[1] != 0) ||
(msg.in_size[2] != 0) || (msg.in_size[3] != 0)
) {
SPM_PANIC("Should not receive iovecs in PSA_IPC_CONNECT or PSA_IPC_DISCONNECT");
}
break;
}
default:
SPM_PANIC("Unexpected message type %lu!", msg.type);
break;
}
psa_reply(msg.handle, PSA_SUCCESS);
}
}

View File

@ -1,21 +0,0 @@
{
"name": "SMOKE_TESTS_PART1",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000004",
"entry_point": "smoke_part_main",
"stack_size": "0x200",
"heap_size": "0x400",
"services": [{
"name": "SMOKE_TESTS_PART1_ROT_SRV1",
"identifier": "0x00001A00",
"signal": "ROT_SRV1_MSK",
"non_secure_clients": true,
"minor_version": 5,
"minor_policy": "RELAXED"
}
],
"source_files": [
"COMPONENT_SPE/smoke_tests_partition.c"
]
}

View File

@ -1,217 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_BOOT_STATUS_H__
#define __TFM_BOOT_STATUS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Major numbers (4 bit) to identify
* the consumer of shared data in runtime SW
*/
#define TLV_MAJOR_CORE 0x0
#define TLV_MAJOR_IAS 0x1
/**
* The shared data between boot loader and runtime SW is TLV encoded. The
* shared data is stored in a well known location in secure memory and this is
* a contract between boot loader and runtime SW.
*
* The structure of shared data must be the following:
* - At the beginning there must be a header: struct shared_data_tlv_header
* This contains a magic number and a size field which covers the entire
* size of the shared data area including this header.
* - After the header there come the entries which are composed from an entry
* header structure: struct shared_data_tlv_entry and the data. In the entry
* header is a type field (tly_type) which identify the consumer of the
* entry in the runtime SW and specify the subtype of that data item. There
* is a size field (tlv_len) which covers the size of the entry header and
* the data. After this structure comes the actual data.
* - Arbitrary number and size of data entry can be in the shared memory area.
*
* This table gives of overview about the tlv_type field in the entry header.
* The tlv_type always composed from a major and minor number. Major number
* identifies the addressee in runtime SW, who should process the data entry.
* Minor number used to encode more info about the data entry. The actual
* definition of minor number could change per major number. In case of boot
* status data, which is going to be processed by initial attestation service
* the minor number is split further to two part: sw_module and claim. The
* sw_module identifies the SW component in the system which the data item
* belongs to and the claim part identifies the exact type of the data.
*
* |---------------------------------------|
* | tlv_type (16) |
* |---------------------------------------|
* | tlv_major(4)| tlv_minor(12) |
* |---------------------------------------|
* | MAJOR_IAS | sw_module(6) | claim(6) |
* |---------------------------------------|
* | MAJOR_CORE | TBD |
* |---------------------------------------|
*/
/* Initial attestation: SW components / SW modules
* This list is intended to be adjusted per device. It contains more SW
* components than currently available in TF-M project. It serves as an example,
* what kind of SW components might be available.
*/
#define SW_GENERAL 0x00
#define SW_BL2 0x01
#define SW_PROT 0x02
#define SW_AROT 0x03
#define SW_SPE 0x04
#define SW_NSPE 0x05
#define SW_S_NS 0x06
#define SW_MAX 0x07
/* Initial attestation: Claim per SW components / SW modules */
/* Bits: 0-2 */
#define SW_VERSION 0x00
#define SW_SIGNER_ID 0x01
#define SW_EPOCH 0x02
#define SW_TYPE 0x03
/* Bits: 3-5 */
#define SW_MEASURE_VALUE 0x08
#define SW_MEASURE_TYPE 0x09
/* Initial attestation: General claim does not belong any particular SW
* component. But they might be part of the boot status.
*/
#define BOOT_SEED 0x00
#define HW_VERSION 0x01
#define SECURITY_LIFECYCLE 0x02
/* Minor numbers (12 bit) to identify attestation service related data */
#define TLV_MINOR_IAS_BOOT_SEED ((SW_GENERAL << 6) | BOOT_SEED)
#define TLV_MINOR_IAS_HW_VERSION ((SW_GENERAL << 6) | HW_VERSION)
#define TLV_MINOR_IAS_SLC ((SW_GENERAL << 6) | SECURITY_LIFECYCLE)
/* Bootloader - It can be more stage */
#define TLV_MINOR_IAS_BL2_MEASURE_VALUE ((SW_BL2 << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_BL2_MEASURE_TYPE ((SW_BL2 << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_BL2_VERSION ((SW_BL2 << 6) | SW_VERSION)
#define TLV_MINOR_IAS_BL2_SIGNER_ID ((SW_BL2 << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_BL2_EPOCH ((SW_BL2 << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_BL2_TYPE ((SW_BL2 << 6) | SW_TYPE)
/* PROT: PSA Root of Trust */
#define TLV_MINOR_IAS_PROT_MEASURE_VALUE ((SW_PROT << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_PROT_MEASURE_TYPE ((SW_PROT << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_PROT_VERSION ((SW_PROT << 6) | SW_VERSION)
#define TLV_MINOR_IAS_PROT_SIGNER_ID ((SW_PROT << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_PROT_EPOCH ((SW_PROT << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_PROT_TYPE ((SW_PROT << 6) | SW_TYPE)
/* AROT: Application Root of Trust */
#define TLV_MINOR_IAS_AROT_MEASURE_VALUE ((SW_AROT << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_AROT_MEASURE_TYPE ((SW_AROT << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_AROT_VERSION ((SW_AROT << 6) | SW_VERSION)
#define TLV_MINOR_IAS_AROT_SIGNER_ID ((SW_AROT << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_AROT_EPOCH ((SW_AROT << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_AROT_TYPE ((SW_AROT << 6) | SW_TYPE)
/* Non-secure processing environment - single non-secure image */
#define TLV_MINOR_IAS_NSPE_MEASURE_VALUE ((SW_NSPE << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_NSPE_MEASURE_TYPE ((SW_NSPE << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_NSPE_VERSION ((SW_NSPE << 6) | SW_VERSION)
#define TLV_MINOR_IAS_NSPE_SIGNER_ID ((SW_NSPE << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_NSPE_EPOCH ((SW_NSPE << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_NSPE_TYPE ((SW_NSPE << 6) | SW_TYPE)
/* Secure processing environment (ARoT + PRoT) - single secure image */
#define TLV_MINOR_IAS_SPE_MEASURE_VALUE ((SW_SPE << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_SPE_MEASURE_TYPE ((SW_SPE << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_SPE_VERSION ((SW_SPE << 6) | SW_VERSION)
#define TLV_MINOR_IAS_SPE_SIGNER_ID ((SW_SPE << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_SPE_EPOCH ((SW_SPE << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_SPE_TYPE ((SW_SPE << 6) | SW_TYPE)
/* SPE + NSPE - combined secure and non-secure image */
#define TLV_MINOR_IAS_S_NS_MEASURE_VALUE ((SW_S_NS << 6) | SW_MEASURE_VALUE)
#define TLV_MINOR_IAS_S_NS_MEASURE_TYPE ((SW_S_NS << 6) | SW_MEASURE_TYPE)
#define TLV_MINOR_IAS_S_NS_VERSION ((SW_S_NS << 6) | SW_VERSION)
#define TLV_MINOR_IAS_S_NS_SIGNER_ID ((SW_S_NS << 6) | SW_SIGNER_ID)
#define TLV_MINOR_IAS_S_NS_EPOCH ((SW_S_NS << 6) | SW_EPOCH)
#define TLV_MINOR_IAS_S_NS_TYPE ((SW_S_NS << 6) | SW_TYPE)
/* General macros to handle TLV type */
#define MAJOR_MASK 0xF /* 4 bit */
#define MAJOR_POS 12 /* 12 bit */
#define MINOR_MASK 0xFFF /* 12 bit */
#define SET_TLV_TYPE(major, minor) \
((((major) & MAJOR_MASK) << MAJOR_POS) | ((minor) & MINOR_MASK))
#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS)
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
/* Initial attestation specific macros */
#define MODULE_POS 6 /* 6 bit */
#define CLAIM_MASK 0x3F /* 6 bit */
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS)
#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim))
#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \
MEASUREMENT_CLAIM_POS)
/* Magic value which marks the beginning of shared data area in memory */
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
/**
* Shared data TLV header. All fields in little endian.
*
* -----------------------------------
* | tlv_magic(16) | tlv_tot_len(16) |
* -----------------------------------
*/
struct shared_data_tlv_header {
uint16_t tlv_magic;
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
};
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
/**
* Shared data TLV entry header format. All fields in little endian.
*
* -------------------------------
* | tlv_type(16) | tlv_len(16) |
* -------------------------------
* | Raw data |
* -------------------------------
*/
struct shared_data_tlv_entry {
uint16_t tlv_type;
uint16_t tlv_len; /* size of single TLV entry (including this header). */
};
/**
* \struct tfm_boot_data
*
* \brief Store the data for the runtime SW
*/
struct tfm_boot_data {
struct shared_data_tlv_header header;
uint8_t data[];
};
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
#ifdef __cplusplus
}
#endif
#endif /* __TFM_BOOT_STATUS_H__ */

View File

@ -1,68 +0,0 @@
/* Copyright (c) 2017-2019 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*******************************************************************************
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Template Version 1.0
* Generated by tools/psa/generate_partition_code.py Version 1.1
******************************************************************************/
#ifndef __TFM_PARTITION_DEFS_INC__
#define __TFM_PARTITION_DEFS_INC__
/*************************** Service Partitions *******************************/
#define ATTEST_SRV_ID (TFM_SP_BASE + 0)
#define CRYPTO_SRV_ID (TFM_SP_BASE + 1)
#define PLATFORM_ID (TFM_SP_BASE + 2)
#define ITS_ID (TFM_SP_BASE + 3)
/*************************** Test Partitions **********************************/
#ifdef USE_PSA_TEST_PARTITIONS
#ifdef USE_CRYPTO_ACL_TEST
#define CRYPTO_ACL_TEST_ID (TFM_SP_BASE + 4 + 0)
#endif
#ifdef USE_CLIENT_TESTS_PART1
#define CLIENT_TESTS_PART1_ID (TFM_SP_BASE + 4 + 1)
#endif
#ifdef USE_SERVER_TESTS_PART1
#define SERVER_TESTS_PART1_ID (TFM_SP_BASE + 4 + 2)
#endif
#ifdef USE_SERVER_TESTS_PART2
#define SERVER_TESTS_PART2_ID (TFM_SP_BASE + 4 + 3)
#endif
#ifdef USE_SMOKE_TESTS_PART1
#define SMOKE_TESTS_PART1_ID (TFM_SP_BASE + 4 + 4)
#endif
#endif // USE_PSA_TEST_PARTITIONS
#ifdef USE_PSA_TEST_PARTITIONS
#define TFM_MAX_USER_PARTITIONS (4 + 5)
#else
#define TFM_MAX_USER_PARTITIONS (4)
#endif
#endif // __TFM_PARTITION_DEFS_INC__

View File

@ -1,107 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/*******************************************************************************
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Template Version 1.0
* Generated by tools/psa/generate_partition_code.py Version 1.1
******************************************************************************/
#ifndef __TFM_PARTITION_LIST_INC__
#define __TFM_PARTITION_LIST_INC__
/*************************** Service Partitions *******************************/
/* -----------------------------------------------------------------------------
* ATTEST_SRV
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(ATTEST_SRV, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 37, NORMAL, 8192);
PARTITION_ADD_INIT_FUNC(ATTEST_SRV, attest_main);
/* -----------------------------------------------------------------------------
* CRYPTO_SRV
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(CRYPTO_SRV, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 35, NORMAL, 16384);
PARTITION_ADD_INIT_FUNC(CRYPTO_SRV, crypto_main);
/* -----------------------------------------------------------------------------
* PLATFORM
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(PLATFORM, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 8, NORMAL, 1024);
PARTITION_ADD_INIT_FUNC(PLATFORM, platform_partition_entry);
/* -----------------------------------------------------------------------------
* ITS
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(ITS, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 10, NORMAL, 2048);
PARTITION_ADD_INIT_FUNC(ITS, its_entry);
/*************************** Test Partitions **********************************/
#ifdef USE_PSA_TEST_PARTITIONS
#ifdef USE_CRYPTO_ACL_TEST
/* -----------------------------------------------------------------------------
* CRYPTO_ACL_TEST
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(CRYPTO_ACL_TEST, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 128, NORMAL, 512);
PARTITION_ADD_INIT_FUNC(CRYPTO_ACL_TEST, test_partition_main);
#endif // USE_CRYPTO_ACL_TEST
#ifdef USE_CLIENT_TESTS_PART1
/* -----------------------------------------------------------------------------
* CLIENT_TESTS_PART1
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(CLIENT_TESTS_PART1, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 1, NORMAL, 1024);
PARTITION_ADD_INIT_FUNC(CLIENT_TESTS_PART1, client_part_main);
#endif // USE_CLIENT_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART1
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART1
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(SERVER_TESTS_PART1, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 2, NORMAL, 1024);
PARTITION_ADD_INIT_FUNC(SERVER_TESTS_PART1, server_part1_main);
#endif // USE_SERVER_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART2
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART2
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(SERVER_TESTS_PART2, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 3, NORMAL, 1024);
PARTITION_ADD_INIT_FUNC(SERVER_TESTS_PART2, server_part2_main);
#endif // USE_SERVER_TESTS_PART2
#ifdef USE_SMOKE_TESTS_PART1
/* -----------------------------------------------------------------------------
* SMOKE_TESTS_PART1
* -------------------------------------------------------------------------- */
PARTITION_DECLARE(SMOKE_TESTS_PART1, 0
| SPM_PART_FLAG_IPC
, "APPLICATION-ROT", 4, NORMAL, 512);
PARTITION_ADD_INIT_FUNC(SMOKE_TESTS_PART1, smoke_part_main);
#endif // USE_SMOKE_TESTS_PART1
#endif // USE_PSA_TEST_PARTITIONS
#endif // __TFM_PARTITION_LIST_INC__

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/*******************************************************************************
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Template Version 1.0
* Generated by tools/psa/generate_partition_code.py Version 1.1
******************************************************************************/
#ifndef __TFM_SERVICE_LIST_INC__
#define __TFM_SERVICE_LIST_INC__
/*************************** Service Partitions *******************************/
/* -----------------------------------------------------------------------------
* ATTEST_SRV Services
* -------------------------------------------------------------------------- */
{"PSA_ATTEST_GET_TOKEN_ID", ATTEST_SRV_ID, PSA_ATTEST_GET_TOKEN, 0x00000F10, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_ATTEST_GET_TOKEN_SIZE_ID", ATTEST_SRV_ID, PSA_ATTEST_GET_TOKEN_SIZE, 0x00000F11, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_ATTEST_INJECT_KEY_ID", ATTEST_SRV_ID, PSA_ATTEST_INJECT_KEY, 0x00000F12, true, 1, TFM_VERSION_POLICY_STRICT},
/* -----------------------------------------------------------------------------
* CRYPTO_SRV Services
* -------------------------------------------------------------------------- */
{"PSA_CRYPTO_INIT_ID", CRYPTO_SRV_ID, PSA_CRYPTO_INIT, 0x00000F00, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_MAC_ID", CRYPTO_SRV_ID, PSA_MAC, 0x00000F01, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_HASH_ID", CRYPTO_SRV_ID, PSA_HASH, 0x00000F02, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_ASYMMETRIC_ID", CRYPTO_SRV_ID, PSA_ASYMMETRIC, 0x00000F03, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_SYMMETRIC_ID", CRYPTO_SRV_ID, PSA_SYMMETRIC, 0x00000F04, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_AEAD_ID", CRYPTO_SRV_ID, PSA_AEAD, 0x00000F05, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_KEY_MNG_ID", CRYPTO_SRV_ID, PSA_KEY_MNG, 0x00000F06, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_RNG_ID", CRYPTO_SRV_ID, PSA_RNG, 0x00000F07, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_CRYPTO_FREE_ID", CRYPTO_SRV_ID, PSA_CRYPTO_FREE, 0x00000F08, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_KEY_DERIVATION_ID", CRYPTO_SRV_ID, PSA_KEY_DERIVATION, 0x00000F09, true, 1, TFM_VERSION_POLICY_STRICT},
{"PSA_ENTROPY_ID", CRYPTO_SRV_ID, PSA_ENTROPY_INJECT, 0x00000F0A, true, 1, TFM_VERSION_POLICY_STRICT},
/* -----------------------------------------------------------------------------
* PLATFORM Services
* -------------------------------------------------------------------------- */
{"PSA_PLATFORM_LC_GET", PLATFORM_ID, PSA_PLATFORM_LC_GET_MSK, 0x00011000, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_PLATFORM_LC_SET", PLATFORM_ID, PSA_PLATFORM_LC_SET_MSK, 0x00011001, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_PLATFORM_SYSTEM_RESET", PLATFORM_ID, PSA_PLATFORM_SYSTEM_RESET_MSK, 0x00011002, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_PLATFORM_IOCTL", PLATFORM_ID, PSA_PLATFORM_IOCTL_MSK, 0x00011003, true, 1, TFM_VERSION_POLICY_RELAXED},
/* -----------------------------------------------------------------------------
* ITS Services
* -------------------------------------------------------------------------- */
{"PSA_ITS_GET", ITS_ID, PSA_ITS_GET_MSK, 0x00011A00, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_ITS_SET", ITS_ID, PSA_ITS_SET_MSK, 0x00011A01, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_ITS_INFO", ITS_ID, PSA_ITS_INFO_MSK, 0x00011A02, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_ITS_REMOVE", ITS_ID, PSA_ITS_REMOVE_MSK, 0x00011A03, true, 1, TFM_VERSION_POLICY_RELAXED},
{"PSA_ITS_RESET", ITS_ID, PSA_ITS_RESET_MSK, 0x00011A04, false, 1, TFM_VERSION_POLICY_RELAXED},
/*************************** Test Partitions **********************************/
#ifdef USE_PSA_TEST_PARTITIONS
#ifdef USE_CRYPTO_ACL_TEST
/* -----------------------------------------------------------------------------
* CRYPTO_ACL_TEST Services
* -------------------------------------------------------------------------- */
{"CRYPTO_GENERATE_KEY", CRYPTO_ACL_TEST_ID, CRYPTO_GENERATE_KEY_MSK, 0x00000201, true, 1, TFM_VERSION_POLICY_RELAXED},
{"CRYPTO_OPEN_KEY", CRYPTO_ACL_TEST_ID, CRYPTO_OPEN_KEY_MSK, 0x00000202, true, 1, TFM_VERSION_POLICY_RELAXED},
{"CRYPTO_CLOSE_KEY", CRYPTO_ACL_TEST_ID, CRYPTO_CLOSE_KEY_MSK, 0x00000203, true, 1, TFM_VERSION_POLICY_RELAXED},
{"CRYPTO_DESTROY_KEY", CRYPTO_ACL_TEST_ID, CRYPTO_DESTROY_KEY_MSK, 0x00000205, true, 1, TFM_VERSION_POLICY_RELAXED},
{"CRYPTO_GET_KEY_ATTRIBUTES", CRYPTO_ACL_TEST_ID, CRYPTO_GET_KEY_ATTRIBUTES_MSK, 0x00000206, true, 1, TFM_VERSION_POLICY_RELAXED},
{"CRYPTO_IMPORT_KEY", CRYPTO_ACL_TEST_ID, CRYPTO_IMPORT_KEY_MSK, 0x00000208, true, 1, TFM_VERSION_POLICY_RELAXED},
#endif // USE_CRYPTO_ACL_TEST
#ifdef USE_CLIENT_TESTS_PART1
/* -----------------------------------------------------------------------------
* CLIENT_TESTS_PART1 Services
* -------------------------------------------------------------------------- */
{"CLIENT_TESTS_PART1_ROT_SRV1", CLIENT_TESTS_PART1_ID, PART1_ROT_SRV1_MSK, 0x00001A05, true, 5, TFM_VERSION_POLICY_RELAXED},
{"CLIENT_TESTS_PART1_DROP_CONN", CLIENT_TESTS_PART1_ID, DROP_CONN_MSK, 0x00001A06, true, 5, TFM_VERSION_POLICY_RELAXED},
{"CLIENT_TESTS_PART1_SECURE_CLIENTS_ONLY", CLIENT_TESTS_PART1_ID, SECURE_CLIENTS_ONLY_MSK, 0x00001A07, false, 5, TFM_VERSION_POLICY_RELAXED},
#endif // USE_CLIENT_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART1
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART1 Services
* -------------------------------------------------------------------------- */
{"SERVER_TESTS_PART1_CONTROL", SERVER_TESTS_PART1_ID, CONTROL_MSK, 0x00001A01, true, 5, TFM_VERSION_POLICY_RELAXED},
{"SERVER_TESTS_PART1_TEST", SERVER_TESTS_PART1_ID, TEST_MSK, 0x00001A02, true, 12, TFM_VERSION_POLICY_STRICT},
#endif // USE_SERVER_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART2
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART2 Services
* -------------------------------------------------------------------------- */
{"SERVER_TESTS_PART2_ROT_SRV_REVERSE", SERVER_TESTS_PART2_ID, ROT_SRV_REVERSE_MSK, 0x00001A03, false, 5, TFM_VERSION_POLICY_STRICT},
{"SERVER_TESTS_PART2_ROT_SRV_DB_TST", SERVER_TESTS_PART2_ID, ROT_SRV_DB_TST_MSK, 0x00001A04, false, 5, TFM_VERSION_POLICY_STRICT},
#endif // USE_SERVER_TESTS_PART2
#ifdef USE_SMOKE_TESTS_PART1
/* -----------------------------------------------------------------------------
* SMOKE_TESTS_PART1 Services
* -------------------------------------------------------------------------- */
{"SMOKE_TESTS_PART1_ROT_SRV1", SMOKE_TESTS_PART1_ID, ROT_SRV1_MSK, 0x00001A00, true, 5, TFM_VERSION_POLICY_RELAXED},
#endif // USE_SMOKE_TESTS_PART1
#endif // USE_PSA_TEST_PARTITIONS
#endif // __TFM_SERVICE_LIST_INC__

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/*******************************************************************************
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Template Version 1.0
* Generated by tools/psa/generate_partition_code.py Version 1.1
******************************************************************************/
#ifndef __TFM_SPM_SIGNAL_DEFS_H__
#define __TFM_SPM_SIGNAL_DEFS_H__
/*************************** Service Partitions *******************************/
/* -----------------------------------------------------------------------------
* ATTEST_SRV Signals
* -------------------------------------------------------------------------- */
#define PSA_ATTEST_GET_TOKEN_POS (4UL)
#define PSA_ATTEST_GET_TOKEN (1UL << PSA_ATTEST_GET_TOKEN_POS)
#define PSA_ATTEST_GET_TOKEN_SIZE_POS (5UL)
#define PSA_ATTEST_GET_TOKEN_SIZE (1UL << PSA_ATTEST_GET_TOKEN_SIZE_POS)
#define PSA_ATTEST_INJECT_KEY_POS (6UL)
#define PSA_ATTEST_INJECT_KEY (1UL << PSA_ATTEST_INJECT_KEY_POS)
/* -----------------------------------------------------------------------------
* CRYPTO_SRV Signals
* -------------------------------------------------------------------------- */
#define PSA_CRYPTO_INIT_POS (4UL)
#define PSA_CRYPTO_INIT (1UL << PSA_CRYPTO_INIT_POS)
#define PSA_MAC_POS (5UL)
#define PSA_MAC (1UL << PSA_MAC_POS)
#define PSA_HASH_POS (6UL)
#define PSA_HASH (1UL << PSA_HASH_POS)
#define PSA_ASYMMETRIC_POS (7UL)
#define PSA_ASYMMETRIC (1UL << PSA_ASYMMETRIC_POS)
#define PSA_SYMMETRIC_POS (8UL)
#define PSA_SYMMETRIC (1UL << PSA_SYMMETRIC_POS)
#define PSA_AEAD_POS (9UL)
#define PSA_AEAD (1UL << PSA_AEAD_POS)
#define PSA_KEY_MNG_POS (10UL)
#define PSA_KEY_MNG (1UL << PSA_KEY_MNG_POS)
#define PSA_RNG_POS (11UL)
#define PSA_RNG (1UL << PSA_RNG_POS)
#define PSA_CRYPTO_FREE_POS (12UL)
#define PSA_CRYPTO_FREE (1UL << PSA_CRYPTO_FREE_POS)
#define PSA_KEY_DERIVATION_POS (13UL)
#define PSA_KEY_DERIVATION (1UL << PSA_KEY_DERIVATION_POS)
#define PSA_ENTROPY_INJECT_POS (14UL)
#define PSA_ENTROPY_INJECT (1UL << PSA_ENTROPY_INJECT_POS)
/* -----------------------------------------------------------------------------
* PLATFORM Signals
* -------------------------------------------------------------------------- */
#define PSA_PLATFORM_LC_GET_MSK_POS (4UL)
#define PSA_PLATFORM_LC_GET_MSK (1UL << PSA_PLATFORM_LC_GET_MSK_POS)
#define PSA_PLATFORM_LC_SET_MSK_POS (5UL)
#define PSA_PLATFORM_LC_SET_MSK (1UL << PSA_PLATFORM_LC_SET_MSK_POS)
#define PSA_PLATFORM_SYSTEM_RESET_MSK_POS (6UL)
#define PSA_PLATFORM_SYSTEM_RESET_MSK (1UL << PSA_PLATFORM_SYSTEM_RESET_MSK_POS)
#define PSA_PLATFORM_IOCTL_MSK_POS (7UL)
#define PSA_PLATFORM_IOCTL_MSK (1UL << PSA_PLATFORM_IOCTL_MSK_POS)
/* -----------------------------------------------------------------------------
* ITS Signals
* -------------------------------------------------------------------------- */
#define PSA_ITS_GET_MSK_POS (4UL)
#define PSA_ITS_GET_MSK (1UL << PSA_ITS_GET_MSK_POS)
#define PSA_ITS_SET_MSK_POS (5UL)
#define PSA_ITS_SET_MSK (1UL << PSA_ITS_SET_MSK_POS)
#define PSA_ITS_INFO_MSK_POS (6UL)
#define PSA_ITS_INFO_MSK (1UL << PSA_ITS_INFO_MSK_POS)
#define PSA_ITS_REMOVE_MSK_POS (7UL)
#define PSA_ITS_REMOVE_MSK (1UL << PSA_ITS_REMOVE_MSK_POS)
#define PSA_ITS_RESET_MSK_POS (8UL)
#define PSA_ITS_RESET_MSK (1UL << PSA_ITS_RESET_MSK_POS)
/*************************** Test Partitions **********************************/
#ifdef USE_PSA_TEST_PARTITIONS
#ifdef USE_CRYPTO_ACL_TEST
/* -----------------------------------------------------------------------------
* CRYPTO_ACL_TEST Signals
* -------------------------------------------------------------------------- */
#define CRYPTO_GENERATE_KEY_MSK_POS (4UL)
#define CRYPTO_GENERATE_KEY_MSK (1UL << CRYPTO_GENERATE_KEY_MSK_POS)
#define CRYPTO_OPEN_KEY_MSK_POS (5UL)
#define CRYPTO_OPEN_KEY_MSK (1UL << CRYPTO_OPEN_KEY_MSK_POS)
#define CRYPTO_CLOSE_KEY_MSK_POS (6UL)
#define CRYPTO_CLOSE_KEY_MSK (1UL << CRYPTO_CLOSE_KEY_MSK_POS)
#define CRYPTO_DESTROY_KEY_MSK_POS (7UL)
#define CRYPTO_DESTROY_KEY_MSK (1UL << CRYPTO_DESTROY_KEY_MSK_POS)
#define CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS (8UL)
#define CRYPTO_GET_KEY_ATTRIBUTES_MSK (1UL << CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS)
#define CRYPTO_IMPORT_KEY_MSK_POS (9UL)
#define CRYPTO_IMPORT_KEY_MSK (1UL << CRYPTO_IMPORT_KEY_MSK_POS)
#endif // USE_CRYPTO_ACL_TEST
#ifdef USE_CLIENT_TESTS_PART1
/* -----------------------------------------------------------------------------
* CLIENT_TESTS_PART1 Signals
* -------------------------------------------------------------------------- */
#define PART1_ROT_SRV1_MSK_POS (4UL)
#define PART1_ROT_SRV1_MSK (1UL << PART1_ROT_SRV1_MSK_POS)
#define DROP_CONN_MSK_POS (5UL)
#define DROP_CONN_MSK (1UL << DROP_CONN_MSK_POS)
#define SECURE_CLIENTS_ONLY_MSK_POS (6UL)
#define SECURE_CLIENTS_ONLY_MSK (1UL << SECURE_CLIENTS_ONLY_MSK_POS)
#endif // USE_CLIENT_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART1
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART1 Signals
* -------------------------------------------------------------------------- */
#define CONTROL_MSK_POS (4UL)
#define CONTROL_MSK (1UL << CONTROL_MSK_POS)
#define TEST_MSK_POS (5UL)
#define TEST_MSK (1UL << TEST_MSK_POS)
#endif // USE_SERVER_TESTS_PART1
#ifdef USE_SERVER_TESTS_PART2
/* -----------------------------------------------------------------------------
* SERVER_TESTS_PART2 Signals
* -------------------------------------------------------------------------- */
#define ROT_SRV_REVERSE_MSK_POS (4UL)
#define ROT_SRV_REVERSE_MSK (1UL << ROT_SRV_REVERSE_MSK_POS)
#define ROT_SRV_DB_TST_MSK_POS (5UL)
#define ROT_SRV_DB_TST_MSK (1UL << ROT_SRV_DB_TST_MSK_POS)
#endif // USE_SERVER_TESTS_PART2
#ifdef USE_SMOKE_TESTS_PART1
/* -----------------------------------------------------------------------------
* SMOKE_TESTS_PART1 Signals
* -------------------------------------------------------------------------- */
#define ROT_SRV1_MSK_POS (4UL)
#define ROT_SRV1_MSK (1UL << ROT_SRV1_MSK_POS)
#endif // USE_SMOKE_TESTS_PART1
#endif // USE_PSA_TEST_PARTITIONS
#endif // __TFM_SPM_SIGNAL_DEFS_H__

View File

@ -1,11 +0,0 @@
{
"name": "tfm-s",
"macros": ["MBED_FAULT_HANDLER_DISABLED"],
"config": {
"max_ns_thread_count": {
"help": "maximum allowed number of non-secure threads",
"macro_name": "TFM_MAX_NS_THREAD_COUNT",
"value": 10
}
}
}

View File

@ -1,190 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_HAL_H__
#define __TFM_SPM_HAL_H__
#include <stdint.h>
#include "tfm_secure_api.h"
#include "spm_api.h"
/**
* \brief Holds peripheral specific data fields required to manage the
* peripherals isolation
*
* This structure has to be defined in the platform directory, and may have
* different definition for each platform. The structure should contain fields
* that describe the peripheral for the functions that are prototyped in this
* file and are responsible for configuring the isolation of the peripherals.
*
* Pointers to structures of this type are managed by the SPM, and passed to the
* necessary function on isolation request. The pointers are also defined by the
* platform in the header file tfm_peripherals_def.h. For details on this, see
* the documentation of that file.
*/
struct tfm_spm_partition_platform_data_t;
#if defined (TFM_PSA_API) || (TFM_LVL != 1)
/**
* \brief Holds SPM db fields that define the memory regions used by a
* partition.
*/
struct tfm_spm_partition_memory_data_t
{
uint32_t code_start; /*!< Start of the code memory of this partition. */
uint32_t code_limit; /*!< Address of the byte beyond the end of the code
* memory of this partition.
*/
uint32_t ro_start; /*!< Start of the read only memory of this
* partition.
*/
uint32_t ro_limit; /*!< Address of the byte beyond the end of the read
* only memory of this partition.
*/
uint32_t rw_start; /*!< Start of the data region of this partition. */
uint32_t rw_limit; /*!< Address of the byte beyond the end of the data
* region of this partition.
*/
uint32_t zi_start; /*!< Start of the zero initialised data region of
* this partition.
*/
uint32_t zi_limit; /*!< Address of the byte beyond the end of the zero
* initialised region of this partition.
*/
uint32_t stack_bottom; /*!< The bottom of the stack for the partition. */
uint32_t stack_top; /*!< The top of the stack for the partition. */
};
#endif
/**
* \brief This function initialises the HW used for isolation, and sets the
* default configuration for them.
*
* This function is called during TF-M core early startup, before DB init
*/
void tfm_spm_hal_init_isolation_hw(void);
/**
* \brief This function initialises the HW used for isolation, and sets the
* default configuration for them.
* This function is called during TF-M core early startup, after DB init
*/
void tfm_spm_hal_setup_isolation_hw(void);
/**
* \brief Configure peripherals for a partition based on the platfotm data from
* the DB
*
* This function is called during partition initialisation (before calling the
* init function for the partition)
*
* \param[in] platform_data The platform fields of the partition DB record to
* be used for configuration. Can be NULL.
*/
void tfm_spm_hal_configure_default_isolation(
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Configures the system debug properties.
* The default configuration of this function should disable secure debug
* when either DAUTH_NONE or DAUTH_NS_ONLY define is set. It is up to the
* platform owner to decide if secure debug can be turned on in their
* system, if DAUTH_FULL define is present.
* The DAUTH_CHIP_DEFAULT define should not be considered a safe default
* option unless explicitly noted by the chip vendor.
* The implementation has to expect that one of those defines is going to
* be set. Otherwise, a compile error needs to be triggered.
*/
void tfm_spm_hal_init_debug(void);
/**
* \brief Enables the fault handlers
*/
void enable_fault_handlers(void);
/**
* \brief Configures the system reset request properties
*/
void system_reset_cfg(void);
/**
* \brief Configures all external interrupts to target the
* NS state, apart for the ones associated to secure
* peripherals (plus MPC and PPC)
*/
void nvic_interrupt_target_state_cfg(void);
/**
* \brief This function enable the interrupts associated
* to the secure peripherals (plus the isolation boundary violation
* interrupts)
*/
void nvic_interrupt_enable(void);
/**
* \brief Get the VTOR value of non-secure image
*
* \return Returns the address where the vector table of the non-secure image
* is located
*/
uint32_t tfm_spm_hal_get_ns_VTOR(void);
/**
* \brief Get the initial address of non-secure image main stack
*
* \return Returns the initial non-secure MSP
*/
uint32_t tfm_spm_hal_get_ns_MSP(void);
/**
* \brief Get the entry point of the non-secure image
*
* \return Returns the address of the non-secure image entry point
*/
uint32_t tfm_spm_hal_get_ns_entry_point(void);
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
/**
* \brief Configure the sandbox for a partition.
*
* \param[in] memory_data The memory ranges from the partition DB for this
* partition
* \param[in] platform_data The platform fields of the partition DB record
* for this partition. Can be NULL.
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_partition_sandbox_config(
const struct tfm_spm_partition_memory_data_t *memory_data,
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Deconfigure the sandbox for a partition.
*
* \param[in] memory_data The memory ranges from the partition DB for this
* partition
* \param[in] platform_data The platform fields of the partition DB record
* for this partition. Can be NULL.
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
const struct tfm_spm_partition_memory_data_t *memory_data,
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Set the share region mode
*
* \param[in] share The mode to set
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_set_share_region(
enum tfm_buffer_share_region_e share);
#endif
#endif /* __TFM_SPM_HAL_H__ */

View File

@ -1,16 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
//This file holds description for the current directory. This documentation
//will be included in the Doxygen output.
/*!
\dir
\brief Source code for the TF-M core.
\details This directory holds the source code of the "TF-M core" module.
*/

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_ARCH_V8M_H__
#define __TFM_ARCH_V8M_H__
#include "cmsis.h"
#define XPSR_T32 0x01000000
#define LR_UNPRIVILEGED 0xfffffffd
/* This header file collects the ARCH related operations. */
struct tfm_state_context_base {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t ra_lr;
uint32_t ra;
uint32_t xpsr;
};
struct tfm_state_context_ext {
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t sp;
uint32_t sp_limit;
uint32_t dummy;
uint32_t lr;
};
struct tfm_state_context {
struct tfm_state_context_ext ctxb;
};
#define TFM_STATE_1ST_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
#define TFM_STATE_2ND_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r1)
#define TFM_STATE_3RD_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r2)
#define TFM_STATE_4TH_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r3)
#define TFM_STATE_RET_VAL(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
__STATIC_INLINE void tfm_trigger_pendsv(void)
{
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
void tfm_initialize_context(struct tfm_state_context *ctx,
uint32_t r0, uint32_t ra,
uint32_t sp, uint32_t sp_limit);
#endif

View File

@ -1,18 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_INTERNAL_DEFINES_H__
#define __TFM_INTERNAL_DEFINES_H__
/* IPC internal return status */
#define IPC_SUCCESS 0
#define IPC_ERROR_BAD_PARAMETERS (INT32_MIN)
#define IPC_ERROR_SHORT_BUFFER (INT32_MIN + 1)
#define IPC_ERROR_VERSION (INT32_MIN + 2)
#define IPC_ERROR_MEMORY_CHECK (INT32_MIN + 3)
#define IPC_ERROR_GENERIC (INT32_MIN + 0x1F)
#endif

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_LIST_H__
#define __TFM_LIST_H__
/* List structure */
struct tfm_list_node_t {
struct tfm_list_node_t *prev;
struct tfm_list_node_t *next;
};
/**
* \brief Initialize list head.
*
* \param[in] head List head need to be initialized.
*/
__STATIC_INLINE void tfm_list_init(struct tfm_list_node_t *head)
{
head->next = head;
head->prev = head;
}
/**
* \brief Add one node to list tail.
*
* \param[in] head List head initialized by \ref tfm_list_init.
* \param[in] node List node want to be added.
*/
__STATIC_INLINE void
tfm_list_add_tail(struct tfm_list_node_t *head, struct tfm_list_node_t *node)
{
head->prev->next = node;
node->prev = head->prev;
head->prev = node;
node->next = head;
}
/**
* \brief Check if a list is empty.
*
* \param[in] head List head initialized by \ref tfm_list_init.
*
* \returns returns 1 for empty, or 0 for not.
*/
__STATIC_INLINE int32_t tfm_list_is_empty(struct tfm_list_node_t *head)
{
return (head->next == head);
}
/**
* \brief Insert one node to list head.
*
* \param[in] head List head initialized by \ref tfm_list_init.
* \param[in] node List node want to be inserted.
*/
__STATIC_INLINE void
tfm_list_insert_first(struct tfm_list_node_t *head,
struct tfm_list_node_t *node)
{
node->next = head->next;
node->prev = head;
head->next->prev = node;
head->next = node;
}
/**
* \brief Retrieve the fist node from list.
*
* \param[in] head List head initialized by \ref tfm_list_init.
*
* \returns Returns the pointer to first list node.
*/
__STATIC_INLINE
struct tfm_list_node_t *tfm_list_first_node(struct tfm_list_node_t *head)
{
return head->next;
}
/**
* \brief Delete one node from list.
*
* \param[in] node List node want to be deleted.
*/
__STATIC_INLINE void tfm_list_del_node(struct tfm_list_node_t *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
/* Go through each node of a list */
#define TFM_LIST_FOR_EACH(node, head) \
for (node = (head)->next; node != head; node = node->next)
#endif

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_MESSAGE_QUEUE_H__
#define __TFM_MESSAGE_QUEUE_H__
#ifndef TFM_MSG_QUEUE_MAX_MSG_NUM
#define TFM_MSG_QUEUE_MAX_MSG_NUM 128
#endif
#define TFM_MSG_MAGIC 0x15154343
/* Message struct to collect parameter from client */
struct tfm_msg_body_t {
int32_t magic;
struct tfm_spm_service_t *service; /* RoT service pointer */
psa_handle_t handle; /* Connected Service handle */
struct tfm_event_t ack_evnt; /* Event for ack reponse */
psa_msg_t msg; /* PSA message body */
psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body */
psa_outvec outvec[PSA_MAX_IOVEC];
psa_outvec *caller_outvec; /*
* Save caller outvec pointer for
* write length update
*/
struct tfm_msg_body_t *next; /* List operators */
};
struct tfm_msg_queue_t {
struct tfm_msg_body_t *head; /* Queue head */
struct tfm_msg_body_t *tail; /* Queue tail */
uint32_t size; /* Number of the queue member */
};
/**
* \brief Enqueue a message into message queue.
*
* \param[in] queue Message queue, it will be initialized
* if has not been initialized.
* \param[in] node Message queue node want to be enqueue.
*
* \retval IPC_SUCCESS Success.
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
*/
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
struct tfm_msg_body_t *node);
/**
* \brief Dequeue a message from message queue.
*
* \param[in] queue Message queue.
*
* \retval node pointer Success.
* \retval NULL Queue is NULL or size is zero.
*/
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue);
/**
* \brief Check if a message queue is empty.
*
* \param[in] queue Message queue.
*
* \returns Returns 1 for empty, or 0 for not.
*/
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue);
#endif

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_POOLS_H__
#define __TFM_POOLS_H__
/*
* Resource pool - few known size resources allocation/free is required,
* so pool is more applicable than heap.
*/
/*
* Pool Instance:
* [ Pool Instance ] + N * [ Pool Chunks ]
*/
struct tfm_pool_chunk_t {
struct tfm_list_node_t list; /* Chunk list */
void *pool; /* Point to the parent pool */
uint8_t data[0]; /* Data indicator */
};
struct tfm_pool_instance_t {
size_t chunksz; /* Chunks size of pool member */
struct tfm_list_node_t chunks_list; /* Chunk list head in pool */
struct tfm_pool_chunk_t chunks[0]; /* Data indicator */
};
/*
* This will declares a static memory pool variable with chunk memory.
* Parameters:
* name - Variable name, will be used when register
* chunksz - chunk size in bytes
* num - Number of chunks
*/
#define TFM_POOL_DECLARE(name, chunksz, num) \
static uint8_t name##_pool_buf[((chunksz) + \
sizeof(struct tfm_pool_chunk_t)) * (num) \
+ sizeof(struct tfm_pool_instance_t)] \
__attribute__((aligned(4))); \
static struct tfm_pool_instance_t *name = \
(struct tfm_pool_instance_t *)name##_pool_buf
/* Get the head size of memory pool */
#define POOL_HEAD_SIZE (sizeof(struct tfm_pool_instance_t) + \
sizeof(struct tfm_pool_chunk_t))
/* Get the whole size of memory pool */
#define POOL_BUFFER_SIZE(name) sizeof(name##_pool_buf)
/**
* \brief Register a memory pool.
*
* \param[in] pool Pointer to memory pool declared by
* \ref TFM_POOL_DECLARE
* \param[in] poolsz Size of the pool buffer.
* \param[in] chunksz Size of chunks.
* \param[in] num Number of chunks.
*
* \retval IPC_SUCCESS Success.
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
*/
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
size_t chunksz, size_t num);
/**
* \brief Allocate a memory from pool.
*
* \param[in] pool pool pointer decleared by \ref TFM_POOL_DECLARE
*
* \retval buffer pointer Success.
* \retval NULL Failed.
*/
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool);
/**
* \brief Free the allocated memory.
*
* \param[in] ptr Buffer pointer want to free.
*/
void tfm_pool_free(void *ptr);
#endif

View File

@ -1,326 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_H__
#define __TFM_SPM_H__
#include <stdbool.h>
#include "tfm_list.h"
#include "tfm_secure_api.h"
#ifndef TFM_SPM_MAX_ROT_SERV_NUM
#define TFM_SPM_MAX_ROT_SERV_NUM 28
#endif
#define TFM_VERSION_POLICY_RELAXED 0
#define TFM_VERSION_POLICY_STRICT 1
#ifndef TFM_CONN_HANDLE_MAX_NUM
#define TFM_CONN_HANDLE_MAX_NUM 32
#endif
/* RoT connection handle list */
struct tfm_conn_handle_t {
psa_handle_t handle; /* Handle value */
void *rhandle; /* Reverse handle value */
struct tfm_list_node_t list; /* list node */
};
/* Service database defined by manifest */
struct tfm_spm_service_db_t {
char *name; /* Service name */
uint32_t partition_id; /* Partition ID which service belong to */
psa_signal_t signal; /* Service signal */
uint32_t sid; /* Service identifier */
bool non_secure_client; /* If can be called by non secure client */
uint32_t minor_version; /* Minor version */
uint32_t minor_policy; /* Minor version policy */
};
/* RoT Service data */
struct tfm_spm_service_t {
struct tfm_spm_service_db_t *service_db; /* Service database pointer */
struct tfm_spm_ipc_partition_t *partition; /*
* Point to secure partition
* data
*/
struct tfm_list_node_t handle_list; /* Service handle list */
struct tfm_msg_queue_t msg_queue; /* Message queue */
struct tfm_list_node_t list; /* For list operation */
};
/*
* FixMe: This structure is for IPC partition which is different with library
* mode partition. There needs to be an alignment for IPC partition database
* and library mode database.
*/
/* Secure Partition data */
struct tfm_spm_ipc_partition_t {
int32_t index; /* Partition index */
int32_t id; /* Secure partition ID */
struct tfm_event_t signal_evnt; /* Event signal */
uint32_t signals; /* Service signals had been triggered*/
uint32_t signal_mask; /* Service signal mask passed by psa_wait() */
struct tfm_list_node_t service_list;/* Service list */
};
/*************************** Extended SPM functions **************************/
/**
* \brief Get the running partition ID.
*
* \return Returns the partition ID
*/
uint32_t tfm_spm_partition_get_running_partition_id_ext(void);
/**
* \brief Get the current partition mode.
*
* \param[in] partition_idx Index of current partition
*
* \retval TFM_PARTITION_PRIVILEGED_MODE Privileged mode
* \retval TFM_PARTITION_UNPRIVILEGED_MODE Unprivileged mode
*/
uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx);
/******************** Service handle management functions ********************/
/**
* \brief Create connection handle for client connect
*
* \param[in] service Target service context pointer
*
* \retval PSA_NULL_HANDLE Create failed \ref PSA_NULL_HANDLE
* \retval >0 Service handle created, \ref psa_handle_t
*/
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service);
/**
* \brief Free connection handle which not used anymore.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval "Does not return" Panic for not find service by handle
*/
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle);
/**
* \brief Set reverse handle value for connection.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
* \param[in] rhandle rhandle need to save
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval "Does not return" Panic for not find handle node
*/
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle,
void *rhandle);
/**
* \brief Get reverse handle value from connection hanlde.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
*
* \retval void * Success
* \retval "Does not return" Panic for those:
* service pointer are NULL
* hanlde is \ref PSA_NULL_HANDLE
* handle node does not be found
*/
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle);
/******************** Partition management functions *************************/
/**
* \brief Get current running partition context.
*
* \retval NULL Failed
* \retval "Not NULL" Return the parttion context pointer
* \ref spm_partition_t structures
*/
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void);
/**
* \brief Get the service context by signal.
*
* \param[in] partition Partition context pointer
* \ref spm_partition_t structures
* \param[in] signal Signal associated with inputs to the Secure
* Partition, \ref psa_signal_t
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
psa_signal_t signal);
/**
* \brief Get the service context by service ID.
*
* \param[in] sid RoT Service identity
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid);
/**
* \brief Get the service context by connection handle.
*
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle()
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *
tfm_spm_get_service_by_handle(psa_handle_t conn_handle);
/**
* \brief Get the partition context by partition ID.
*
* \param[in] partition_id Partition identity
*
* \retval NULL Failed
* \retval "Not NULL" Target partition context pointer,
* \ref spm_partition_t structures
*/
struct tfm_spm_ipc_partition_t *
tfm_spm_get_partition_by_id(int32_t partition_id);
/************************ Message functions **********************************/
/**
* \brief Get message context by message handle.
*
* \param[in] msg_handle Message handle which is a reference generated
* by the SPM to a specific message.
*
* \return The message body context pointer
* \ref msg_body_t structures
*/
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle);
/**
* \brief Create a message for PSA client call.
*
* \param[in] service Target service context pointer, which can be
* obtained by partition management functions
* \prarm[in] handle Connect handle return by psa_connect(). Should
* be \ref PSA_NULL_HANDLE in psa_connect().
* \param[in] type Message type, PSA_IPC_CONNECT, PSA_IPC_CALL or
* PSA_IPC_DISCONNECT
* \param[in] ns_caller Whether from NS caller
* \param[in] invec Array of input \ref psa_invec structures
* \param[in] in_len Number of input \ref psa_invec structures
* \param[in] outvec Array of output \ref psa_outvec structures
* \param[in] out_len Number of output \ref psa_outvec structures
* \param[in] caller_outvec Array of caller output \ref psa_outvec structures
*
* \retval NULL Failed
* \retval "Not NULL" New message body pointer \ref msg_body_t structures
*/
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
psa_handle_t handle,
uint32_t type, int32_t ns_caller,
psa_invec *invec, size_t in_len,
psa_outvec *outvec, size_t out_len,
psa_outvec *caller_outvec);
/**
* \brief Free message which unused anymore
*
* \param[in] msg Message pointer which want to free
* \ref msg_body_t structures
*
* \retval void Success
* \retval "Does not return" Failed
*/
void tfm_spm_free_msg(struct tfm_msg_body_t *msg);
/**
* \brief Send message and wake up the SP who is waiting on
* message queue, block the current thread and
* scheduler triggered
*
* \param[in] service Target service context pointer, which can be
* obtained by partition management functions
* \param[in] msg message created by spm_create_msg()
* \ref msg_body_t structures
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_GENERIC Failed to enqueue message to service message queue
*/
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
struct tfm_msg_body_t *msg);
/**
* \brief Check the client minor version according to
* version policy
*
* \param[in] service Target service context pointer, which can be get
* by partition management functions
* \param[in] minor_version Client support minor version
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_VERSION Check failed
*/
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
uint32_t minor_version);
/**
* \brief Check the memory reference is valid.
*
* \param[in] buffer Pointer of memory reference
* \param[in] len Length of memory reference in bytes
* \param[in] ns_caller From non-secure caller
* \param[in] access Type of access specified by the
* \ref tfm_memory_access_e
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_MEMORY_CHECK Check failed
*/
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
enum tfm_memory_access_e access,
uint32_t privileged);
/* This function should be called before schedule function */
void tfm_spm_init(void);
/*
* PendSV specified function.
*
* Parameters :
* ctxb - State context storage pointer
*
* Notes:
* This is a staging API. Scheduler should be called in SPM finally and
* this function will be obsoleted later.
*/
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb);
#endif

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SVCALLS_H__
#define __TFM_SVCALLS_H__
/* Svcall for PSA Client APIs */
/**
* \brief SVC handler for \ref psa_framework_version.
*
* \return version The version of the PSA Framework implementation
* that is providing the runtime services to the
* caller.
*/
uint32_t tfm_svcall_psa_framework_version(void);
/**
* \brief SVC handler for \ref psa_version.
*
* \param[in] args Include all input arguments: sid.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
* caller is not permitted to access the service.
* \retval > 0 The minor version of the implemented RoT
* Service.
*/
uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for \ref psa_connect.
*
* \param[in] args Include all input arguments:
* sid, minor_version.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval > 0 A handle for the connection.
* \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
* connection.
* \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the
* connection at the moment.
* \retval "Does not return" The RoT Service ID and version are not
* supported, or the caller is not permitted to
* access the service.
*/
psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for \ref psa_call.
*
* \param[in] args Include all input arguments:
* handle, in_vec, in_len, out_vec, out_len.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
* \param[in] lr EXC_RETURN value of the SVC.
*
* \retval >=0 RoT Service-specific status value.
* \retval <0 RoT Service-specific error code.
* \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
* Service. This indicates that either this or
* a previous message was invalid.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was passed.
* \arg The connection is already handling a request.
* \arg An invalid memory reference was provided.
* \arg in_len + out_len > PSA_MAX_IOVEC.
* \arg The message is unrecognized by the RoT
* Service or incorrectly formatted.
*/
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller,
uint32_t lr);
/**
* \brief SVC handler for \ref psa_close.
*
* \param[in] args Include all input arguments: handle.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval void Success.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was provided that is not
* the null handle.
* \arg The connection is handling a request.
*/
void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for IPC functions
*
* \param[in] svc_num SVC number
* \param[in] ctx Argument context
* \param[in] lr EXC_RETURN value of the SVC.
*
* \returns Return values from those who has,
* or PSA_SUCCESS.
*/
int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx, uint32_t lr);
#endif

View File

@ -1,232 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_THREAD_H__
#define __TFM_THREAD_H__
#include "tfm_arch_v8m.h"
#include "cmsis_compiler.h"
/* Status code */
#define THRD_STAT_CREATING 0
#define THRD_STAT_RUNNING 1
#define THRD_STAT_BLOCK 2
#define THRD_STAT_DETACH 3
#define THRD_STAT_INVALID 4
/* Security attribute - default as security */
#define THRD_ATTR_SECURE_OFFSET 16
#define THRD_ATTR_SECURE (0)
#define THRD_ATTR_NON_SECURE (1 << THRD_ATTR_SECURE_OFFSET)
/* Lower value has higher priority */
#define THRD_PRIOR_MASK 0xFF
#define THRD_PRIOR_HIGHEST 0x0
#define THRD_PRIOR_MEDIUM 0x7F
#define THRD_PRIOR_LOWEST 0xFF
/* Error code */
#define THRD_SUCCESS 0
#define THRD_ERR_INVALID_PARAM 1
/* Thread entry function type */
typedef void *(*tfm_thrd_func_t)(void *);
/* Thread context */
struct tfm_thrd_ctx {
tfm_thrd_func_t pfn; /* entry function */
void *param; /* entry parameter */
uint8_t *sp_base; /* stack bottom */
uint8_t *sp_top; /* stack top */
uint32_t prior; /* priority */
uint32_t status; /* status */
struct tfm_state_context state_ctx; /* State context */
struct tfm_thrd_ctx *next; /* next thread in list */
};
/*
* Initialize a thread context with the necessary info.
*
* Parameters :
* pth - pointer of caller provided thread context
* pfn - thread entry function
* param - thread entry function parameter
* sp_base - stack pointer base (higher address)
* sp_top - stack pointer top (lower address)
*
* Notes :
* Thread contex rely on caller allocated memory; initialize members in
* context. This function does not insert thread into schedulable list.
*/
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
tfm_thrd_func_t pfn, void *param,
uint8_t *sp_base, uint8_t *sp_top);
/* Set thread priority.
*
* Parameters :
* pth - pointer of thread context
* prior - priority value (0~255)
*
* Notes :
* Set thread priority. Priority is set to THRD_PRIOR_MEDIUM in
* tfm_thrd_init().
*/
void __STATIC_INLINE tfm_thrd_priority(struct tfm_thrd_ctx *pth,
uint32_t prior)
{
pth->prior &= ~THRD_PRIOR_MASK;
pth->prior |= prior & THRD_PRIOR_MASK;
}
/*
* Set thread security attribute.
*
* Parameters :
* pth - pointer of thread context
* attr_secure - THRD_ATTR_SECURE or THRD_ATTR_NON_SECURE
*
* Notes
* Reuse prior of thread context to shift down non-secure thread priority.
*/
void __STATIC_INLINE tfm_thrd_secure(struct tfm_thrd_ctx *pth,
uint32_t attr_secure)
{
pth->prior &= ~THRD_ATTR_NON_SECURE;
pth->prior |= attr_secure;
}
/*
* Set thread status.
*
* Parameters :
* pth - pointer of thread context
* new_status - new status of thread
*
* Return :
* None
*
* Notes :
* Thread status is not changed if invalid status value inputed.
*/
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status);
/*
* Get thread status.
*
* Parameters :
* pth - pointer of thread context
*
* Return :
* Status of thread
*/
uint32_t __STATIC_INLINE tfm_thrd_get_status(struct tfm_thrd_ctx *pth)
{
return pth->status;
}
/*
* Set thread state return value.
*
* Parameters :
* pth - pointer of thread context
* retval - return value to be set for thread state
*
* Notes :
* This API is useful for blocked syscall blocking thread. Syscall
* could set its return value to the caller before caller goes.
*/
void __STATIC_INLINE tfm_thrd_set_retval(struct tfm_thrd_ctx *pth,
uint32_t retval)
{
TFM_STATE_RET_VAL(&pth->state_ctx) = retval;
}
/*
* Validate thread context and insert it into schedulable list.
*
* Parameters :
* pth - pointer of thread context
*
* Return :
* THRD_SUCCESS for success. Or an error is returned.
*
* Notes :
* This function validates thread info. It returns error if thread info
* is not correct. Thread is avaliable after successful tfm_thrd_start().
*/
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth);
/*
* Get current running thread.
*
* Return :
* Current running thread context pointer.
*/
struct tfm_thrd_ctx *tfm_thrd_curr_thread(void);
/*
* Get next running thread in list.
*
* Return :
* Pointer of next thread to be run.
*/
struct tfm_thrd_ctx *tfm_thrd_next_thread(void);
/*
* Start scheduler for existing threads
*
* Parameters:
* pth - pointer of the caller context collecting thread
*
* Notes :
* This function should be called only ONCE to start the scheduler.
* Caller needs to provide a thread object to collect current context.
* The usage of the collected context is caller defined.
*/
void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth);
/*
* Activate a scheduling action after exception.
*
* Notes :
* This function could be called multiple times before scheduling.
*/
void tfm_thrd_activate_schedule(void);
/*
* Save current context into 'prev' thread and switch to 'next'.
*
* Parameters :
* ctxb - latest caller context
* prev - previous thread to be switched out
* next - thread to be run
*
* Notes :
* This function could be called multiple times before scheduling.
*/
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
struct tfm_thrd_ctx *prev,
struct tfm_thrd_ctx *next);
/*
* Svcall to exit current running thread.
*
* Notes :
* Remove current thread out of schedulable list.
*/
void tfm_svcall_thrd_exit(void);
/*
* Exit current running thread for client.
*
* Notes:
* Must be called in thread mode.
*/
void tfm_thrd_exit(void);
#endif

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_UTILS_H__
#define __TFM_UTILS_H__
/* CPU spin here */
void tfm_panic(void);
/* Assert and spin */
#define TFM_ASSERT(cond) \
do { \
if (!(cond)) { \
printf("Assert:%s:%d", __FUNCTION__, __LINE__); \
while (1) \
; \
} \
} while (0)
/* Get container structure start address from member */
#define TFM_GET_CONTAINER_PTR(ptr, type, member) \
(type *)((unsigned long)(ptr) - offsetof(type, member))
int32_t tfm_bitcount(uint32_t n);
#endif

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_WAIT_H__
#define __TFM_WAIT_H__
#include "cmsis_compiler.h"
/* The magic number has two purposes: corruption detection and debug */
#define TFM_EVENT_MAGIC 0x65766e74
struct tfm_event_t {
uint32_t magic; /* 'evnt' */
struct tfm_thrd_ctx *owner; /* Event blocked thread */
};
/*
* Initialize an event object.
*
* Parameters:
* pevnt - The pointer of event object allocated by the caller
*/
void __STATIC_INLINE tfm_event_init(struct tfm_event_t *pevnt)
{
pevnt->magic = TFM_EVENT_MAGIC;
pevnt->owner = NULL;
}
/*
* Wait on an event object.
*
* Parameters:
* pevnt - The pointer of event object allocated by the caller
*
* Notes:
* Block caller thread by calling this function.
*/
void tfm_event_wait(struct tfm_event_t *pevnt);
/*
* Wake up an event object.
*
* Parameters :
* pevnt - The pointer of event object allocated by the caller
* retval - Value to be returned to owner
*
* Notes:
* Wake up the blocked thread and set parameter 'retval' as the return value.
*/
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval);
#endif

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_svc.h"
#include "psa_client.h"
__attribute__((naked, section("SFN")))
uint32_t psa_framework_version(void)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_FRAMEWORK_VERSION));
}
__attribute__((naked, section("SFN")))
uint32_t psa_version(uint32_t sid)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_VERSION));
}
__attribute__((naked, section("SFN")))
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CONNECT));
}
__attribute__((naked, section("SFN")))
psa_status_t psa_call(psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CALL));
}
__attribute__((naked, section("SFN")))
void psa_close(psa_handle_t handle)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CLOSE));
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_svc.h"
#include "psa_client.h"
#include "psa_service.h"
__attribute__((naked, section("SFN")))
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_WAIT));
}
__attribute__((naked, section("SFN")))
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_GET));
}
__attribute__((naked, section("SFN")))
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_SET_RHANDLE));
}
__attribute__((naked, section("SFN")))
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
void *buffer, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_READ));
}
__attribute__((naked, section("SFN")))
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_SKIP));
}
__attribute__((naked, section("SFN")))
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
const void *buffer, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_WRITE));
}
__attribute__((naked, section("SFN")))
void psa_reply(psa_handle_t msg_handle, psa_status_t retval)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_REPLY));
}
__attribute__((naked, section("SFN")))
void psa_notify(int32_t partition_id)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_NOTIFY));
}
__attribute__((naked, section("SFN")))
void psa_clear(void)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CLEAR));
}
__attribute__((naked, section("SFN")))
void psa_eoi(psa_signal_t irq_signal)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_EOI));
}

View File

@ -1,147 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_arch_v8m.h"
#include "cmsis.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_utils.h"
#include "tfm_thread.h"
#include "tfm_memory_utils.h"
/* This file contains the ARCH code for ARM V8M */
__attribute__((section("SFN")))
static void exit_zone(void)
{
tfm_thrd_exit();
}
void tfm_initialize_context(struct tfm_state_context *ctx,
uint32_t r0, uint32_t ra,
uint32_t sp, uint32_t sp_limit)
{
/*
* For security consideration, set unused registers into ZERO;
* and only necessary registers are set here.
*/
struct tfm_state_context_base *p_ctxa =
(struct tfm_state_context_base *)sp;
/*
* Shift back SP to leave space for holding base context
* since thread is kicked off through exception return.
*/
p_ctxa--;
/* Basic context is considerate at thread start.*/
tfm_memset(p_ctxa, 0, sizeof(*p_ctxa));
p_ctxa->r0 = r0;
p_ctxa->ra = ra;
p_ctxa->ra_lr = (uint32_t)exit_zone;
p_ctxa->xpsr = XPSR_T32;
tfm_memset(ctx, 0, sizeof(*ctx));
ctx->ctxb.sp = (uint32_t)p_ctxa;
ctx->ctxb.sp_limit = sp_limit;
ctx->ctxb.lr = LR_UNPRIVILEGED;
}
/*
* Stack status at PendSV entry:
*
* [ R0 - R3 ]<- PSP
* [ R12 ]
* [ LR_of_RA ]
* MSP->[ ........ ] [ RA ]
* [ ........ ] [ XPSR ]
* [ ........ ]
* [ ........ ]
*
* Stack status before calling pendsv_do_schedule():
*
* MSP->[ R4 - R11 ]
* [ PSP ]--->[ R0 - R3 ]
* [ PSP Limit] [ R12 ]
* [ R2(dummy)] [ LR_of_RA ]
* [ LR ] [ RA ]
* [ ........ ] [ XPSR ]
* [ ........ ] [ ........ ]
* [ ........ ]
*
* pendsv_do_schedule() updates stacked context into current thread and
* replace stacked context with context of next thread.
*
* Scheduler does not support handler mode thread so take PSP/PSP_LIMIT as
* thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
* aligned.
*/
#if defined(__ARM_ARCH_8M_MAIN__)
__attribute__((naked)) void PendSV_Handler(void)
{
__ASM volatile(
"mrs r0, psp \n"
"mrs r1, psplim \n"
"push {r0, r1, r2, lr} \n"
"push {r4-r11} \n"
"mov r0, sp \n"
"bl tfm_pendsv_do_schedule \n"
"pop {r4-r11} \n"
"pop {r0, r1, r2, lr} \n"
"msr psp, r0 \n"
"msr psplim, r1 \n"
"bx lr \n"
);
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) void PendSV_Handler(void)
{
__ASM volatile(
"mrs r0, psp \n"
"mrs r1, psplim \n"
"push {r0, r1, r2, lr} \n"
"push {r4-r7} \n"
"mov r4, r8 \n"
"mov r5, r9 \n"
"mov r6, r10 \n"
"mov r7, r11 \n"
"push {r4-r7} \n"
"mov r0, sp \n"
"bl tfm_pendsv_do_schedule \n"
"pop {r4-r7} \n"
"mov r8, r4 \n"
"mov r9, r5 \n"
"mov r10, r6 \n"
"mov r11, r7 \n"
"pop {r4-r7} \n"
"pop {r0-r3} \n"
"mov lr, r3 \n"
"msr psp, r0 \n"
"msr psplim, r1 \n"
"bx lr \n"
);
}
#else
#error "Unsupported ARM Architecture."
#endif
/* Reserved for future usage */
__attribute__((naked)) void MemManage_Handler(void)
{
__ASM volatile("b .");
}
__attribute__((naked)) void BusFault_Handler(void)
{
__ASM volatile("b .");
}
__attribute__((naked)) void UsageFault_Handler(void)
{
__ASM volatile("b .");
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_internal_defines.h"
#include "tfm_message_queue.h"
/* Message queue process */
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
struct tfm_msg_body_t *node)
{
if (!queue || !node) {
return IPC_ERROR_BAD_PARAMETERS;
}
if (queue->size == 0) {
queue->head = node;
queue->tail = node;
} else {
queue->tail->next = node;
queue->tail = node;
}
queue->size++;
return IPC_SUCCESS;
}
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue)
{
struct tfm_msg_body_t *pop_node;
if (!queue) {
return NULL;
}
if (queue->size == 0) {
return NULL;
}
pop_node = queue->head;
queue->head = queue->head->next;
queue->size--;
return pop_node;
}
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue)
{
return queue->size == 0 ? 1 : 0;
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_internal_defines.h"
#include "cmsis_compiler.h"
#include "tfm_utils.h"
#include "tfm_list.h"
#include "tfm_pools.h"
#include "tfm_memory_utils.h"
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
size_t chunksz, size_t num)
{
struct tfm_pool_chunk_t *pchunk;
size_t i;
if (!pool || num == 0) {
return IPC_ERROR_BAD_PARAMETERS;
}
/* Ensure buffer is large enough */
if (poolsz != ((chunksz + sizeof(struct tfm_pool_chunk_t)) * num +
sizeof(struct tfm_pool_instance_t))) {
return IPC_ERROR_BAD_PARAMETERS;
}
/* Buffer should be BSS cleared but clear it again */
tfm_memset(pool, 0, poolsz);
/* Chain pool chunks */
tfm_list_init(&pool->chunks_list);
pchunk = (struct tfm_pool_chunk_t *)pool->chunks;
for (i = 0; i < num; i++) {
pchunk->pool = pool;
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
pchunk = (struct tfm_pool_chunk_t *)&pchunk->data[chunksz];
}
/* Prepare instance and insert to pool list */
pool->chunksz = chunksz;
return IPC_SUCCESS;
}
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool)
{
struct tfm_list_node_t *node;
struct tfm_pool_chunk_t *pchunk;
if (!pool) {
return NULL;
}
if (tfm_list_is_empty(&pool->chunks_list)) {
return NULL;
}
node = tfm_list_first_node(&pool->chunks_list);
pchunk = TFM_GET_CONTAINER_PTR(node, struct tfm_pool_chunk_t, list);
/* Remove node from list node, it will be added when pool free */
tfm_list_del_node(node);
return &pchunk->data;
}
void tfm_pool_free(void *ptr)
{
struct tfm_pool_chunk_t *pchunk;
struct tfm_pool_instance_t *pool;
pchunk = TFM_GET_CONTAINER_PTR(ptr, struct tfm_pool_chunk_t, data);
pool = (struct tfm_pool_instance_t *)pchunk->pool;
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
}

View File

@ -1,619 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_utils.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
#include "spm_db_setup.h"
#include "tfm_internal_defines.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_list.h"
#include "tfm_pools.h"
#include "tfm_spm.h"
#include "tfm_spm_signal_defs.h"
#include "tfm_thread.h"
#include "region_defs.h"
#include "tfm_nspm.h"
#include "tfm_memory_utils.h"
#include "platform/mbed_toolchain.h"
/*
* IPC partitions.
* FixMe: Need to get align with spm_partition_db_t.
*/
static struct tfm_spm_ipc_partition_t
g_spm_ipc_partition[SPM_MAX_PARTITIONS] = {};
/* Extern SPM variable */
extern struct spm_partition_db_t g_spm_partition_db;
/* Extern secure lock variable */
extern int32_t tfm_secure_lock;
/* Pools */
TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
TFM_CONN_HANDLE_MAX_NUM);
TFM_POOL_DECLARE(spm_service_pool, sizeof(struct tfm_spm_service_t),
TFM_SPM_MAX_ROT_SERV_NUM);
TFM_POOL_DECLARE(msg_db_pool, sizeof(struct tfm_msg_body_t),
TFM_MSG_QUEUE_MAX_MSG_NUM);
static struct tfm_spm_service_db_t g_spm_service_db[] = {
#include "tfm_service_list.inc"
};
/********************** SPM functions for handler mode ***********************/
/* Service handle management functions */
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Get buffer for handle list structure from handle pool */
node = (struct tfm_conn_handle_t *)tfm_pool_alloc(conn_handle_pool);
if (!node) {
return PSA_NULL_HANDLE;
}
/* Global unique handle, use handle buffer address directly */
node->handle = (psa_handle_t)node;
/* Add handle node to list for next psa functions */
tfm_list_add_tail(&service->handle_list, &node->list);
return node->handle;
}
static struct tfm_conn_handle_t *
tfm_spm_find_conn_handle_node(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *handle_node;
struct tfm_list_node_t *node, *head;
TFM_ASSERT(service);
head = &service->handle_list;
TFM_LIST_FOR_EACH(node, head) {
handle_node = TFM_GET_CONTAINER_PTR(node, struct tfm_conn_handle_t,
list);
if (handle_node->handle == conn_handle) {
return handle_node;
}
}
return NULL;
}
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
/* Remove node from handle list */
tfm_list_del_node(&node->list);
node->rhandle = NULL;
/* Back handle buffer to pool */
tfm_pool_free(node);
return IPC_SUCCESS;
}
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle,
void *rhandle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Set reverse handle value only be allowed for a connected handle */
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
node->rhandle = rhandle;
return IPC_SUCCESS;
}
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Get reverse handle value only be allowed for a connected handle */
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
return node->rhandle;
}
/* Partition management functions */
struct tfm_spm_service_t *
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
psa_signal_t signal)
{
struct tfm_list_node_t *node, *head;
struct tfm_spm_service_t *service;
TFM_ASSERT(partition);
if (tfm_list_is_empty(&partition->service_list)) {
tfm_panic();
}
head = &partition->service_list;
TFM_LIST_FOR_EACH(node, head) {
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t, list);
if (service->service_db->signal == signal) {
return service;
}
}
return NULL;
}
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid)
{
uint32_t i;
struct tfm_list_node_t *node, *head;
struct tfm_spm_service_t *service;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
/* Skip partition without IPC flag */
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
SPM_PART_FLAG_IPC) == 0) {
continue;
}
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
continue;
}
head = &g_spm_ipc_partition[i].service_list;
TFM_LIST_FOR_EACH(node, head) {
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t,
list);
if (service->service_db->sid == sid) {
return service;
}
}
}
return NULL;
}
struct tfm_spm_service_t *
tfm_spm_get_service_by_handle(psa_handle_t conn_handle)
{
uint32_t i;
struct tfm_conn_handle_t *handle;
struct tfm_list_node_t *service_node, *service_head;
struct tfm_list_node_t *handle_node, *handle_head;
struct tfm_spm_service_t *service;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
/* Skip partition without IPC flag */
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
SPM_PART_FLAG_IPC) == 0) {
continue;
}
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
continue;
}
service_head = &g_spm_ipc_partition[i].service_list;
TFM_LIST_FOR_EACH(service_node, service_head) {
service = TFM_GET_CONTAINER_PTR(service_node,
struct tfm_spm_service_t, list);
handle_head = &service->handle_list;
TFM_LIST_FOR_EACH(handle_node, handle_head) {
handle = TFM_GET_CONTAINER_PTR(handle_node,
struct tfm_conn_handle_t, list);
if (handle->handle == conn_handle) {
return service;
}
}
}
}
return NULL;
}
struct tfm_spm_ipc_partition_t *
tfm_spm_get_partition_by_id(int32_t partition_id)
{
uint32_t i;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
if (g_spm_ipc_partition[i].id == partition_id) {
return &g_spm_ipc_partition[i];
}
}
return NULL;
}
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void)
{
uint32_t spid;
spid = tfm_spm_partition_get_running_partition_id_ext();
return tfm_spm_get_partition_by_id(spid);
}
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
uint32_t minor_version)
{
TFM_ASSERT(service);
switch (service->service_db->minor_policy) {
case TFM_VERSION_POLICY_RELAXED:
if (minor_version > service->service_db->minor_version) {
return IPC_ERROR_VERSION;
}
break;
case TFM_VERSION_POLICY_STRICT:
if (minor_version != service->service_db->minor_version) {
return IPC_ERROR_VERSION;
}
break;
default:
return IPC_ERROR_VERSION;
}
return IPC_SUCCESS;
}
/* Message functions */
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
{
/*
* There may be one error handle passed by the caller in two conditions:
* 1. Not a valid message handle.
* 2. Handle between different Partitions. Partition A passes one handle
* belong to other Partitions and tries to access other's data.
* So, need do necessary checking to prevent those conditions.
*/
struct tfm_msg_body_t *msg;
uint32_t partition_id;
msg = (struct tfm_msg_body_t *)msg_handle;
if (!msg) {
return NULL;
}
/*
* FixMe: For condition 1: using a magic number to define it's a message.
* It needs to be an enhancement to check the handle belong to service.
*/
if (msg->magic != TFM_MSG_MAGIC) {
return NULL;
}
/* For condition 2: check if the partition ID is same */
partition_id = tfm_spm_partition_get_running_partition_id_ext();
if (partition_id != msg->service->partition->id) {
return NULL;
}
return msg;
}
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
psa_handle_t handle,
uint32_t type, int32_t ns_caller,
psa_invec *invec, size_t in_len,
psa_outvec *outvec, size_t out_len,
psa_outvec *caller_outvec)
{
struct tfm_msg_body_t *msg = NULL;
uint32_t i;
TFM_ASSERT(service);
TFM_ASSERT(!(invec == NULL && in_len != 0));
TFM_ASSERT(!(outvec == NULL && out_len != 0));
TFM_ASSERT(in_len <= PSA_MAX_IOVEC);
TFM_ASSERT(out_len <= PSA_MAX_IOVEC);
TFM_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
/* Get message buffer from message pool */
msg = (struct tfm_msg_body_t *)tfm_pool_alloc(msg_db_pool);
if (!msg) {
return NULL;
}
/* Clear message buffer before using it */
tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
tfm_event_init(&msg->ack_evnt);
msg->magic = TFM_MSG_MAGIC;
msg->service = service;
msg->handle = handle;
msg->caller_outvec = caller_outvec;
/* Get current partition id */
if (ns_caller) {
msg->msg.client_id = tfm_nspm_get_current_client_id();
} else {
msg->msg.client_id = tfm_spm_partition_get_running_partition_id_ext();
}
/* Copy contents */
msg->msg.type = type;
for (i = 0; i < in_len; i++) {
msg->msg.in_size[i] = invec[i].len;
msg->invec[i].base = invec[i].base;
}
for (i = 0; i < out_len; i++) {
msg->msg.out_size[i] = outvec[i].len;
msg->outvec[i].base = outvec[i].base;
/* Out len is used to record the writed number, set 0 here again */
msg->outvec[i].len = 0;
}
/* Use message address as handle */
msg->msg.handle = (psa_handle_t)msg;
/* For connected handle, set rhandle to every message */
if (handle != PSA_NULL_HANDLE) {
msg->msg.rhandle = tfm_spm_get_rhandle(service, handle);
}
return msg;
}
void tfm_spm_free_msg(struct tfm_msg_body_t *msg)
{
tfm_pool_free(msg);
}
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
struct tfm_msg_body_t *msg)
{
TFM_ASSERT(service);
TFM_ASSERT(msg);
/* Enqueue message to service message queue */
if (tfm_msg_enqueue(&service->msg_queue, msg) != IPC_SUCCESS) {
return IPC_ERROR_GENERIC;
}
/* Messages put. Update signals */
service->partition->signals |= service->service_db->signal;
tfm_event_wake(&service->partition->signal_evnt,
(service->partition->signals &
service->partition->signal_mask));
tfm_event_wait(&msg->ack_evnt);
return IPC_SUCCESS;
}
/* SPM extend functions */
uint32_t tfm_spm_partition_get_running_partition_id_ext(void)
{
struct tfm_thrd_ctx *pth = tfm_thrd_curr_thread();
struct spm_partition_desc_t *partition;
partition = TFM_GET_CONTAINER_PTR(pth, struct spm_partition_desc_t,
sp_thrd);
return partition->static_data.partition_id;
}
static struct tfm_thrd_ctx *
tfm_spm_partition_get_thread_info_ext(uint32_t partition_idx)
{
return &g_spm_partition_db.partitions[partition_idx].sp_thrd;
}
static tfm_thrd_func_t
tfm_spm_partition_get_init_func_ext(uint32_t partition_idx)
{
return (tfm_thrd_func_t)(g_spm_partition_db.partitions[partition_idx].
static_data.partition_init);
}
static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_priority;
}
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
enum tfm_memory_access_e access,
uint32_t privileged)
{
int32_t err;
/* If len is zero, this indicates an empty buffer and base is ignored */
if (len == 0) {
return IPC_SUCCESS;
}
if (!buffer) {
return IPC_ERROR_BAD_PARAMETERS;
}
if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
return IPC_ERROR_MEMORY_CHECK;
}
if (access == TFM_MEMORY_ACCESS_RW) {
err = tfm_core_has_write_access_to_region(buffer, len, ns_caller,
privileged);
} else {
err = tfm_core_has_read_access_to_region(buffer, len, ns_caller,
privileged);
}
if (err == TFM_SUCCESS) {
return IPC_SUCCESS;
}
return IPC_ERROR_MEMORY_CHECK;
}
uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx)
{
if (tfm_spm_partition_get_flags(partition_idx) & SPM_PART_FLAG_PSA_ROT) {
return TFM_PARTITION_PRIVILEGED_MODE;
} else {
return TFM_PARTITION_UNPRIVILEGED_MODE;
}
}
/********************** SPM functions for thread mode ************************/
void tfm_spm_init(void)
{
uint32_t i, num;
struct tfm_spm_ipc_partition_t *partition;
struct tfm_spm_service_t *service;
struct tfm_thrd_ctx *pth, this_thrd;
struct spm_partition_desc_t *part;
tfm_pool_init(conn_handle_pool,
POOL_BUFFER_SIZE(conn_handle_pool),
sizeof(struct tfm_conn_handle_t),
TFM_CONN_HANDLE_MAX_NUM);
tfm_pool_init(spm_service_pool, POOL_BUFFER_SIZE(spm_service_pool),
sizeof(struct tfm_spm_service_t),
TFM_SPM_MAX_ROT_SERV_NUM);
tfm_pool_init(msg_db_pool, POOL_BUFFER_SIZE(msg_db_pool),
sizeof(struct tfm_msg_body_t),
TFM_MSG_QUEUE_MAX_MSG_NUM);
/* Init partition first for it will be used when init service */
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
part = &g_spm_partition_db.partitions[i];
tfm_spm_hal_configure_default_isolation(part->platform_data);
g_spm_ipc_partition[i].index = i;
if ((tfm_spm_partition_get_flags(i) & SPM_PART_FLAG_IPC) == 0) {
continue;
}
g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
tfm_event_init(&g_spm_ipc_partition[i].signal_evnt);
tfm_list_init(&g_spm_ipc_partition[i].service_list);
pth = tfm_spm_partition_get_thread_info_ext(i);
if (!pth) {
tfm_panic();
}
tfm_thrd_init(pth,
tfm_spm_partition_get_init_func_ext(i),
NULL,
(uint8_t *)tfm_spm_partition_get_stack_top(i),
(uint8_t *)tfm_spm_partition_get_stack_bottom(i));
pth->prior = tfm_spm_partition_get_priority_ext(i);
/* Kick off */
if (tfm_thrd_start(pth) != THRD_SUCCESS) {
tfm_panic();
}
}
/* Init Service */
num = sizeof(g_spm_service_db) / sizeof(struct tfm_spm_service_db_t);
for (i = 0; i < num; i++) {
partition =
tfm_spm_get_partition_by_id(g_spm_service_db[i].partition_id);
if (!partition) {
tfm_panic();
}
service = (struct tfm_spm_service_t *)tfm_pool_alloc(spm_service_pool);
if (!service) {
tfm_panic();
}
service->service_db = &g_spm_service_db[i];
service->partition = partition;
tfm_list_init(&service->handle_list);
tfm_list_add_tail(&partition->service_list, &service->list);
}
/*
* All threads initialized, start the scheduler.
*
* NOTE:
* Here is the booting privileged thread mode, and will never
* return to this place after scheduler is started. The start
* function has to save current runtime context to act as a
* 'current thread' to avoid repeating NULL 'current thread'
* checking while context switching. This saved context is worthy
* of being saved somewhere if there are potential usage purpose.
* Let's save this context in a local variable 'this_thrd' at
* current since there is no usage for it.
* Also set tfm_nspm_thread_entry as pfn for this thread to
* use in detecting NS/S thread scheduling changes.
*/
this_thrd.pfn = (tfm_thrd_func_t)tfm_nspm_thread_entry;
tfm_thrd_start_scheduler(&this_thrd);
}
MBED_USED void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb)
{
#if TFM_LVL == 2
struct spm_partition_desc_t *p_next_partition;
uint32_t is_privileged;
#endif
struct tfm_thrd_ctx *pth_next = tfm_thrd_next_thread();
struct tfm_thrd_ctx *pth_curr = tfm_thrd_curr_thread();
if (pth_curr != pth_next) {
#if TFM_LVL == 2
p_next_partition = TFM_GET_CONTAINER_PTR(pth_next,
struct spm_partition_desc_t,
sp_thrd);
if (p_next_partition->static_data.partition_flags &
SPM_PART_FLAG_PSA_ROT) {
is_privileged = TFM_PARTITION_PRIVILEGED_MODE;
} else {
is_privileged = TFM_PARTITION_UNPRIVILEGED_MODE;
}
tfm_spm_partition_change_privilege(is_privileged);
#endif
/* Increase the secure lock, if we enter secure from non-secure */
if ((void *)pth_curr->pfn == (void *)tfm_nspm_thread_entry) {
++tfm_secure_lock;
}
/* Decrease the secure lock, if we return from secure to non-secure */
if ((void *)pth_next->pfn == (void *)tfm_nspm_thread_entry) {
--tfm_secure_lock;
}
tfm_thrd_context_switch(ctxb, pth_curr, pth_next);
}
}

View File

@ -1,181 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_arch_v8m.h"
#include "tfm_thread.h"
#include "tfm_utils.h"
#include "tfm_memory_utils.h"
#include "tfm_svc.h"
#include "spm_api.h"
/* Force ZERO in case ZI(bss) clear is missing */
static struct tfm_thrd_ctx *p_thrd_head = NULL;
static struct tfm_thrd_ctx *p_runn_head = NULL;
static struct tfm_thrd_ctx *p_curr_thrd = NULL;
/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
#define LIST_HEAD p_thrd_head
#define RUNN_HEAD p_runn_head
#define CURR_THRD p_curr_thrd
static struct tfm_thrd_ctx *find_next_running_thread(struct tfm_thrd_ctx *pth)
{
while (pth && pth->status != THRD_STAT_RUNNING) {
pth = pth->next;
}
return pth;
}
/* To get next running thread for scheduler */
struct tfm_thrd_ctx *tfm_thrd_next_thread(void)
{
/*
* First RUNNING thread has highest priority since threads are sorted with
* priority.
*/
return find_next_running_thread(RUNN_HEAD);
}
/* To get current thread for caller */
struct tfm_thrd_ctx *tfm_thrd_curr_thread()
{
return CURR_THRD;
}
/* Insert a new thread into list by descending priority (Highest at head) */
static void insert_by_prior(struct tfm_thrd_ctx **head,
struct tfm_thrd_ctx *node)
{
if (*head == NULL || (node->prior <= (*head)->prior)) {
node->next = *head;
*head = node;
} else {
struct tfm_thrd_ctx *iter = *head;
while (iter->next && (node->prior > iter->next->prior)) {
iter = iter->next;
}
node->next = iter->next;
iter->next = node;
}
}
/*
* Set first running thread as head to reduce enumerate
* depth while searching for a first running thread.
*/
static void update_running_head(struct tfm_thrd_ctx **runn,
struct tfm_thrd_ctx *node)
{
if ((node->status == THRD_STAT_RUNNING) &&
(*runn == NULL || (node->prior < (*runn)->prior))) {
*runn = node;
} else {
*runn = find_next_running_thread(LIST_HEAD);
}
}
/* Set context members only. No validation here */
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
tfm_thrd_func_t pfn, void *param,
uint8_t *sp_base, uint8_t *sp_top)
{
pth->prior = THRD_PRIOR_MEDIUM;
pth->status = THRD_STAT_CREATING;
pth->pfn = pfn;
pth->param = param;
pth->sp_base = sp_base;
pth->sp_top = sp_top;
}
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth)
{
/* Validate parameters before really start */
if ((pth->status != THRD_STAT_CREATING) ||
(pth->pfn == NULL) ||
(pth->sp_base == NULL) ||
(pth->sp_top == NULL)) {
return THRD_ERR_INVALID_PARAM;
}
/* Thread management runs in handler mode; set context for thread mode. */
tfm_initialize_context(&pth->state_ctx,
(uint32_t)pth->param, (uint32_t)pth->pfn,
(uint32_t)pth->sp_base, (uint32_t)pth->sp_top);
/* Insert a new thread with priority */
insert_by_prior(&LIST_HEAD, pth);
/* Mark it as RUNNING after insertion */
tfm_thrd_set_status(pth, THRD_STAT_RUNNING);
return THRD_SUCCESS;
}
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status)
{
TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID);
pth->status = new_status;
update_running_head(&RUNN_HEAD, pth);
}
/* Scheduling won't happen immediately but after the exception returns */
void tfm_thrd_activate_schedule(void)
{
tfm_trigger_pendsv();
}
void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth)
{
/*
* There is no selected thread before scheduler start, assign
* a caller provided thread as current thread. This function
* should get called only ONCE; further calling triggers assert.
*/
TFM_ASSERT(CURR_THRD == NULL);
TFM_ASSERT(pth != NULL);
CURR_THRD = pth;
tfm_thrd_activate_schedule();
}
/* Remove current thread out of the schedulable list */
void tfm_svcall_thrd_exit(void)
{
CURR_THRD->status = THRD_STAT_DETACH;
tfm_trigger_pendsv();
}
__attribute__((section("SFN")))
void tfm_thrd_exit(void)
{
SVC(TFM_SVC_EXIT_THRD);
while (1) {
;
}
}
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
struct tfm_thrd_ctx *prev,
struct tfm_thrd_ctx *next)
{
TFM_ASSERT(prev != NULL);
TFM_ASSERT(next != NULL);
/*
* First, update latest context into the current thread context.
* Then, update background context with next thread's context.
*/
tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
/* Update current thread indicator */
CURR_THRD = next;
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_utils.h"
void tfm_panic(void)
{
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;
}

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "tfm_thread.h"
#include "tfm_utils.h"
#include "tfm_wait.h"
void tfm_event_wait(struct tfm_event_t *pevnt)
{
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
pevnt->owner = tfm_thrd_curr_thread();
tfm_thrd_set_status(pevnt->owner, THRD_STAT_BLOCK);
tfm_thrd_activate_schedule();
}
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval)
{
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
if (pevnt->owner && pevnt->owner->status == THRD_STAT_BLOCK) {
tfm_thrd_set_status(pevnt->owner, THRD_STAT_RUNNING);
tfm_thrd_set_retval(pevnt->owner, retval);
tfm_thrd_activate_schedule();
}
}

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SECURE_UTILITIES_H__
#define __SECURE_UTILITIES_H__
#include <stdio.h>
#include "cmsis_compiler.h"
#include "tfm_svc.h"
#define EXC_RETURN_INDICATOR (0xF << 28)
#define EXC_RETURN_SECURITY_STACK_STATUS_MASK (0x3 << 5)
#define EXC_RETURN_SECURE_STACK (1 << 6)
#define EXC_RETURN_FPU_FRAME_BASIC (1 << 4)
#define EXC_RETURN_MODE_THREAD (1 << 3)
#define EXC_RETURN_STACK_PROCESS (1 << 2)
#define EXC_RETURN_EXC_SECURE (1)
#define EXC_NUM_THREAD_MODE (0)
#define EXC_NUM_SVCALL (11)
#define EXC_NUM_PENDSV (14)
#define EXC_NUM_SYSTICK (15)
#define printf(...)
/* Disable NS exceptions by setting NS PRIMASK to 1 */
#define TFM_NS_EXC_DISABLE() __TZ_set_PRIMASK_NS(1)
/* Enable NS exceptions by setting NS PRIMASK to 0 */
#define TFM_NS_EXC_ENABLE() __TZ_set_PRIMASK_NS(0)
struct tfm_exc_stack_t {
uint32_t R0;
uint32_t R1;
uint32_t R2;
uint32_t R3;
uint32_t R12;
uint32_t LR;
uint32_t RetAddr;
uint32_t XPSR;
};
#ifdef TFM_CORE_DEBUG
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
#else
/* FixMe: redirect to secure log area */
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
#endif
#define LOG_MSG_THR(MSG) \
__ASM volatile("MOV r0, %0\n" \
"SVC %1\n" \
: : "r" (MSG), "I" (TFM_SVC_PRINT))
#define LOG_MSG(MSG) \
do { \
if (__get_active_exc_num()) { \
LOG_MSG_HDLR(MSG); \
} else { \
LOG_MSG_THR(MSG); \
} \
} while (0)
#ifdef TFM_CORE_DEBUG
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
#else
/* FixMe: redirect to secure log area */
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
#endif
/**
* \brief Get Link Register
* \details Returns the value of the Link Register (LR)
* \return LR value
*/
__attribute__ ((always_inline)) __STATIC_INLINE uint32_t __get_LR(void)
{
register uint32_t result;
__ASM volatile ("MOV %0, LR\n" : "=r" (result));
return result;
}
__attribute__ ((always_inline))
__STATIC_INLINE uint32_t __get_active_exc_num(void)
{
IPSR_Type IPSR;
/* if non-zero, exception is active. NOT banked S/NS */
IPSR.w = __get_IPSR();
return IPSR.b.ISR;
}
__attribute__ ((always_inline))
__STATIC_INLINE void __set_CONTROL_SPSEL(uint32_t SPSEL)
{
CONTROL_Type ctrl;
ctrl.w = __get_CONTROL();
ctrl.b.SPSEL = SPSEL;
__set_CONTROL(ctrl.w);
__ISB();
}
#endif /* __SECURE_UTILITIES_H__ */

View File

@ -1,158 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdint.h>
#include "bl2/include/tfm_boot_status.h"
#include "tfm_memory_utils.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "flash_layout.h"
#include "secure_fw/spm/spm_api.h"
#ifdef TFM_PSA_API
#include "tfm_internal_defines.h"
#include "tfm_utils.h"
#include "psa_service.h"
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_spm.h"
#endif
/*!
* \def BOOT_DATA_VALID
*
* \brief Indicates that shared data between bootloader and runtime firmware was
* passed the sanity check with success.
*/
#define BOOT_DATA_VALID (1u)
/*!
* \def BOOT_DATA_INVALID
*
* \brief Indicates that shared data between bootloader and runtime firmware was
* failed on sanity check.
*/
#define BOOT_DATA_INVALID (0u)
/*!
* \var is_boot_data_valid
*
* \brief Indicates the status of shared data between bootloader and runtime
* firmware
*/
static uint32_t is_boot_data_valid = BOOT_DATA_INVALID;
void tfm_core_validate_boot_data(void)
{
struct tfm_boot_data *boot_data;
boot_data = (struct tfm_boot_data *)BOOT_TFM_SHARED_DATA_BASE;
/* FixMe: Enhance sanity check of shared memory area, it might be invalid:
* - temporal exposure of RAM to non-secure actors
* - mismatched addresses
* - version mismatch between bootloader and runtime binary
* - etc.
*/
if (boot_data->header.tlv_magic == SHARED_DATA_TLV_INFO_MAGIC) {
is_boot_data_valid = BOOT_DATA_VALID;
}
}
void tfm_core_get_boot_data_handler(uint32_t args[])
{
uint8_t tlv_major = (uint8_t)args[0];
uint8_t *buf_start = (uint8_t *)args[1];
uint16_t buf_size = (uint16_t)args[2];
uint8_t *ptr;
struct tfm_boot_data *boot_data;
struct shared_data_tlv_entry tlv_entry;
uintptr_t tlv_end, offset;
#ifndef TFM_PSA_API
uint32_t running_partition_idx =
tfm_spm_partition_get_running_partition_idx();
uint32_t res;
#else
struct tfm_spm_ipc_partition_t *partition = NULL;
uint32_t privileged;
#endif
#ifndef TFM_PSA_API
/* Make sure that the output pointer points to a memory area that is owned
* by the partition
*/
res = tfm_core_check_buffer_access(running_partition_idx,
(void *)buf_start,
buf_size,
2); /* Check 4 bytes alignment */
if (!res) {
/* Not in accessible range, return error */
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
#else
partition = tfm_spm_get_running_partition();
if (!partition) {
tfm_panic();
}
privileged = tfm_spm_partition_get_privileged_mode(partition->index);
if (tfm_memory_check(buf_start, buf_size, false, TFM_MEMORY_ACCESS_RW,
privileged) != IPC_SUCCESS) {
/* Not in accessible range, return error */
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
#endif
/* FixMe: Check whether caller has access right to given tlv_major_type */
if (is_boot_data_valid != BOOT_DATA_VALID) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
/* Get the boundaries of TLV section */
boot_data = (struct tfm_boot_data *)BOOT_TFM_SHARED_DATA_BASE;
tlv_end = BOOT_TFM_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
offset = BOOT_TFM_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
/* Add header to output buffer as well */
if (buf_size < SHARED_DATA_HEADER_SIZE) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
} else {
boot_data = (struct tfm_boot_data *)buf_start;
boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
ptr = boot_data->data;
}
/* Iterates over the TLV section and copy TLVs with requested major
* type to the provided buffer.
*/
for (; offset < tlv_end; offset += tlv_entry.tlv_len) {
/* Create local copy to avoid unaligned access */
tfm_memcpy(&tlv_entry,
(const void *)offset,
SHARED_DATA_ENTRY_HEADER_SIZE);
if (GET_MAJOR(tlv_entry.tlv_type) == tlv_major) {
/* Check buffer overflow */
if (((ptr - buf_start) + tlv_entry.tlv_len) > buf_size) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
tfm_memcpy(ptr, (const void *)offset, tlv_entry.tlv_len);
ptr += tlv_entry.tlv_len;
boot_data->header.tlv_tot_len += tlv_entry.tlv_len;
}
}
args[0] = TFM_SUCCESS;
return;
}

View File

@ -1,234 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "region_defs.h"
#include "tfm_core.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "secure_utilities.h"
#include "secure_fw/spm/spm_api.h"
#include "secure_fw/include/tfm_spm_services_api.h"
#ifdef TFM_PSA_API
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_spm.h"
#endif
/*
* Avoids the semihosting issue
* FixMe: describe 'semihosting issue'
*/
#if defined(__ARMCC_VERSION)
__asm(" .global __ARM_use_no_argv\n");
#endif
#if defined ( __GNUC__ )
/* The macro cmse_nsfptr_create defined in the gcc library uses the non-standard
* gcc C lanuage extension 'typeof'. TF-M is built with '-std=c99' so typeof
* cannot be used in the code. As a workaround cmse_nsfptr_create is redefined
* here to use only standard language elements. */
#undef cmse_nsfptr_create
#define cmse_nsfptr_create(p) ((intptr_t) (p) & ~1)
#endif
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
#if (TFM_LVL != 1) && (TFM_LVL != 2) && (TFM_LVL != 3)
#error Only TFM_LVL 1, 2 and 3 are supported!
#endif
#ifndef TFM_PSA_API
/* Macros to pick linker symbols and allow to form the partition data base */
#define REGION(a, b, c) a##b##c
#define REGION_NAME(a, b, c) REGION(a, b, c)
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif
void configure_ns_code(void)
{
/* SCB_NS.VTOR points to the Non-secure vector table base address */
SCB_NS->VTOR = tfm_spm_hal_get_ns_VTOR();
/* Setups Main stack pointer of the non-secure code */
uint32_t ns_msp = tfm_spm_hal_get_ns_MSP();
__TZ_set_MSP_NS(ns_msp);
/* Get the address of non-secure code entry point to jump there */
uint32_t entry_ptr = tfm_spm_hal_get_ns_entry_point();
/* Clears LSB of the function address to indicate the function-call
* will perform the switch from secure to non-secure
*/
ns_entry = (nsfptr_t) cmse_nsfptr_create(entry_ptr);
}
int32_t tfm_core_init(void)
{
/* Enables fault handlers */
enable_fault_handlers();
/* Configures the system reset request properties */
system_reset_cfg();
/* Configures debug authentication */
tfm_spm_hal_init_debug();
__enable_irq();
LOG_MSG("Secure image initializing!");
#ifdef TFM_CORE_DEBUG
printf("TFM level is: %d\r\n", TFM_LVL);
#endif
tfm_core_validate_boot_data();
tfm_spm_hal_init_isolation_hw();
configure_ns_code();
/* Configures all interrupts to retarget NS state, except for
* secure peripherals
*/
nvic_interrupt_target_state_cfg();
/* Enable secure peripherals interrupts */
nvic_interrupt_enable();
#ifdef TFM_PSA_API
/* FixMe: In case of IPC messaging, scratch area must not be referenced
* These variables should be removed when all obsolete references are
* removed from the codebase
*/
tfm_scratch_area = NULL;
tfm_scratch_area_size = 0;
#else
tfm_scratch_area =
(uint8_t *)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
tfm_scratch_area_size =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit) -
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
#endif
return 0;
}
static int32_t tfm_core_set_secure_exception_priorities(void)
{
uint32_t VECTKEY;
SCB_Type *scb = SCB;
uint32_t AIRCR;
/* Set PRIS flag is AIRCR */
AIRCR = scb->AIRCR;
VECTKEY = (~AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
scb->AIRCR = SCB_AIRCR_PRIS_Msk |
VECTKEY |
(AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
/* FixMe: Explicitly set secure fault and Secure SVC priority to highest */
/*
* Set secure PendSV priority to the lowest in SECURE state.
*
* IMPORTANT NOTE:
*
* Although the priority of the secure PendSV must be the lowest possible
* among other interrupts in the Secure state, it must be ensured that
* PendSV is not preempted nor masked by Non-Secure interrupts to ensure
* the integrity of the Secure operation.
* When AIRCR.PRIS is set, the Non-Secure execution can act on
* FAULTMASK_NS, PRIMASK_NS or BASEPRI_NS register to boost its priority
* number up to the value 0x80.
* For this reason, set the priority of the PendSV interrupt to the next
* priority level configurable on the platform, just below 0x80.
*/
NVIC_SetPriority(PendSV_IRQn, (1 << (__NVIC_PRIO_BITS - 1)) - 1);
return TFM_SUCCESS;
}
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx)
{
uint32_t *res_ptr = (uint32_t *)&svc_ctx->R0;
/* FixMe: check if caller partition is permitted to make an SPM request */
switch (svc_ctx->R0) {
case TFM_SPM_REQUEST_RESET_VOTE:
/* FixMe: this is a placeholder for checks to be performed before
* allowing execution of reset
*/
*res_ptr = TFM_SUCCESS;
break;
default:
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
}
}
int main(void)
{
if (tfm_core_init() != 0) {
/* Placeholder for error handling, currently ignored. */
}
if (tfm_spm_db_init() != SPM_ERR_OK) {
/* Placeholder for error handling, currently ignored. */
}
tfm_spm_hal_setup_isolation_hw();
#ifndef TFM_PSA_API
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_RUNNING);
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
__set_PSPLIM(psp_stack_bottom);
if (tfm_spm_partition_init() != SPM_ERR_OK) {
/* Certain systems might refuse to boot altogether if partitions fail
* to initialize. This is a placeholder for such an error handler
*/
}
/*
* Prioritise secure exceptions to avoid NS being able to pre-empt
* secure SVC or SecureFault. Do it before PSA API initialization.
*/
tfm_core_set_secure_exception_priorities();
/* We close the TFM_SP_CORE_ID partition, because its only purpose is
* to be able to pass the state checks for the tests started from secure.
*/
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_CLOSED);
tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
SPM_PARTITION_STATE_RUNNING);
#ifdef TFM_CORE_DEBUG
/* Jumps to non-secure code */
LOG_MSG("Jumping to non-secure code...");
#endif
jump_to_ns_code();
#else
/*
* Prioritise secure exceptions to avoid NS being able to pre-empt
* secure SVC or SecureFault. Do it before PSA API initialization.
*/
tfm_core_set_secure_exception_priorities();
tfm_spm_init();
#endif
}

View File

@ -1,18 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_CORE_H__
#define __TFM_CORE_H__
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "secure_utilities.h"
extern uint32_t tfm_scratch_area_size;
extern uint8_t *tfm_scratch_area;
#endif /* __TFM_CORE_H__ */

View File

@ -1,225 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <string.h>
#include "secure_utilities.h"
#include "tfm_svc.h"
#include "tfm_secure_api.h"
#include "region_defs.h"
#include "tfm_api.h"
#include "tfm_internal.h"
#include "tfm_memory_utils.h"
#ifdef TFM_PSA_API
#include <stdbool.h>
#include "tfm_svcalls.h"
#endif
#include "platform/mbed_toolchain.h"
/* This SVC handler is called when a secure partition requests access to a
* buffer area
*/
extern int32_t tfm_core_set_buffer_area_handler(const uint32_t args[]);
#ifdef TFM_PSA_API
extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
#endif
struct tfm_fault_context_s {
uint32_t R0;
uint32_t R1;
uint32_t R2;
uint32_t R3;
uint32_t R12;
uint32_t LR;
uint32_t ReturnAddress;
uint32_t RETPSR;
} tfm_fault_context;
#if defined(__ARM_ARCH_8M_MAIN__)
/**
* \brief Overwrites default Secure fault handler.
*/
void SecureFault_Handler(void)
{
/* figure out context from which we landed in fault handler */
uint32_t lr = __get_LR();
uint32_t sp;
if (lr & EXC_RETURN_SECURE_STACK) {
if (lr & EXC_RETURN_STACK_PROCESS) {
sp = __get_PSP();
} else {
sp = __get_MSP();
}
} else {
if (lr & EXC_RETURN_STACK_PROCESS) {
sp = __TZ_get_PSP_NS();
} else {
sp = __TZ_get_MSP_NS();
}
}
/* Only save the context if sp is valid */
if ((sp >= S_DATA_START &&
sp <= (S_DATA_LIMIT - sizeof(tfm_fault_context)) + 1) ||
(sp >= NS_DATA_START &&
sp <= (NS_DATA_LIMIT - sizeof(tfm_fault_context)) + 1)) {
tfm_memcpy(&tfm_fault_context,
(const void *)sp,
sizeof(tfm_fault_context));
}
LOG_MSG("Oops... Secure fault!!! You're not going anywhere!");
while (1) {
;
}
}
#elif defined(__ARM_ARCH_8M_BASE__)
/**
* \brief Overwrites default Hard fault handler.
*
* In case of a baseline implementation fault conditions that would generate a
* SecureFault in a mainline implementation instead generate a Secure HardFault.
*/
void HardFault_Handler(void)
{
/* In a baseline implementation there is no way, to find out whether this is
* a hard fault triggered directly, or another fault that has been
* escalated.
*/
while (1) {
;
}
}
#else
#error "Unsupported ARM Architecture."
#endif
#if defined(__ARM_ARCH_8M_MAIN__)
__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"
);
}
#elif defined(__ARM_ARCH_8M_BASE__)
__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"
);
}
#else
#error "Unsupported ARM Architecture."
#endif
MBED_USED uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr)
{
uint8_t svc_number;
/*
* Stack contains:
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
* First argument (r0) is svc_args[0]
*/
if (lr & EXC_RETURN_SECURE_STACK) {
/* SV called directly from secure context. Check instruction for
* svc_number
*/
svc_number = ((uint8_t *)svc_args[6])[-2];
} else {
/* Secure SV executing with NS return.
* NS cannot directly trigger S SVC so this should not happen
* FixMe: check for security implications
*/
return lr;
}
switch (svc_number) {
#ifdef TFM_PSA_API
case TFM_SVC_IPC_REQUEST:
tfm_psa_ipc_request_handler(svc_args);
break;
case TFM_SVC_SCHEDULE:
case TFM_SVC_EXIT_THRD:
case TFM_SVC_PSA_FRAMEWORK_VERSION:
case TFM_SVC_PSA_VERSION:
case TFM_SVC_PSA_CONNECT:
case TFM_SVC_PSA_CALL:
case TFM_SVC_PSA_CLOSE:
case TFM_SVC_PSA_WAIT:
case TFM_SVC_PSA_GET:
case TFM_SVC_PSA_SET_RHANDLE:
case TFM_SVC_PSA_READ:
case TFM_SVC_PSA_SKIP:
case TFM_SVC_PSA_WRITE:
case TFM_SVC_PSA_REPLY:
case TFM_SVC_PSA_NOTIFY:
case TFM_SVC_PSA_CLEAR:
case TFM_SVC_PSA_EOI:
svc_args[0] = SVC_Handler_IPC(svc_number, svc_args, lr);
break;
#else
case TFM_SVC_SFN_REQUEST:
lr = tfm_core_partition_request_svc_handler(svc_args, lr);
break;
case TFM_SVC_SFN_RETURN:
lr = tfm_core_partition_return_handler(lr);
break;
case TFM_SVC_VALIDATE_SECURE_CALLER:
tfm_core_validate_secure_caller_handler(svc_args);
break;
case TFM_SVC_GET_CALLER_CLIENT_ID:
tfm_core_get_caller_client_id_handler(svc_args);
break;
case TFM_SVC_SPM_REQUEST:
tfm_core_spm_request_handler((struct tfm_exc_stack_t *)svc_args);
break;
case TFM_SVC_MEMORY_CHECK:
tfm_core_memory_permission_check_handler(svc_args);
break;
case TFM_SVC_SET_SHARE_AREA:
tfm_core_set_buffer_area_handler(svc_args);
break;
#endif
case TFM_SVC_PRINT:
printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
break;
case TFM_SVC_GET_BOOT_DATA:
tfm_core_get_boot_data_handler(svc_args);
break;
default:
LOG_MSG("Unknown SVC number requested!");
break;
}
return lr;
}
void tfm_access_violation_handler(void)
{
while (1) {
;
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "secure_utilities.h"
#ifndef __TFM_INTERNAL_H__
#define __TFM_INTERNAL_H__
/*
* This function pointer is meant to only hold non secure function pointers.
* It will be turned into a non-secure one (LSB cleared) before being called
* whatever happens anyway (unless cast to another function pointer type).
* Registers will be cleared before branching so that no information leaks
* from secure to non-secure world.
*/
typedef void __attribute__((cmse_nonsecure_call)) (*nsfptr_t) (void);
extern nsfptr_t ns_entry;
/**
* \brief Signal that secure partition initialisation is finished
*/
void tfm_secure_api_init_done(void);
/**
* \brief Jumps to non-secure code.
*/
void jump_to_ns_code(void);
/**
* \brief Called if veneer is running in thread mode
*/
uint32_t tfm_core_partition_request_svc_handler(
const uint32_t *svc_args, uint32_t lr);
/**
* \brief Called when secure service returns
*/
uint32_t tfm_core_partition_return_handler(uint32_t lr);
/**
* \brief Called by secure service to check if client is secure
*/
void tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
/**
* \brief Stores caller's client id in state context
*/
void tfm_core_get_caller_client_id_handler(const uint32_t svc_args[]);
/**
* \brief Checks if a secure service's access to a memory location is permitted
*/
void tfm_core_memory_permission_check_handler(const uint32_t svc_args[]);
/**
* \brief Handle an SPM request by a secure service
*/
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx);
/**
* \brief Check whether a buffer is ok for writing to by the privileged API
* function.
*
* This function checks whether the caller partition owns the buffer, can write
* to it, and the buffer has proper alignment.
*
* \param[in] partition_idx Partition index
* \param[in] start_addr The start address of the buffer
* \param[in] len The length of the buffer
* \param[in] alignment The expected alignment (in bits)
*
* \return 1 if the check passes, 0 otherwise.
*
* \note For a 0 long buffer the check fails.
*/
int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
void *start_addr,
size_t len,
uint32_t alignment);
/**
* \brief Retrieve secure partition related data from shared memory area, which
* stores shared data between bootloader and runtime firmware.
*
* \param[in] args Pointer to stack frame, which carries input parameters.
*/
void tfm_core_get_boot_data_handler(uint32_t args[]);
/**
* \brief Validate the content of shared memory area, which stores the shared
* data between bootloader and runtime firmware.
*/
void tfm_core_validate_boot_data(void);
#endif /* __TFM_INTERNAL_H__ */

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_MEMORY_UTILS_H__
#define __TFM_MEMORY_UTILS_H__
#include <string.h>
#include "cmsis_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
/* FIXME: The following functions are wrappers around standard C library
* functions: memcpy, memcmp, memset
* In long term standard C library might be removed from TF-M project or
* replaced with a secure implementation due to security concerns.
*/
__attribute__ ((always_inline)) __STATIC_INLINE
void *tfm_memcpy(void *dest, const void *src, size_t num)
{
return (memcpy(dest, src, num));
}
__attribute__ ((always_inline)) __STATIC_INLINE
int tfm_memcmp(const void *ptr1, const void *ptr2, size_t num)
{
return (memcmp(ptr1, ptr2, num));
}
__attribute__ ((always_inline)) __STATIC_INLINE
void *tfm_memset(void *ptr, int value, size_t num)
{
return (memset(ptr, value, num));
}
#ifdef __cplusplus
}
#endif
#endif /* __TFM_MEMORY_UTILS_H__ */

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <stdbool.h>
#include "secure_utilities.h"
#include "tfm_api.h"
#ifdef TFM_PSA_API
#include "tfm_utils.h"
#include "tfm_internal.h"
#endif
#ifndef TFM_MAX_NS_THREAD_COUNT
#define TFM_MAX_NS_THREAD_COUNT 8
#endif
#define INVALID_CLIENT_ID 0
#define DEFAULT_NS_CLIENT_ID ((int32_t)-1)
#define INVALID_NS_CLIENT_IDX (-1)
#define DEFAULT_NS_CLIENT_IDX 0
typedef uint32_t TZ_ModuleId_t;
typedef uint32_t TZ_MemoryId_t;
static struct ns_client_list_t {
int32_t ns_client_id;
int32_t next_free_index;
} NsClientIdList[TFM_MAX_NS_THREAD_COUNT];
static int32_t free_index = 0U;
static int32_t active_ns_client_idx = INVALID_NS_CLIENT_IDX;
static int get_next_ns_client_id()
{
#ifdef TFM_NS_CLIENT_IDENTIFICATION
static int32_t next_ns_client_id = DEFAULT_NS_CLIENT_ID;
if (next_ns_client_id > 0)
{
next_ns_client_id = DEFAULT_NS_CLIENT_ID;
}
return next_ns_client_id--;
#else
return DEFAULT_NS_CLIENT_ID;
#endif
}
void tfm_nspm_configure_clients(void)
{
int32_t i;
/* Default to one NS client */
free_index = 1;
NsClientIdList[0].ns_client_id = get_next_ns_client_id();
for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
}
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
}
int32_t tfm_nspm_get_current_client_id()
{
if (active_ns_client_idx == INVALID_NS_CLIENT_IDX)
{
return 0;
} else {
return NsClientIdList[active_ns_client_idx].ns_client_id;
}
}
/* TF-M implementation of the CMSIS TZ RTOS thread context management API */
/// Initialize secure context memory system
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_InitContextSystem_S(void)
{
int32_t i;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
/* NS RTOS supports TZ context management, override defaults */
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("NS RTOS initialized TZ RTOS context management");
#endif /* PRINT_NSPM_DEBUG */
for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
NsClientIdList[i].next_free_index = i + 1;
}
/* Terminate list */
NsClientIdList[i - 1].next_free_index = INVALID_NS_CLIENT_IDX;
/* Success */
return 1U;
}
/// Allocate context memory for calling secure software modules in TrustZone
/// \param[in] module identifies software modules called from non-secure mode
/// \return value != 0 id TrustZone memory slot identifier
/// \return value 0 no memory available or internal error
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module)
{
TZ_MemoryId_t tz_id;
(void) module; /* Currently unused */
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
if (free_index < 0) {
/* No more free slots */
return 0U;
}
/* TZ_MemoryId_t must be a positive integer */
tz_id = (TZ_MemoryId_t)free_index + 1;
NsClientIdList[free_index].ns_client_id = get_next_ns_client_id();
#ifdef PRINT_NSPM_DEBUG
printf("TZ_AllocModuleContext_S called, returning id %d\r\n",
NsClientIdList[free_index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
free_index = NsClientIdList[free_index].next_free_index;
return tz_id;
}
/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
printf("TZ_FreeModuleContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
if (active_ns_client_idx == index) {
#ifdef PRINT_NSPM_DEBUG
printf("Freeing active NS client, NS inactive\r\n");
#endif /* PRINT_NSPM_DEBUG */
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
}
NsClientIdList[index].ns_client_id = INVALID_CLIENT_ID;
NsClientIdList[index].next_free_index = free_index;
free_index = index;
return 1U; // Success
}
/// Load secure context (called on RTOS thread context switch)
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_LoadContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("TZ_LoadContext_S called");
#endif /* PRINT_NSPM_DEBUG */
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
active_ns_client_idx = index;
#ifdef PRINT_NSPM_DEBUG
printf("TZ_LoadContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return 1U; // Success
}
/// Store secure context (called on RTOS thread context switch)
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_StoreContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("TZ_StoreContext_S called");
#endif /* PRINT_NSPM_DEBUG */
/* id corresponds to context being swapped out on NS side */
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
if (active_ns_client_idx != index) {
#ifdef PRINT_NSPM_DEBUG
printf("TZ_StoreContext_S called for id %d, active id: %d\r\n",
NsClientIdList[index].ns_client_id,
NsClientIdList[active_ns_client_idx].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
printf("TZ_StoreContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
return 1U; // Success
}
#ifdef TFM_NS_CLIENT_IDENTIFICATION
__attribute__((cmse_nonsecure_entry))
enum tfm_status_e tfm_register_client_id (int32_t ns_client_id)
{
int current_client_id;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return TFM_ERROR_NS_THREAD_MODE_CALL;
}
if (ns_client_id >= 0) {
/* The client ID is invalid */
return TFM_ERROR_INVALID_PARAMETER;
}
if (active_ns_client_idx < 0) {
/* No client is active */
return TFM_ERROR_GENERIC;
}
current_client_id = NsClientIdList[active_ns_client_idx].ns_client_id;
if (current_client_id >= 0 ) {
/* The client ID is invalid */
return TFM_ERROR_INVALID_PARAMETER;
}
NsClientIdList[active_ns_client_idx].ns_client_id = ns_client_id;
#ifdef PRINT_NSPM_DEBUG
printf("tfm_register_client_id called with id %d\r\n", ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return TFM_SUCCESS;
}
#endif
#ifdef TFM_PSA_API
__attribute__((section("SFN")))
psa_status_t tfm_nspm_thread_entry(void)
{
#ifdef TFM_CORE_DEBUG
/* Jumps to non-secure code */
LOG_MSG("Jumping to non-secure code...");
#endif
jump_to_ns_code();
/* Should not run here */
TFM_ASSERT(false);
return PSA_SUCCESS;
}
#endif

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_NSPM_H__
#define __TFM_NSPM_H__
#include <stdint.h>
/**
* \brief initialise the NS context database
*/
void tfm_nspm_configure_clients(void);
/**
* \brief Get the client ID of the current NS client
*
* \return The client id of the current NS client. 0 (invalid client id) is
* returned in case of error.
*/
int32_t tfm_nspm_get_current_client_id(void);
#ifdef TFM_PSA_API
/**
* \brief NSPM thread main entry function
*
* \return PSA_SUCCESS indicates failed.
*
* Note: This function should not return back.
*/
psa_status_t tfm_nspm_thread_entry(void);
#endif
#endif /* __TFM_NSPM_H__ */

View File

@ -1,24 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_PLATFORM_CORE_API_H__
#define __TFM_PLATFORM_CORE_API_H__
/**
* \brief Should be called in case of access violation.
*
* There might be platform specific means, by which it is possible on a
* subsystem to detect access violation. For example a platform can have a
* Peripheral Protection Controller, to detect unauthorised accesses to
* peripheral registers. Setting up the protection, and handling the violation
* is implemented in platform specific code. However TF-M should be able to
* decide how to proceed if a violation happens. So to notify TF-M, platform
* code have to call this function, if a violation happens.
*/
void tfm_access_violation_handler(void);
#endif /* __TFM_PLATFORM_CORE_API_H__ */

View File

@ -1,176 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <arm_cmse.h>
#include "tfm_secure_api.h"
#include "tfm_nspm.h"
#include "secure_utilities.h"
#include "secure_fw/spm/spm_api.h"
#include "region_defs.h"
#include "tfm_api.h"
#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
/* Macros to pick linker symbols and allow references to sections */
#define REGION(a, b, c) a##b##c
#define REGION_NAME(a, b, c) REGION(a, b, c)
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif /* !defined(TFM_PSA_API) */
/* This is the "Big Lock" on the secure side, to guarantee single entry
* to SPE
*/
int32_t tfm_secure_lock;
/**
* \brief Check whether a memory range is inside a memory region.
*
* \param[in] p The start address of the range to check
* \param[in] s The size of the range to check
* \param[in] region_start The start address of the region, which should
* contain the range
* \param[in] region_len The size of the region, which should contain the
* range
*
* \return TFM_SUCCESS if the region contains the range,
* TFM_ERROR_GENERIC otherwise.
*/
static int32_t check_address_range(const void *p, size_t s,
uintptr_t region_start, uint32_t region_len)
{
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)p+s <= region_start+region_len);
if (range_in_region) {
return TFM_SUCCESS;
} else {
return TFM_ERROR_GENERIC;
}
}
/**
* \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 int32_t has_access_to_region(const void *p, size_t s, int flags)
{
int32_t range_access_allowed_by_mpu;
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
uint32_t scratch_base =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
uint32_t scratch_limit =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif /* !defined(TFM_PSA_API) */
/* 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;
}
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
/* If the check for the current MPU settings fails, check for the share
* region, only if the partition is secure
*/
if ((flags & CMSE_NONSECURE) == 0) {
if (check_address_range(p, s, scratch_base,
scratch_limit+1-scratch_base) == TFM_SUCCESS) {
return TFM_SUCCESS;
}
}
#endif /* !defined(TFM_PSA_API) */
/* If all else fails, check whether the region is in the non-secure
* memory
*/
if (check_address_range(p, s, NS_CODE_START,
NS_CODE_LIMIT+1-NS_CODE_START) == TFM_SUCCESS ||
check_address_range(p, s, NS_DATA_START,
NS_DATA_LIMIT+1-NS_DATA_START) == TFM_SUCCESS) {
return TFM_SUCCESS;
} else {
return TFM_ERROR_GENERIC;
}
}
int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged)
{
int flags = CMSE_MPU_READ;
if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
flags |= CMSE_MPU_UNPRIV;
}
if (ns_caller) {
flags |= CMSE_NONSECURE;
}
return has_access_to_region(p, s, flags);
}
int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged)
{
int flags = CMSE_MPU_READWRITE;
if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
flags |= CMSE_MPU_UNPRIV;
}
if (ns_caller) {
flags |= CMSE_NONSECURE;
}
return has_access_to_region(p, s, flags);
}
void tfm_secure_api_error_handler(void)
{
ERROR_MSG("Security violation when calling secure API");
while (1) {
;
}
}

View File

@ -1,214 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SECURE_API_H__
#define __TFM_SECURE_API_H__
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "secure_utilities.h"
#include "tfm_core.h"
#include "tfm_api.h"
#include "bl2/include/tfm_boot_status.h"
/*!
* \def __tfm_secure_gateway_attributes__
*
* \brief Attributes for secure gateway functions
*/
#define __tfm_secure_gateway_attributes__ \
__attribute__((cmse_nonsecure_entry, noinline, section("SFN")))
/* Hide specific errors if not debugging */
#ifdef TFM_CORE_DEBUG
#define TFM_ERROR_STATUS(status) (status)
#else
#define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY)
#endif
#define TFM_SFN_API_LEGACY 0
#define TFM_SFN_API_IOVEC 1
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
extern void tfm_secure_api_error_handler(void);
typedef int32_t(*sfn_t)(int32_t, int32_t, int32_t, int32_t);
struct tfm_sfn_req_s {
uint32_t sp_id;
sfn_t sfn;
int32_t *args;
uint32_t caller_part_idx;
int32_t iovec_api;
uint32_t ns_caller;
};
enum tfm_buffer_share_region_e {
TFM_BUFFER_SHARE_DISABLE,
TFM_BUFFER_SHARE_NS_CODE,
TFM_BUFFER_SHARE_SCRATCH,
TFM_BUFFER_SHARE_PRIV, /* only for TCB in level 2, all in level 1 */
TFM_BUFFER_SHARE_DEFAULT,
};
enum tfm_ns_region_e {
TFM_NS_REGION_CODE = 0,
TFM_NS_REGION_DATA,
TFM_NS_REGION_VENEER,
TFM_NS_REGION_PERIPH_1,
TFM_NS_REGION_PERIPH_2,
TFM_NS_SECONDARY_IMAGE_REGION,
};
enum tfm_memory_access_e {
TFM_MEMORY_ACCESS_RO = 1,
TFM_MEMORY_ACCESS_RW = 2,
};
extern int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share);
extern int32_t tfm_core_validate_secure_caller(void);
extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
extern int32_t tfm_core_memory_permission_check(const void *ptr,
uint32_t size,
int32_t access);
extern int32_t tfm_core_get_boot_data(uint8_t major_type,
struct tfm_boot_data *boot_data,
uint32_t len);
int32_t tfm_core_sfn_request(const struct tfm_sfn_req_s *desc_ptr);
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
/**
* \brief Check whether the current partition has read access to a memory range
*
* This function assumes, that the current MPU configuration is set for the
* partition to be checked.
*
* \param[in] p The start address of the range to check
* \param[in] s The size of the range to check
* \param[in] ns_caller Whether the current partition is a non-secure one
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \return TFM_SUCCESS if the partition has access to the memory range,
* TFM_ERROR_GENERIC otherwise.
*/
int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged);
/**
* \brief Check whether the current partition has write access to a memory range
*
* This function assumes, that the current MPU configuration is set for the
* partition to be checked.
*
* \param[in] p The start address of the range to check
* \param[in] s The size of the range to check
* \param[in] ns_caller Whether the current partition is a non-secure one
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \return TFM_SUCCESS if the partition has access to the memory range,
* TFM_ERROR_GENERIC otherwise.
*/
int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged);
#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
*/
#define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
do { \
ERROR_MSG("Invalid TF-M configuration detected"); \
tfm_secure_api_error_handler(); \
/* This point never reached */ \
return (int32_t)TFM_ERROR_GENERIC; \
} while (0)
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
do { \
ERROR_MSG("Invalid TF-M configuration detected"); \
tfm_secure_api_error_handler(); \
/* This point never reached */ \
return (int32_t)TFM_ERROR_GENERIC; \
} while (0)
#else
#define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
return tfm_core_partition_request(id, fn, TFM_SFN_API_IOVEC, \
(int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d)
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
return tfm_core_partition_request(id, fn, TFM_SFN_API_LEGACY, \
(int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d)
__attribute__ ((always_inline)) __STATIC_INLINE
int32_t tfm_core_partition_request(uint32_t id, void *fn, int32_t iovec_api,
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;
/*
* This preprocessor condition checks if a version of GCC smaller than
* 7.3.1 is being used to compile the code.
* These versions are affected by a bug on the cmse_nonsecure_caller
* intrinsic which returns incorrect results.
* Please check Bug 85203 on GCC Bugzilla for more information.
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION) && \
(__GNUC__ < 7 || \
(__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || \
(__GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ < 1))))
/*
* Use the fact that, if called from Non-Secure, the LSB of the return
* address is set to 0.
*/
desc.ns_caller = (uint32_t)!(
(intptr_t)__builtin_extract_return_addr(__builtin_return_address(0U))
& 1);
#else
/*
* Convert the result of cmse_nonsecure_caller from an int to a uint32_t
* to prevent using an int in the tfm_sfn_req_s structure.
*/
desc.ns_caller = (cmse_nonsecure_caller() != 0) ? 1U : 0U;
#endif /* Check for GCC compiler version smaller than 7.3.1 */
desc.iovec_api = iovec_api;
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
/* FixMe: Error severity TBD */
return TFM_ERROR_GENERIC;
} else {
#if TFM_LVL == 1
if (desc.ns_caller) {
return tfm_core_sfn_request(desc_ptr);
} else {
return tfm_core_sfn_request_thread_mode(desc_ptr);
}
#else
return tfm_core_sfn_request(desc_ptr);
#endif
}
}
#endif
#endif /* __TFM_SECURE_API_H__ */

View File

@ -1,166 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "tfm_secure_api.h"
#include "tfm_internal.h"
#include "secure_fw/include/tfm_spm_services_api.h"
#include "spm_api.h"
uint8_t *tfm_scratch_area;
uint32_t tfm_scratch_area_size;
nsfptr_t ns_entry;
void jump_to_ns_code(void)
{
#if TFM_LVL == 3 || ((!defined(TFM_PSA_API)) && (TFM_LVL != 1))
/* Initialization is done, set thread mode to unprivileged. */
tfm_spm_partition_change_privilege(TFM_PARTITION_UNPRIVILEGED_MODE);
#endif
/* All changes made to memory will be effective after this point */
__DSB();
__ISB();
/* Calls the non-secure Reset_Handler to jump to the non-secure binary */
ns_entry();
}
#ifndef TFM_PSA_API
#if defined(__ARM_ARCH_8M_MAIN__)
__attribute__((naked)) int32_t tfm_core_sfn_request(
const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile(
"PUSH {r4-r12, lr}\n"
"SVC %[SVC_REQ]\n"
"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"
"BLX lr\n"
"SVC %[SVC_RET]\n"
"POP {r4-r12, pc}\n"
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) int32_t tfm_core_sfn_request(
const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile(
".syntax unified\n"
"PUSH {lr}\n"
"PUSH {r4-r7}\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"
"SVC %[SVC_REQ]\n"
"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"
"BLX lr\n"
"SVC %[SVC_RET]\n"
"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}\n"
"POP {pc}\n"
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
#else
#error "Unsupported ARM Architecture."
#endif
__attribute__((naked))
int32_t tfm_core_memory_permission_check(const void *ptr,
uint32_t len,
int32_t access)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_MEMORY_CHECK));
}
__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_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_spm_request(void)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_SPM_REQUEST));
}
__attribute__((naked))
int32_t tfm_core_validate_secure_caller(void)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_VALIDATE_SECURE_CALLER));
}
__attribute__((naked))
int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_SET_SHARE_AREA));
}
#endif
__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));
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SVC_H__
#define __TFM_SVC_H__
#include "cmsis.h"
typedef enum {
TFM_SVC_SFN_REQUEST = 0,
TFM_SVC_SFN_RETURN,
TFM_SVC_VALIDATE_SECURE_CALLER,
TFM_SVC_GET_CALLER_CLIENT_ID,
TFM_SVC_MEMORY_CHECK,
TFM_SVC_SET_SHARE_AREA,
TFM_SVC_SPM_REQUEST,
TFM_SVC_PRINT,
TFM_SVC_GET_BOOT_DATA,
#ifdef TFM_PSA_API
TFM_SVC_IPC_REQUEST,
TFM_SVC_SCHEDULE,
TFM_SVC_EXIT_THRD,
/* PSA Client SVC */
TFM_SVC_PSA_FRAMEWORK_VERSION,
TFM_SVC_PSA_VERSION,
TFM_SVC_PSA_CONNECT,
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,
TFM_SVC_PSA_SKIP,
TFM_SVC_PSA_WRITE,
TFM_SVC_PSA_REPLY,
TFM_SVC_PSA_NOTIFY,
TFM_SVC_PSA_CLEAR,
TFM_SVC_PSA_EOI,
#endif
} tfm_svc_number_t;
#define SVC(code) __ASM volatile("svc %0" : : "I" (code))
#endif /* __TFM_SVC_H__ */

View File

@ -1,17 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
//This file holds description for the current directory. This documentation
//will be included in the Doxygen output.
/*!
\dir
\brief Include files for the TF-M.
\details This directory currently only holds the include file for the SPM
module.
*/

View File

@ -1,22 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_SERVICES_API_H__
#define __TFM_SPM_SERVICES_API_H__
enum tfm_spm_request_type_t {
TFM_SPM_REQUEST_RESET_VOTE,
};
/**
* \brief Request a vote from SPM on a system reset
*
* \return Returns 0 if request is accepted, any other value means reject
*/
int32_t tfm_spm_request_reset_vote(void);
#endif /* __TFM_SPM_SERVICES_API_H__ */

View File

@ -1,134 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdbool.h>
#include <stdio.h>
#include "psa_client.h"
#include "psa_service.h"
#include "secure_utilities.h"
#include "tfm_secure_api.h"
#include "tfm_api.h"
#include "tfm_svcalls.h"
/* FixMe: check if this is really needed */
extern int32_t tfm_secure_lock;
__attribute__ ((always_inline)) __STATIC_INLINE
int32_t tfm_psa_veneer_sanity_check(struct tfm_sfn_req_s *desc_ptr)
{
if (desc_ptr->ns_caller) {
if (tfm_secure_lock != 0) {
/* Secure domain is already locked!
* FixMe: Decide if this is a fault or permitted in case of PSA
* API usage
*/
return TFM_ERROR_SECURE_DOMAIN_LOCKED;
}
} else {
/* Secure partition should not call a different secure partition
* using TFM PSA veneers
*/
return TFM_ERROR_INVALID_EXC_MODE;
}
return TFM_SUCCESS;
}
/* Veneer implementation */
#define TFM_CORE_NS_IPC_REQUEST_VENEER(fn, a, b, c, d) \
return tfm_core_ns_ipc_request(fn, (int32_t)a, (int32_t)b, \
(int32_t)c, (int32_t)d)
__attribute__ ((naked, section("SFN")))
static int32_t tfm_core_ipc_request(const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_IPC_REQUEST));
}
__attribute__ ((always_inline)) __STATIC_INLINE
int32_t tfm_core_ns_ipc_request(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 = {0};
desc.sfn = fn;
desc.args = args;
desc.ns_caller = cmse_nonsecure_caller();
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE)
{
/* FIXME: Proper error handling to be implemented */
return TFM_ERROR_INVALID_EXC_MODE;
} else {
return tfm_core_ipc_request(&desc);
}
}
/* FixMe: these functions need to have different attributes compared to those
* legacy veneers which may be called by secure partitions.
* They won't call legacy SFN but instead will be handlers for TF-M
*/
__tfm_secure_gateway_attributes__
uint32_t tfm_psa_framework_version_veneer(void)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_framework_version, 0, 0,
0, 0);
}
__tfm_secure_gateway_attributes__
uint32_t tfm_psa_version_veneer(uint32_t sid)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_version, sid, 0, 0, 0);
}
__tfm_secure_gateway_attributes__
psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_connect, sid,
minor_version, 0, 0);
}
__tfm_secure_gateway_attributes__
psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
const psa_invec *in_vecs,
psa_outvec *out_vecs)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_call, handle, in_vecs,
out_vecs, 0);
}
__tfm_secure_gateway_attributes__
psa_status_t tfm_psa_close_veneer(psa_handle_t handle)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_close, handle, 0, 0, 0);
}
void tfm_psa_ipc_request_handler(uint32_t svc_ctx[])
{
uint32_t *r0_ptr = svc_ctx;
/* The only argument to the SVC call is stored in the stacked r0 */
struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) *r0_ptr;
if(tfm_psa_veneer_sanity_check(desc_ptr) != TFM_SUCCESS) {
/* FixMe: consider error handling - this may be critical error */
*r0_ptr = TFM_ERROR_INVALID_PARAMETER;
return;
}
/* Store SVC return value in stacked r0 */
*r0_ptr = desc_ptr->sfn((int32_t)desc_ptr->args,
desc_ptr->ns_caller,
0,
0);
return;
}

View File

@ -1,16 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
//This file holds description for the current directory. This documentation
//will be included in the Doxygen output.
/*!
\dir
\brief Source code for the Secure Partition Manager.
\details This directory holds the source code of the "TF-M SPM" module.
*/

View File

@ -1,416 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/* This file contains the APIs exported by the SPM to tfm core */
#include <stdio.h>
#include <string.h>
#include "spm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "tfm_memory_utils.h"
#include "spm_db_setup.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "tfm_nspm.h"
#include "secure_fw/core/tfm_core.h"
#include "tfm_peripherals_def.h"
#include "spm_partition_defs.h"
struct spm_partition_db_t g_spm_partition_db = {0,};
typedef enum {
TFM_INIT_FAILURE,
} sp_error_type_t;
/*
* 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
* returned.
*/
#ifndef TFM_PSA_API
static void tfm_spm_partition_err_handler(
const struct spm_partition_desc_t *partition,
sp_error_type_t err_type,
int32_t err_code)
{
#ifdef TFM_CORE_DEBUG
if (err_type == TFM_INIT_FAILURE) {
printf("Partition init failed for partition id 0x%08X\r\n",
partition->static_data.partition_id);
} else {
printf(
"Unknown partition error %d (code: %d) for partition id 0x%08X\r\n",
err_type, err_code, partition->static_data.partition_id);
}
#else
(void)err_type;
(void)err_code;
#endif
tfm_spm_partition_set_state(partition->static_data.partition_id,
SPM_PARTITION_STATE_CLOSED);
}
#endif /* !defined(TFM_PSA_API) */
/*
* This function prevents name clashes between the variable names accessibles in
* the scope of where tfm_partition_list.inc is included and the varaible names
* defined inside tfm_partition_list.inc file.
*/
static inline enum spm_err_t add_user_defined_partitions(void) {
#include "tfm_partition_list.inc"
return SPM_ERR_OK;
}
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)
{
struct spm_partition_desc_t *part_ptr;
enum spm_err_t err;
(void)tfm_memset (&g_spm_partition_db, 0, sizeof(g_spm_partition_db));
/* This function initialises partition db */
g_spm_partition_db.running_partition_idx = SPM_INVALID_PARTITION_IDX;
g_spm_partition_db.partition_count = 0;
/* There are a few partitions that are used by TF-M internally.
* These are explicitly added to the partition db here.
*/
/* For the non secure Execution environment */
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[];
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
uint32_t psp_stack_top = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Limit;
#endif
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
g_spm_partition_db.partition_count]);
part_ptr->static_data.partition_id = TFM_SP_NON_SECURE_ID;
#ifdef TFM_PSA_API
part_ptr->static_data.partition_flags = SPM_PART_FLAG_APP_ROT |
SPM_PART_FLAG_IPC;
part_ptr->static_data.partition_priority = TFM_PRIORITY_LOW;
part_ptr->static_data.partition_init = tfm_nspm_thread_entry;
#else
part_ptr->static_data.partition_flags = 0;
#endif
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
part_ptr->memory_data.stack_bottom = psp_stack_bottom;
part_ptr->memory_data.stack_top = psp_stack_top;
/* Since RW, ZI and stack are configured as one MPU region, configure
* RW start address to psp_stack_bottom to get RW access to stack
*/
part_ptr->memory_data.rw_start = psp_stack_bottom;
#endif
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
tfm_nspm_configure_clients();
++g_spm_partition_db.partition_count;
/* For the TF-M core environment itself */
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
g_spm_partition_db.partition_count]);
part_ptr->static_data.partition_id = TFM_SP_CORE_ID;
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;
++g_spm_partition_db.partition_count;
err = add_user_defined_partitions();
if (err != SPM_ERR_OK) {
return err;
}
g_spm_partition_db.is_init = 1;
return SPM_ERR_OK;
}
#ifndef TFM_PSA_API
enum spm_err_t tfm_spm_partition_init(void)
{
struct spm_partition_desc_t *part;
struct tfm_sfn_req_s desc;
int32_t args[4] = {0};
int32_t fail_cnt = 0;
uint32_t idx;
/* Call the init function for each partition */
for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
part = &g_spm_partition_db.partitions[idx];
tfm_spm_hal_configure_default_isolation(part->platform_data);
if (part->static_data.partition_init == NULL) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
tfm_spm_partition_set_caller_partition_idx(idx,
SPM_INVALID_PARTITION_IDX);
} else {
int32_t res;
desc.args = args;
desc.ns_caller = 0U;
desc.iovec_api = TFM_SFN_API_IOVEC;
desc.sfn = (sfn_t)part->static_data.partition_init;
desc.sp_id = part->static_data.partition_id;
res = tfm_core_sfn_request(&desc);
if (res == TFM_SUCCESS) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
} else {
tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, res);
fail_cnt++;
}
}
}
tfm_secure_api_init_done();
if (fail_cnt == 0) {
return SPM_ERR_OK;
} else {
return SPM_ERR_PARTITION_NOT_AVAILABLE;
}
}
#endif /* !defined(TFM_PSA_API) */
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.stack_bottom;
}
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].memory_data.stack_top;
}
#endif
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx)
{
struct spm_partition_desc_t *part;
if (!g_spm_partition_db.is_init) {
return SPM_ERR_PARTITION_DB_NOT_INIT;
}
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_config(&(part->memory_data),
part->platform_data);
}
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx)
{
/* This function takes a partition id and disables the
* SPM partition for that partition
*/
struct spm_partition_desc_t *part;
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_deconfig(&(part->memory_data),
part->platform_data);
}
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_start;
}
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_limit;
}
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_start;
}
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_limit;
}
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
}
#endif
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;
}
#ifndef TFM_PSA_API
void tfm_spm_partition_store_context(uint32_t partition_idx,
uint32_t stack_ptr, uint32_t lr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
g_spm_partition_db.partitions[partition_idx].
runtime_data.lr = lr;
}
const struct spm_partition_runtime_data_t *
tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
{
return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
}
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
state;
if (state == SPM_PARTITION_STATE_RUNNING) {
g_spm_partition_db.running_partition_idx = partition_idx;
}
}
void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
uint32_t caller_partition_idx)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.
caller_partition_idx = caller_partition_idx;
}
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.
caller_client_id = caller_client_id;
}
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share)
{
enum spm_err_t ret = SPM_ERR_OK;
#if TFM_LVL != 1
/* Only need to set configuration on levels higher than 1 */
ret = tfm_spm_hal_set_share_region(share);
#endif
if (ret == SPM_ERR_OK) {
g_spm_partition_db.partitions[partition_idx].runtime_data.share = share;
}
return ret;
}
enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
const int32_t *args)
{
struct spm_partition_runtime_data_t *runtime_data =
&g_spm_partition_db.partitions[partition_idx].runtime_data;
size_t i;
if ((args[1] < 0) || (args[3] < 0)) {
return SPM_ERR_INVALID_PARAMETER;
}
runtime_data->iovec_args.in_len = (size_t)args[1];
for (i = 0U; i < runtime_data->iovec_args.in_len; ++i) {
runtime_data->iovec_args.in_vec[i].base =
((psa_invec *)args[0])[i].base;
runtime_data->iovec_args.in_vec[i].len = ((psa_invec *)args[0])[i].len;
}
runtime_data->iovec_args.out_len = (size_t)args[3];
for (i = 0U; i < runtime_data->iovec_args.out_len; ++i) {
runtime_data->iovec_args.out_vec[i].base =
((psa_outvec *)args[2])[i].base;
runtime_data->iovec_args.out_vec[i].len =
((psa_outvec *)args[2])[i].len;
}
runtime_data->orig_outvec = (psa_outvec *)args[2];
runtime_data->iovec_api = 1;
return SPM_ERR_OK;
}
uint32_t tfm_spm_partition_get_running_partition_idx(void)
{
return g_spm_partition_db.running_partition_idx;
}
void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
{
struct spm_partition_desc_t *partition =
&(g_spm_partition_db.partitions[partition_idx]);
int32_t i;
partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
partition->runtime_data.share = 0;
partition->runtime_data.iovec_args.in_len = 0;
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
partition->runtime_data.iovec_args.in_vec[i].base = 0;
partition->runtime_data.iovec_args.in_vec[i].len = 0;
}
partition->runtime_data.iovec_args.out_len = 0;
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
partition->runtime_data.iovec_args.out_vec[i].base = 0;
partition->runtime_data.iovec_args.out_vec[i].len = 0;
}
partition->runtime_data.orig_outvec = 0;
partition->runtime_data.iovec_api = 0;
}
#endif /* !defined(TFM_PSA_API) */
__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);
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_API_H__
#define __SPM_API_H__
/* This file contains the apis exported by the SPM to tfm core */
#include "tfm_api.h"
#include "spm_partition_defs.h"
#include "secure_fw/core/tfm_secure_api.h"
#define SPM_INVALID_PARTITION_IDX (~0U)
/* Privileged definitions for partition thread mode */
#define TFM_PARTITION_PRIVILEGED_MODE 1
#define TFM_PARTITION_UNPRIVILEGED_MODE 0
enum spm_err_t {
SPM_ERR_OK = 0,
SPM_ERR_PARTITION_DB_NOT_INIT,
SPM_ERR_PARTITION_ALREADY_ACTIVE,
SPM_ERR_PARTITION_NOT_AVAILABLE,
SPM_ERR_INVALID_PARAMETER,
SPM_ERR_INVALID_CONFIG,
};
enum spm_part_state_t {
SPM_PARTITION_STATE_UNINIT = 0,
SPM_PARTITION_STATE_IDLE,
SPM_PARTITION_STATE_RUNNING,
SPM_PARTITION_STATE_SUSPENDED,
SPM_PARTITION_STATE_BLOCKED,
SPM_PARTITION_STATE_CLOSED
};
enum spm_part_flag_mask_t {
SPM_PART_FLAG_APP_ROT = 0x01,
SPM_PART_FLAG_PSA_ROT = 0x02,
SPM_PART_FLAG_IPC = 0x04
};
/**
* \brief Holds the iovec parameters that are passed to a service
*
* \note The size of the structure is (and have to be) multiple of 8 bytes
*/
struct iovec_args_t {
psa_invec in_vec[PSA_MAX_IOVEC]; /*!< Array of psa_invec objects */
size_t in_len; /*!< Number psa_invec objects in in_vec
*/
psa_outvec out_vec[PSA_MAX_IOVEC]; /*!< Array of psa_outvec objects */
size_t out_len; /*!< Number psa_outvec objects in out_vec
*/
};
/**
* \brief Runtime context information of a partition
*/
struct spm_partition_runtime_data_t {
uint32_t partition_state;
uint32_t caller_partition_idx;
int32_t caller_client_id;
uint32_t share;
uint32_t stack_ptr;
uint32_t lr;
int32_t iovec_api; /*!< Whether the function in the partition
* had been called using the iovec API.
* FIXME: Remove the field once this is the
* only option
*/
struct iovec_args_t iovec_args;
psa_outvec *orig_outvec;
};
/**
* \brief Returns the index of the partition with the given partition ID.
*
* \param[in] partition_id Partition id
*
* \return the partition idx if partition_id is valid,
* \ref SPM_INVALID_PARTITION_IDX othervise
*/
uint32_t get_partition_idx(uint32_t partition_id);
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
/**
* \brief Get bottom of stack region for a partition
*
* \param[in] partition_idx Partition index
*
* \return Stack region bottom value
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx);
/**
* \brief Get top of stack region for a partition
*
* \param[in] partition_idx Partition index
*
* \return Stack region top value
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
#endif
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
/**
* \brief Configure isolated sandbox for a partition
*
* \param[in] partition_idx Partition index
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
*/
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx);
/**
* \brief Deconfigure sandbox for a partition
*
* \param[in] partition_idx Partition index
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
*/
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx);
/**
* \brief Get the start of the zero-initialised region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Start of the zero-initialised region
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx);
/**
* \brief Get the limit of the zero-initialised region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Limit of the zero-initialised region
*
* \note This function doesn't check if partition_idx is valid.
* \note The address returned is not part of the region.
*/
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx);
/**
* \brief Get the start of the read-write region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Start of the read-write region
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx);
/**
* \brief Get the limit of the read-write region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Limit of the read-write region
*
* \note This function doesn't check if partition_idx is valid.
* \note The address returned is not part of the region.
*/
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
/**
* \brief Save stack pointer for partition in database
*
* \param[in] partition_idx Partition index
* \param[in] stack_ptr Stack pointer to be stored
*
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr);
#endif
/**
* \brief Get the id of the partition for its index from the db
*
* \param[in] partition_idx Partition index
*
* \return Partition ID for that partition
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx);
/**
* \brief Get the flags associated with a partition
*
* \param[in] partition_idx Partition index
*
* \return Flags associated with the partition
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx);
#ifndef TFM_PSA_API
/**
* \brief Get the current runtime data of a partition
*
* \param[in] partition_idx Partition index
*
* \return The runtime data of the specified partition
*
* \note This function doesn't check if partition_idx is valid.
*/
const struct spm_partition_runtime_data_t *
tfm_spm_partition_get_runtime_data(uint32_t partition_idx);
/**
* \brief Returns the index of the partition that has running state
*
* \return The index of the partition with the running state, if there is any
* set. 0 otherwise.
*/
uint32_t tfm_spm_partition_get_running_partition_idx(void);
/**
* \brief Save stack pointer and link register for partition in database
*
* \param[in] partition_idx Partition index
* \param[in] stack_ptr Stack pointer to be stored
* \param[in] lr Link register to be stored
*
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_store_context(uint32_t partition_idx,
uint32_t stack_ptr, uint32_t lr);
/**
* \brief Set the current state of a partition
*
* \param[in] partition_idx Partition index
* \param[in] state The state to be set
*
* \note This function doesn't check if partition_idx is valid.
* \note The state has to have the value set of \ref spm_part_state_t.
*/
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
/**
* \brief Set the caller partition index for a given partition
*
* \param[in] partition_idx Partition index
* \param[in] caller_partition_idx The index of the caller partition
*
* \note This function doesn't check if any of the partition_idxs are valid.
*/
void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
uint32_t caller_partition_idx);
/**
* \brief Set the caller client ID for a given partition
*
* \param[in] partition_idx Partition index
* \param[in] caller_client_id The ID of the calling client
*
* \note This function doesn't check if any of the partition_idxs are valid.
*/
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id);
/**
* \brief Set the buffer share region of the partition
*
* \param[in] partition_idx Partition index
* \param[in] share The buffer share region to be set
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
* \note share has to have the value set of \ref tfm_buffer_share_region_e
*/
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share);
/**
* \brief Set the iovec parameters for the partition
*
* \param[in] partition_idx Partition index
* \param[in] args The arguments of the secure function
*
* args is expected to be of type int32_t[4] where:
* args[0] is in_vec
* args[1] is in_len
* args[2] is out_vec
* args[3] is out_len
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
* \note This function assumes that the iovecs that are passed in args are
* valid, and does no sanity check on them at all.
*/
enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
const int32_t *args);
/**
* \brief Execute partition init function
*
* \return Error code \ref spm_err_t
*/
enum spm_err_t tfm_spm_partition_init(void);
/**
* \brief Clears the context info from the database for a partition.
*
* \param[in] partition_idx Partition index
*
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_cleanup_context(uint32_t partition_idx);
#endif /* !defined(TFM_PSA_API) */
/**
* \brief Initialize partition database
*
* \return Error code \ref spm_err_t
*/
enum spm_err_t tfm_spm_db_init(void);
/**
* \brief Change the privilege mode for partition thread mode.
*
* \param[in] privileged Privileged mode,
* \ref TFM_PARTITION_PRIVILEGED_MODE
* and \ref TFM_PARTITION_UNPRIVILEGED_MODE
*
* \note Barrier instructions are not called by this function, and if
* it is called in thread mode, it might be necessary to call
* them after this function returns (just like it is done in
* jump_to_ns_code()).
*/
void tfm_spm_partition_change_privilege(uint32_t privileged);
#endif /*__SPM_API_H__ */

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_DB_H__
#define __SPM_DB_H__
#ifdef TFM_PSA_API
#include "tfm_thread.h"
#endif
struct spm_partition_desc_t;
struct spm_partition_db_t;
typedef psa_status_t(*sp_init_function)(void);
#define TFM_PARTITION_TYPE_APP "APPLICATION-ROT"
#define TFM_PARTITION_TYPE_PSA "PSA-ROT"
#ifdef TFM_PSA_API
enum tfm_partition_priority {
TFM_PRIORITY_LOW = THRD_PRIOR_LOWEST,
TFM_PRIORITY_NORMAL = THRD_PRIOR_MEDIUM,
TFM_PRIORITY_HIGH = THRD_PRIOR_HIGHEST,
};
#else
enum tfm_partition_priority {
TFM_PRIORITY_LOW = 0xFF,
TFM_PRIORITY_NORMAL = 0x7F,
TFM_PRIORITY_HIGH = 0,
};
#endif
#define TFM_PRIORITY(LEVEL) TFM_PRIORITY_##LEVEL
/**
* Holds the fields of the partition DB used by the SPM code. The values of
* these fields are calculated at compile time, and set during initialisation
* phase.
*/
struct spm_partition_static_data_t {
uint32_t partition_id;
uint32_t partition_flags;
uint32_t partition_priority;
sp_init_function partition_init;
};
/**
* Holds the fields that define a partition for SPM. The fields are further
* divided to structures, to keep the related fields close to each other.
*/
struct spm_partition_desc_t {
struct spm_partition_static_data_t static_data;
struct spm_partition_runtime_data_t runtime_data;
struct tfm_spm_partition_platform_data_t *platform_data;
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
struct tfm_spm_partition_memory_data_t memory_data;
#endif
#ifdef TFM_PSA_API
struct tfm_thrd_ctx sp_thrd;
#endif
};
/* Macros to pick linker symbols and allow to form the partition data base */
#define REGION(a, b, c) a##b##c
#define REGION_NAME(a, b, c) REGION(a, b, c)
/* Changed from #if (TFM_LVL == 1) && !defined(TFM_PSA_API) to #if (TFM_LVL == 1) to avoid linker error.
TF-M build autogenerates region details (code, ro, rw, zi and stack ) using linker scripts. We do not
hve that in mbed-os build yet.
*/
#if (TFM_LVL == 1)
#define REGION_DECLARE(a, b, c)
#else
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
#define PART_REGION_ADDR(partition, region) \
(uint32_t)&REGION_NAME(Image$$, partition, region)
#endif
#endif /* __SPM_DB_H__ */

View File

@ -1,138 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_DB_SETUP_H__
#define __SPM_DB_SETUP_H__
#include <stdint.h>
#include "spm_db.h"
/**
* \brief Get the index of a partition.
*
* Gets the index of a partition in the partition db based on the partition ID
* provided as a parameter.
*
* \param[in] partition_idx The index of the partition
*
* \return \ref INVALID_PARTITION_IDX if the provided index is invalid. The
* index of the partition otherwise.
*/
uint32_t get_partition_idx(uint32_t partition_id);
struct spm_partition_db_t {
uint32_t is_init;
uint32_t partition_count;
uint32_t running_partition_idx;
struct spm_partition_desc_t partitions[SPM_MAX_PARTITIONS];
};
#define PARTITION_INIT_STATIC_DATA(data, partition, flags, id, priority) \
do { \
data.partition_id = partition##_ID; \
data.partition_flags = flags; \
data.partition_priority = TFM_PRIORITY(priority); \
} while (0)
/* Changed from #if (TFM_LVL == 1) && !defined(TFM_PSA_API) to #if (TFM_LVL == 1) to avoid linker error.
TF-M build autogenerates region details (code, ro, rw, zi and stack ) using linker scripts. We do not
hve that in mbed-os build yet.
*/
#if (TFM_LVL == 1)
#define PARTITION_INIT_MEMORY_DATA(data, partition)
#else
#define PARTITION_INIT_MEMORY_DATA(data, partition) \
do { \
data.code_start = PART_REGION_ADDR(partition, $$Base); \
data.code_limit = PART_REGION_ADDR(partition, $$Limit); \
data.ro_start = PART_REGION_ADDR(partition, $$RO$$Base); \
data.ro_limit = PART_REGION_ADDR(partition, $$RO$$Limit); \
data.rw_start = PART_REGION_ADDR(partition, _DATA$$RW$$Base); \
data.rw_limit = PART_REGION_ADDR(partition, _DATA$$RW$$Limit); \
data.zi_start = PART_REGION_ADDR(partition, _DATA$$ZI$$Base); \
data.zi_limit = PART_REGION_ADDR(partition, _DATA$$ZI$$Limit); \
data.stack_bottom = PART_REGION_ADDR(partition, _STACK$$ZI$$Base); \
data.stack_top = PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
} while (0)
#endif
#if TFM_LVL == 1
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
do { \
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
} while (0)
#else
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
do { \
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 = \
PART_REGION_ADDR(partition, _STACK$$ZI$$Limit - \
sizeof(struct iovec_args_t)); \
} while (0)
#endif
#define PARTITION_DECLARE(partition, flag, type, id, priority, part_stack_size) \
do { \
REGION_DECLARE(Image$$, partition, $$Base); \
REGION_DECLARE(Image$$, partition, $$Limit); \
REGION_DECLARE(Image$$, partition, $$RO$$Base); \
REGION_DECLARE(Image$$, partition, $$RO$$Limit); \
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Base); \
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Limit); \
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Base); \
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Limit); \
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Base); \
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Limit); \
int32_t flags = flag; \
if (tfm_memcmp(type, TFM_PARTITION_TYPE_APP, \
strlen(TFM_PARTITION_TYPE_APP)) == 0) { \
flags |= SPM_PART_FLAG_APP_ROT; \
} else if (tfm_memcmp(type, TFM_PARTITION_TYPE_PSA, \
strlen(TFM_PARTITION_TYPE_PSA)) == 0) { \
flags |= SPM_PART_FLAG_PSA_ROT | SPM_PART_FLAG_APP_ROT; \
} else { \
return SPM_ERR_INVALID_CONFIG; \
} \
struct spm_partition_desc_t *part_ptr; \
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) { \
return SPM_ERR_INVALID_CONFIG; \
} \
__attribute__((section(".data.partitions_stacks"))) \
static uint8_t partition##_stack[part_stack_size] __attribute__((aligned(8))); \
part_ptr = &(g_spm_partition_db.partitions[ \
g_spm_partition_db.partition_count]); \
part_ptr->memory_data.stack_bottom = (uint32_t)partition##_stack; \
part_ptr->memory_data.stack_top = part_ptr->memory_data.stack_bottom + part_stack_size; \
PARTITION_INIT_STATIC_DATA(part_ptr->static_data, partition, flags, \
id, priority); \
PARTITION_INIT_RUNTIME_DATA(part_ptr->runtime_data, partition); \
PARTITION_INIT_MEMORY_DATA(part_ptr->memory_data, partition); \
++g_spm_partition_db.partition_count; \
} while (0)
#define PARTITION_ADD_INIT_FUNC(partition, init_func) \
do { \
extern int32_t init_func(void); \
uint32_t partition_idx = get_partition_idx(partition##_ID); \
struct spm_partition_desc_t *part_ptr = \
&(g_spm_partition_db.partitions[partition_idx]); \
part_ptr->static_data.partition_init = init_func; \
} while (0)
#define PARTITION_ADD_PERIPHERAL(partition, peripheral) \
do { \
uint32_t partition_idx = get_partition_idx(partition##_ID); \
struct spm_partition_desc_t *part_ptr = \
&(g_spm_partition_db.partitions[partition_idx]); \
part_ptr->platform_data = peripheral; \
} while (0)
#endif /* __SPM_DB_SETUP_H__ */

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_PARTITION_DEFS_H__
#define __SPM_PARTITION_DEFS_H__
/* FixMe: allocations to be settled.
* 8 bits reserved by TFM for secure partition Id in this prototype
*/
#define TFM_SP_BASE 256
/* A reserved partition ID that is used for uninitialised data */
#define INVALID_PARTITION_ID (~0U)
/* ***** partition ID-s internal to the TFM ***** */
#define TFM_INTERNAL_PARTITIONS (2)
/* From the SPM point of view the non secure processing environment is handled
* as a special secure partition. This simplifies the context switch
* operations.
*/
#define TFM_SP_NON_SECURE_ID (0)
/* A dummy partition for TFM_SP_CORE is created to handle secure partition
* calls done directly from the core, before NS execution started.
*/
#define TFM_SP_CORE_ID (1)
#include "tfm_partition_defs.inc"
/* This limit is only used to define the size of the database reserved for
* partitions. There's no requirement that it match the number of partitions
* that get registered in a specific build
*/
#define SPM_MAX_PARTITIONS (TFM_MAX_USER_PARTITIONS + TFM_INTERNAL_PARTITIONS)
#endif /* __SPM_PARTITION_DEFS_H__ */

View File

@ -1,111 +0,0 @@
# TF-M integration to Mbed-OS
This document is an initial draft for TF-M for Mbed-OS porting guide .
## Audience
This guide is intended for developers wishing to port Mbed-OS with TF-M used as a secure kernel for ARMv8-M targets.
Prior knowledge with both TF-M & Mbed-OS concepts is assumed.
## Build system concepts:
Mbed-OS build system is based on [Mbed-CLI](https://github.com/ARMmbed/mbed-cli).
Mbed-CLI build system performs lookup for source and header files within project directory and adds them all to a build. All folders will be scanned for sources except for:
- folders starting with `TARGET_*`
- folders starting with `COMPONENT_*`
- folders starting with `FEATURE_*`
- folders starting with `TESTS_*` (not true for `mbed test` builds)
- files and folders listed in `.mbedignore`
The ignored folders listed above can be explicitly added to a compilation by adding following keys to a target description in `targets.json`:
- adding `extra_labels_add`, `inherits` and `sub_target` for adding `TARGET_*`
- adding `components_add` for adding `COMPONENT_*`
- `features_add` for adding `FEATURE_*`
TF-M is built as bare-metal in a secure target, in order to build a secure target with TF-M as its' kernel need to add `--app-config <MBED-OS-ROOT>/tools/psa/tfm/mbed_app.json` to the build command of the secure target.
## Build hooks
Mbed-OS testing tools are designed to work with a single image (`.bin` or `.hex`).
When building mbed-os for TF-M targets two images are created. One for normal world(NW) and one for TrustZone(TZ).
Mbed-OS build system provides `post_binary_hook` that allows executing arbitrary Python script for merging NW and TZ images. Typically `post_binary_hook` is added to NW target and assumes TZ target images as a prerequisite.
## Porting TF-M targets
Typically firmware for TF-M targets consist of 2 or more images: normal world and TrustZone image. More images can be present in case boot loaders are used.
Two images must be built and linked separately. TrustZone image must be built first.
There may be code and/or header files sharing between the two targets.
Nested folder layout typically provides more easy code reuse between two targets:
Example:
```txt
└── tragets
└── TARGET_<VENDOR>
└── TARGET_<BOARD>
├── common_files <-- files shared between NW and TZ images
├── TARGET_<BOARD>_NS
│   └── normal_world_files <-- files only to be included for NW build
└── TARGET_<BOARD>_S
└── trustzone_files <-- files only to be included for TZ build
```
The target should be represented in a following way in `target.json` (`MUSCA_A1` is taken for example and should be substituted):
```json
...
"ARM_MUSCA_A1": {
"public": false,
"inherits": ["Target"],
"supported_toolchains": ["ARMC6", "GCC_ARM"],
"default_toolchain": "ARMC6",
"extra_labels": ["ARM_SSG", "MUSCA_A1"],
},
"ARM_MUSCA_A1_NS": {
"inherits": ["NSPE_Target", "ARM_MUSCA_A1"],
"core": "Cortex-M33-NS",
"device_has_add": ["INTERRUPTIN", "LPTICKER", "SERIAL", "SLEEP", "USTICKER"],
"macros": [
"MBED_FAULT_HANDLER_DISABLED",
"MBEDTLS_PSA_CRYPTO_C"
],
"extra_labels_add": ["MUSCA_A1_NS", "PSA", "TFM"],
"post_binary_hook": {"function": "ArmMuscaA1Code.binary_hook"}
},
"ARM_MUSCA_A1_S": {
"inherits": ["SPE_Target", "ARM_MUSCA_A1"],
"core": "Cortex-M33",
"device_has_add": ["FLASH"],
"macros": [
"MBED_MPU_CUSTOM",
"MBEDTLS_PSA_CRYPTO_SPM",
"MBEDTLS_PSA_CRYPTO_C",
"MBEDTLS_ENTROPY_NV_SEED"
],
"components_add": ["FLASHIAP"],
"extra_labels_add": ["MUSCA_A1_S", "PSA", "TFM"]
},
```
Example details:
- Secure target:
- `"device_has_add": ["FLASH"]` and `"components_add": ["FLASHIAP"]` for enabling storage stack. Required by PSA Internal storage service.
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
- all the macros from the example above are required
- must inherit from `SPE_Target`
- Nonsecure target:
- must inherit from `NSPE_Target`
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
- all the macros from the example above are required
- `post_binary_hook` is used to combine secure and non-secure images
### HAL
For porting Mbed-OS & TF-M both Mbed-OS and TF-M HAL layers should be created.
#### Mbed-OS HAL:
Follow instructions for [Mbed-OS HAL porting](https://os.mbed.com/docs/mbed-os/v5.11/porting/porting-hal-modules.html)
#### TF-M:
Mbed-OS contains customized TF-M version. TF-M services reference implementation was replaced by Mbed-OS version. Thus TF-M has different HAL layer comparing to vanilla [TF-M reference implementation](https://git.trustedfirmware.org/trusted-firmware-m.git/about/).
The porting layer consists of:
- All functions listed in: `components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h`
- Flash API `mbed-os/hal/flash_api.h` implementation is required for TZ image. It is used by PSA Internal trusted storage implementation.

View File

@ -1,253 +0,0 @@
/*
* Copyright (c) 2018-2019 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ---------------------------------- Includes ---------------------------------
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#include "psa_initial_attestation_api.h"
#include "psa_attest_inject_key.h"
#include "psa_inject_attestation_key_impl.h"
#include "attestation.h"
#include <stdlib.h>
#include <string.h>
#include "psa/crypto.h"
int32_t g_caller_id = 0;
static void set_caller_id(psa_msg_t *msg)
{
g_caller_id = msg->client_id;
}
// ------------------------- Partition's Main Thread ---------------------------
static void psa_attest_get_token(void)
{
psa_msg_t msg = { 0 };
enum psa_attest_err_t status = PSA_ATTEST_ERR_SUCCESS;
if (PSA_SUCCESS != psa_get(PSA_ATTEST_GET_TOKEN, &msg)) {
return;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
uint8_t *challenge_buff = NULL;
uint8_t *token_buff = NULL;
uint32_t bytes_read = 0;
challenge_buff = calloc(1, msg.in_size[0]);
if (challenge_buff == NULL) {
status = PSA_ATTEST_ERR_GENERAL;
break;
}
bytes_read = psa_read(msg.handle, 0,
challenge_buff, msg.in_size[0]);
if (bytes_read != msg.in_size[0]) {
free(challenge_buff);
SPM_PANIC("SPM read length mismatch");
}
token_buff = calloc(1, msg.out_size[0]);
if (token_buff == NULL) {
status = PSA_ATTEST_ERR_GENERAL;
free(challenge_buff);
break;
}
psa_invec in_vec[1] = { { challenge_buff, msg.in_size[0] } };
psa_outvec out_vec[1] = { { token_buff, msg.out_size[0] } };
status = attest_init();
if (status != PSA_ATTEST_ERR_SUCCESS) {
free(challenge_buff);
free(token_buff);
break;
}
set_caller_id(&msg);
status = initial_attest_get_token(in_vec, 1, out_vec, 1);
if (status == PSA_ATTEST_ERR_SUCCESS) {
psa_write(msg.handle, 0, out_vec[0].base, out_vec[0].len);
}
free(challenge_buff);
free(token_buff);
break;
}
default: {
SPM_PANIC("Unexpected message type %d!", (int)(msg.type));
break;
}
}
psa_reply(msg.handle, status);
}
static void psa_attest_get_token_size(void)
{
psa_msg_t msg = { 0 };
enum psa_attest_err_t status = PSA_ATTEST_ERR_SUCCESS;
if (PSA_SUCCESS != psa_get(PSA_ATTEST_GET_TOKEN_SIZE, &msg)) {
return;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
uint32_t challenge_size;
uint32_t token_size;
uint32_t bytes_read = 0;
bytes_read = psa_read(msg.handle, 0,
&challenge_size, msg.in_size[0]);
if (bytes_read != msg.in_size[0]) {
SPM_PANIC("SPM read length mismatch");
}
psa_invec in_vec[1] = { { &challenge_size, msg.in_size[0] } };
psa_outvec out_vec[1] = { { &token_size, msg.out_size[0] } };
status = attest_init();
if (status != PSA_ATTEST_ERR_SUCCESS) {
break;
}
set_caller_id(&msg);
status = initial_attest_get_token_size(in_vec, 1, out_vec, 1);
if (status == PSA_ATTEST_ERR_SUCCESS) {
psa_write(msg.handle, 0, out_vec[0].base, out_vec[0].len);
}
break;
}
default: {
SPM_PANIC("Unexpected message type %d!", (int)(msg.type));
break;
}
}
psa_reply(msg.handle, status);
}
static void psa_attest_inject_key(void)
{
psa_msg_t msg = { 0 };
psa_status_t status = PSA_SUCCESS;
if (PSA_SUCCESS != psa_get(PSA_ATTEST_INJECT_KEY, &msg)) {
return;
}
switch (msg.type) {
case PSA_IPC_CONNECT:
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
uint8_t *public_key_data = NULL;
size_t public_key_data_length = 0;
uint8_t *key_data = NULL;
psa_key_type_t type;
uint32_t bytes_read = 0;
if (msg.in_size[0] != sizeof(psa_key_type_t)) {
status = PSA_ERROR_INVALID_ARGUMENT;
break;
}
bytes_read = psa_read(msg.handle, 0, &type, msg.in_size[0]);
if (bytes_read != msg.in_size[0]) {
SPM_PANIC("SPM read length mismatch");
}
public_key_data = calloc(1, msg.out_size[0]);
if (public_key_data == NULL) {
status = PSA_ERROR_INSUFFICIENT_MEMORY;
break;
}
if (msg.in_size[1] != 0) {
key_data = calloc(1, msg.in_size[1]);
if (key_data == NULL) {
status = PSA_ERROR_INSUFFICIENT_MEMORY;
free(public_key_data);
break;
}
bytes_read = psa_read(msg.handle, 1,
key_data, msg.in_size[1]);
if (bytes_read != msg.in_size[1]) {
free(public_key_data);
free(key_data);
SPM_PANIC("SPM read length mismatch");
}
}
status = psa_attestation_inject_key_impl(key_data,
msg.in_size[1],
type,
public_key_data,
msg.out_size[0],
&public_key_data_length);
if (status == PSA_SUCCESS) {
psa_write(msg.handle, 0, public_key_data, public_key_data_length);
}
psa_write(msg.handle, 1,
&public_key_data_length, sizeof(public_key_data_length));
free(public_key_data);
if (key_data != NULL) {
free(key_data);
}
break;
}
default: {
SPM_PANIC("Unexpected message type %d!", (int)(msg.type));
break;
}
}
psa_reply(msg.handle, status);
}
void attest_main(void *ptr)
{
while (1) {
uint32_t signals = psa_wait(ATTEST_SRV_WAIT_ANY_SID_MSK, PSA_BLOCK);
if (signals & PSA_ATTEST_GET_TOKEN) {
psa_attest_get_token();
}
if (signals & PSA_ATTEST_GET_TOKEN_SIZE) {
psa_attest_get_token_size();
}
if (signals & PSA_ATTEST_INJECT_KEY) {
psa_attest_inject_key();
}
}
}

View File

@ -1,47 +0,0 @@
{
"name": "ATTEST_SRV",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000025",
"entry_point": "attest_main",
"stack_size": "0x2000",
"heap_size": "0x2000",
"services": [
{
"name": "PSA_ATTEST_GET_TOKEN_ID",
"identifier": "0x00000F10",
"signal": "PSA_ATTEST_GET_TOKEN",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_ATTEST_GET_TOKEN_SIZE_ID",
"identifier": "0x00000F11",
"signal": "PSA_ATTEST_GET_TOKEN_SIZE",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_ATTEST_INJECT_KEY_ID",
"identifier": "0x00000F12",
"signal": "PSA_ATTEST_INJECT_KEY",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
}
],
"extern_sids": [
"PSA_CRYPTO_INIT_ID",
"PSA_HASH_ID",
"PSA_ASYMMETRIC_ID",
"PSA_KEY_MNG_ID",
"PSA_CRYPTO_FREE_ID",
"PSA_KEY_DERIVATION_ID",
"PSA_PLATFORM_LC_GET"
],
"source_files": [
"COMPONENT_SPE/psa_attestation_partition.c"
]
}

View File

@ -14,9 +14,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef PSA_CRYPTO_SECURE
#include "crypto_struct_spe.h"
#else
#include "crypto_struct_ipc.h"
#endif

View File

@ -1,112 +0,0 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file psa/crypto_spe.h
* \brief Platform Security Architecture cryptography module
*/
#ifndef PSA_CRYPTO_SPE_H
#define PSA_CRYPTO_SPE_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define psa_crypto_init psa_sec_crypto_init
#define psa_get_key_attributes psa_sec_get_key_attributes
#define psa_reset_key_attributes psa_sec_reset_key_attributes
#define psa_open_key psa_sec_open_key
#define psa_close_key psa_sec_close_key
#define psa_import_key psa_sec_import_key
#define psa_destroy_key psa_sec_destroy_key
#define psa_export_key psa_sec_export_key
#define psa_export_public_key psa_sec_export_public_key
#define psa_copy_key psa_sec_copy_key
#define psa_hash_compute psa_sec_hash_compute
#define psa_hash_compare psa_sec_hash_compare
#define psa_hash_setup psa_sec_hash_setup
#define psa_hash_update psa_sec_hash_update
#define psa_hash_finish psa_sec_hash_finish
#define psa_hash_verify psa_sec_hash_verify
#define psa_hash_abort psa_sec_hash_abort
#define psa_hash_clone psa_sec_hash_clone
#define psa_mac_compute psa_sec_mac_compute
#define psa_mac_verify psa_sec_mac_verify
#define psa_mac_sign_setup psa_sec_mac_sign_setup
#define psa_mac_verify_setup psa_sec_mac_verify_setup
#define psa_mac_update psa_sec_mac_update
#define psa_mac_sign_finish psa_sec_mac_sign_finish
#define psa_mac_verify_finish psa_sec_mac_verify_finish
#define psa_mac_abort psa_sec_mac_abort
#define psa_cipher_encrypt psa_sec_cipher_encrypt
#define psa_cipher_decrypt psa_sec_cipher_decrypt
#define psa_cipher_encrypt_setup psa_sec_cipher_encrypt_setup
#define psa_cipher_decrypt_setup psa_sec_cipher_decrypt_setup
#define psa_cipher_generate_iv psa_sec_cipher_generate_iv
#define psa_cipher_set_iv psa_sec_cipher_set_iv
#define psa_cipher_update psa_sec_cipher_update
#define psa_cipher_finish psa_sec_cipher_finish
#define psa_cipher_abort psa_sec_cipher_abort
#define psa_aead_encrypt psa_sec_aead_encrypt
#define psa_aead_decrypt psa_sec_aead_decrypt
#define psa_aead_encrypt_setup psa_sec_aead_encrypt_setup
#define psa_aead_decrypt_setup psa_sec_aead_decrypt_setup
#define psa_aead_generate_nonce psa_sec_aead_generate_nonce
#define psa_aead_set_nonce psa_sec_aead_set_nonce
#define psa_aead_set_lengths psa_sec_aead_set_lengths
#define psa_aead_update_ad psa_sec_aead_update_ad
#define psa_aead_update psa_sec_aead_update
#define psa_aead_finish psa_sec_aead_finish
#define psa_aead_verify psa_sec_aead_verify
#define psa_aead_abort psa_sec_aead_abort
#define psa_sign_hash psa_sec_sign_hash
#define psa_verify_hash psa_sec_verify_hash
#define psa_asymmetric_encrypt psa_sec_asymmetric_encrypt
#define psa_asymmetric_decrypt psa_sec_asymmetric_decrypt
#define psa_key_derivation_setup psa_sec_key_derivation_setup
#define psa_key_derivation_get_capacity psa_sec_key_derivation_get_capacity
#define psa_key_derivation_set_capacity psa_sec_key_derivation_set_capacity
#define psa_key_derivation_input_bytes psa_sec_key_derivation_input_bytes
#define psa_key_derivation_input_key psa_sec_key_derivation_input_key
#define psa_key_derivation_key_agreement psa_sec_key_derivation_key_agreement
#define psa_key_derivation_output_bytes psa_sec_key_derivation_output_bytes
#define psa_key_derivation_output_key psa_sec_key_derivation_output_key
#define psa_key_derivation_abort psa_sec_key_derivation_abort
#define psa_raw_key_agreement psa_sec_raw_key_agreement
#define psa_generate_random psa_sec_generate_random
#define psa_generate_key psa_sec_generate_key
#define mbedtls_psa_crypto_free mbedtls_psa_sec_crypto_free
#define mbedtls_psa_inject_entropy mbedtls_psa_sec_inject_entropy
#define psa_set_key_domain_parameters psa_sec_set_key_domain_parameters
#define psa_get_key_domain_parameters psa_sec_get_key_domain_parameters
#define MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER 1
#include "crypto.h"
#ifdef __cplusplus
}
#endif
/* The file "crypto_extra.h" contains vendor-specific definitions. This
* can include vendor-defined algorithms, extra functions, etc. */
#include "crypto_extra.h"
#endif /* PSA_CRYPTO_SPE_H */

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "psa/client.h"
#include "psa/service.h"
#include "psa_crypto_access_control.h"
#include "psa_crypto_core.h"
#include "psa_crypto_slot_management.h"
typedef struct psa_crypto_access_control_s {
psa_key_handle_t key_handle;
int32_t partition_id;
} psa_crypto_access_control_t;
static psa_crypto_access_control_t crypto_access_control_arr[PSA_KEY_SLOT_COUNT];
static inline void psa_crypto_access_control_reset()
{
memset(crypto_access_control_arr, 0, sizeof(crypto_access_control_arr));
}
void psa_crypto_access_control_init(void)
{
psa_crypto_access_control_reset();
}
void psa_crypto_access_control_destroy(void)
{
psa_crypto_access_control_reset();
}
void psa_crypto_access_control_register_handle(psa_key_handle_t key_handle, int32_t partition_id)
{
for (size_t i = 0; i < PSA_KEY_SLOT_COUNT; i++) {
if (crypto_access_control_arr[i].key_handle == 0 &&
crypto_access_control_arr[i].partition_id == 0) {
crypto_access_control_arr[i].key_handle = key_handle;
crypto_access_control_arr[i].partition_id = partition_id;
return;
}
}
SPM_PANIC("psa_crypto_access_control_register_handle failed");
}
void psa_crypto_access_control_unregister_handle(psa_key_handle_t key_handle)
{
for (size_t i = 0; i < PSA_KEY_SLOT_COUNT; i++) {
if (crypto_access_control_arr[i].key_handle == key_handle) {
crypto_access_control_arr[i].key_handle = 0;
crypto_access_control_arr[i].partition_id = 0;
return;
}
}
SPM_PANIC("psa_crypto_access_control_unregister_handle failed");
}
uint8_t psa_crypto_access_control_is_handle_permitted(psa_key_handle_t key_handle, int32_t partition_id)
{
for (size_t i = 0; i < PSA_KEY_SLOT_COUNT; i++) {
if (crypto_access_control_arr[i].key_handle == key_handle &&
crypto_access_control_arr[i].partition_id == partition_id) {
return 1;
}
}
return 0;
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PSA_CRYPTO_ACCESS_CONTROL_H
#define PSA_CRYPTO_ACCESS_CONTROL_H
#include <stdint.h>
#include "crypto_platform.h"
/* initialize the module, resets all tracked information */
void psa_crypto_access_control_init(void);
/* deinitialize the module, resets all tracked information */
void psa_crypto_access_control_destroy(void);
/* tracks and associates the key_handle with partition_id */
void psa_crypto_access_control_register_handle(psa_key_handle_t key_handle, int32_t partition_id);
/* removes tracking of the key_handle */
void psa_crypto_access_control_unregister_handle(psa_key_handle_t key_handle);
/* checks if the key_handle is associated with the partition_id, returns 0 is false otherwise 1 */
uint8_t psa_crypto_access_control_is_handle_permitted(psa_key_handle_t key_handle, int32_t partition_id);
#endif /* PSA_CRYPTO_ACCESS_CONTROL_H */

View File

@ -1,108 +0,0 @@
{
"name": "CRYPTO_SRV",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000023",
"entry_point": "crypto_main",
"stack_size": "0x4000",
"heap_size": "0x400",
"services": [
{
"name": "PSA_CRYPTO_INIT_ID",
"identifier": "0x00000F00",
"signal": "PSA_CRYPTO_INIT",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_MAC_ID",
"identifier": "0x00000F01",
"signal": "PSA_MAC",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_HASH_ID",
"identifier": "0x00000F02",
"signal": "PSA_HASH",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_ASYMMETRIC_ID",
"identifier": "0x00000F03",
"signal": "PSA_ASYMMETRIC",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_SYMMETRIC_ID",
"identifier": "0x00000F04",
"signal": "PSA_SYMMETRIC",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_AEAD_ID",
"identifier": "0x00000F05",
"signal": "PSA_AEAD",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_KEY_MNG_ID",
"identifier": "0x00000F06",
"signal": "PSA_KEY_MNG",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_RNG_ID",
"identifier": "0x00000F07",
"signal": "PSA_RNG",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_CRYPTO_FREE_ID",
"identifier": "0x00000F08",
"signal": "PSA_CRYPTO_FREE",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_KEY_DERIVATION_ID",
"identifier": "0x00000F09",
"signal": "PSA_KEY_DERIVATION",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
},
{
"name": "PSA_ENTROPY_ID",
"identifier": "0x00000F0A",
"signal": "PSA_ENTROPY_INJECT",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "STRICT"
}
],
"extern_sids": [
"PSA_ITS_GET",
"PSA_ITS_SET",
"PSA_ITS_INFO",
"PSA_ITS_REMOVE"
],
"source_files": [
"COMPONENT_SPE/psa_crypto_partition.c"
]
}

View File

@ -1,202 +0,0 @@
/* Copyright (c) 2019-2020 Arm Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_spm_partitions.h"
#include "platform_srv_impl.h"
#include "psa/lifecycle.h"
#include "psa/internal_trusted_storage.h"
#include "psa/service.h"
#define INPUT_BUFFER_SIZE 64
#define OUTPUT_BUFFER_SIZE 64
typedef psa_status_t (*SignalHandler)(psa_msg_t *);
static psa_status_t lifecycle_get(psa_msg_t *msg)
{
uint32_t lc_state;
if (msg->out_size[0] != sizeof(lc_state)) {
return PSA_DROP_CONNECTION;
}
psa_status_t status = psa_platfrom_lifecycle_get_impl(&lc_state);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &lc_state, sizeof(lc_state));
}
return status;
}
static psa_status_t lifecycle_change_request(psa_msg_t *msg)
{
uint32_t lc_state;
if (msg->in_size[0] != sizeof(lc_state)) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 0, &lc_state, sizeof(lc_state)) != sizeof(lc_state)) {
return PSA_DROP_CONNECTION;
}
return psa_platfrom_lifecycle_change_request_impl(lc_state);
}
static MBED_NORETURN psa_status_t system_reset_request(psa_msg_t *msg)
{
(void)msg;
mbed_psa_system_reset_impl();
}
static enum tfm_platform_err_t
platform_sp_ioctl_ipc(const psa_msg_t *msg) {
void *input = NULL;
void *output = NULL;
psa_invec invec = {0};
psa_outvec outvec = {0};
uint8_t input_buffer[INPUT_BUFFER_SIZE] = {0};
uint8_t output_buffer[OUTPUT_BUFFER_SIZE] = {0};
tfm_platform_ioctl_req_t request = 0;
enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SYSTEM_ERROR;
size_t num = 0;
uint32_t in_len = PSA_MAX_IOVEC;
uint32_t out_len = PSA_MAX_IOVEC;
while ((in_len > 0) && (msg->in_size[in_len - 1] == 0))
{
in_len--;
}
while ((out_len > 0) && (msg->out_size[out_len - 1] == 0))
{
out_len--;
}
if ((in_len < 1) || (in_len > 2) ||
(out_len > 1))
{
return TFM_PLATFORM_ERR_SYSTEM_ERROR;
}
num = psa_read(msg->handle, 0, &request, sizeof(request));
if (num != sizeof(request))
{
return PSA_ERROR_PROGRAMMER_ERROR;
}
if (in_len > 1)
{
if (msg->in_size[1] > INPUT_BUFFER_SIZE) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
num = psa_read(msg->handle, 1, &input_buffer, msg->in_size[1]);
if (num != msg->in_size[1]) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
invec.base = input_buffer;
invec.len = msg->in_size[1];
input = &invec;
}
if (out_len > 0)
{
if (msg->out_size[0] > OUTPUT_BUFFER_SIZE) {
return PSA_ERROR_PROGRAMMER_ERROR;
}
outvec.base = output_buffer;
outvec.len = msg->out_size[0];
output = &outvec;
}
ret = tfm_platform_hal_ioctl(request, input, output);
if (output != NULL)
{
psa_write(msg->handle, 0, outvec.base, outvec.len);
}
return ret;
}
static psa_status_t platform_ioctl(psa_msg_t *msg)
{
/* platform_sp_ioctl_ipc returns either psa_status_t or one of the
* following errorcodes:
* enum tfm_platform_err_t {
* TFM_PLATFORM_ERR_SUCCESS = 0,
* TFM_PLATFORM_ERR_SYSTEM_ERROR,
* TFM_PLATFORM_ERR_INVALID_PARAM,
* TFM_PLATFORM_ERR_NOT_SUPPORTED,
*
* TFM_PLATFORM_ERR_FORCE_INT_SIZE = INT_MAX
* };
*/
return platform_sp_ioctl_ipc(msg);
}
static void message_handler(psa_msg_t *msg, SignalHandler handler)
{
psa_status_t status = PSA_SUCCESS;
switch (msg->type) {
case PSA_IPC_CONNECT: //fallthrough
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
status = handler(msg);
break;
}
default: {
SPM_PANIC("Unexpected message type %lu!", msg->type);
break;
}
}
psa_reply(msg->handle, status);
}
void platform_partition_entry(void *ptr)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
while (1) {
signals = psa_wait(PLATFORM_WAIT_ANY_SID_MSK, PSA_BLOCK);
if ((signals & PSA_PLATFORM_LC_GET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_PLATFORM_LC_GET_MSK, &msg)) {
continue;
}
message_handler(&msg, lifecycle_get);
}
if ((signals & PSA_PLATFORM_LC_SET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_PLATFORM_LC_SET_MSK, &msg)) {
continue;
}
message_handler(&msg, lifecycle_change_request);
}
if ((signals & PSA_PLATFORM_SYSTEM_RESET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_PLATFORM_SYSTEM_RESET_MSK, &msg)) {
continue;
}
message_handler(&msg, system_reset_request);
}
if ((signals & PSA_PLATFORM_IOCTL_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_PLATFORM_IOCTL_MSK, &msg)) {
continue;
}
message_handler(&msg, platform_ioctl);
}
}
}

View File

@ -1,48 +0,0 @@
{
"name": "PLATFORM",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x00000008",
"entry_point": "platform_partition_entry",
"stack_size": "0x400",
"heap_size": "0x400",
"services": [{
"name": "PSA_PLATFORM_LC_GET",
"identifier": "0x00011000",
"signal": "PSA_PLATFORM_LC_GET_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_PLATFORM_LC_SET",
"identifier": "0x00011001",
"signal": "PSA_PLATFORM_LC_SET_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_PLATFORM_SYSTEM_RESET",
"identifier": "0x00011002",
"signal": "PSA_PLATFORM_SYSTEM_RESET_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_PLATFORM_IOCTL",
"identifier": "0x00011003",
"signal": "PSA_PLATFORM_IOCTL_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
}
],
"extern_sids": [
"PSA_ITS_RESET"
],
"source_files": [
"COMPONENT_SPE/platform_partition.c"
]
}

View File

@ -1,221 +0,0 @@
/* Copyright (c) 2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include "psa/client.h"
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#include "psa/internal_trusted_storage.h"
#include "pits_impl.h"
#include "mbed_error.h"
int kv_init_storage_config();
#ifdef __cplusplus
extern "C"
{
#endif
typedef psa_status_t (*SignalHandler)(psa_msg_t *);
static psa_status_t storage_set(psa_msg_t *msg)
{
psa_storage_uid_t key = 0;
void *data = NULL;
uint32_t alloc_size = msg->in_size[1];
psa_storage_create_flags_t flags = 0;
if ((msg->in_size[0] != sizeof(key)) || (msg->in_size[2] != sizeof(flags))) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 0, &key, sizeof(key)) != sizeof(key)) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 2, &flags, sizeof(flags)) != sizeof(flags)) {
return PSA_DROP_CONNECTION;
}
data = malloc(alloc_size);
if (data == NULL) {
return PSA_ERROR_STORAGE_FAILURE;
}
if (psa_read(msg->handle, 1, data, msg->in_size[1]) != msg->in_size[1]) {
free(data);
return PSA_ERROR_STORAGE_FAILURE;
}
psa_status_t status = psa_its_set_impl(msg->client_id, key, alloc_size, data, flags);
memset(data, 0, alloc_size);
free(data);
return status;
}
static psa_status_t storage_get(psa_msg_t *msg)
{
psa_storage_uid_t key = 0;
uint32_t offset = 0;
size_t actual_size;
if ((msg->in_size[0] != sizeof(key)) ||
(msg->in_size[1] != sizeof(offset)) ||
(msg->out_size[1] != sizeof(actual_size))) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 0, &key, sizeof(key)) != sizeof(key)) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 1, &offset, sizeof(offset)) != sizeof(offset)) {
return PSA_DROP_CONNECTION;
}
uint8_t *data = (uint8_t *)malloc(msg->out_size[0]);
if (data == NULL) {
return PSA_ERROR_STORAGE_FAILURE;
}
psa_status_t status = psa_its_get_impl(msg->client_id, key, offset, msg->out_size[0], data, &actual_size);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, data, actual_size);
psa_write(msg->handle, 1, &actual_size, sizeof(actual_size));
}
memset(data, 0, msg->out_size[0]);
free(data);
return status;
}
static psa_status_t storage_info(psa_msg_t *msg)
{
struct psa_storage_info_t info = { 0 };
psa_storage_uid_t key = 0;
if ((msg->in_size[0] != sizeof(key)) || (msg->out_size[0] != sizeof(info))) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 0, &key, sizeof(key)) != sizeof(key)) {
return PSA_DROP_CONNECTION;
}
psa_status_t status = psa_its_get_info_impl(msg->client_id, key, &info);
if (status == PSA_SUCCESS) {
psa_write(msg->handle, 0, &info, msg->out_size[0]);
}
return status;
}
static psa_status_t storage_remove(psa_msg_t *msg)
{
psa_storage_uid_t key = 0;
if (msg->in_size[0] != sizeof(key)) {
return PSA_DROP_CONNECTION;
}
if (psa_read(msg->handle, 0, &key, sizeof(key)) != sizeof(key)) {
return PSA_DROP_CONNECTION;
}
return psa_its_remove_impl(msg->client_id, key);
}
static psa_status_t storage_reset(psa_msg_t *msg)
{
(void)msg;
return psa_its_reset_impl();
}
static void message_handler(psa_msg_t *msg, SignalHandler handler)
{
psa_status_t status = PSA_SUCCESS;
switch (msg->type) {
case PSA_IPC_CONNECT: //fallthrough
case PSA_IPC_DISCONNECT: {
break;
}
case PSA_IPC_CALL: {
status = handler(msg);
break;
}
default: {
SPM_PANIC("Unexpected message type %lu!", msg->type);
break;
}
}
psa_reply(msg->handle, status);
}
void its_entry(void *ptr)
{
psa_signal_t signals = 0;
psa_msg_t msg = {0};
while (1) {
signals = psa_wait(ITS_WAIT_ANY_SID_MSK, PSA_BLOCK);
// KVStore initiation:
// - Must be done after the psa_wait() call since only now we know OS initialization is done
// - Repeating calls has no effect
int kv_status = kv_init_storage_config();
if (kv_status != MBED_SUCCESS) {
SPM_PANIC("KVStore initiation failed with status %d!", kv_status);
}
if ((signals & PSA_ITS_SET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_ITS_SET_MSK, &msg)) {
continue;
}
message_handler(&msg, storage_set);
}
if ((signals & PSA_ITS_GET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_ITS_GET_MSK, &msg)) {
continue;
}
message_handler(&msg, storage_get);
}
if ((signals & PSA_ITS_INFO_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_ITS_INFO_MSK, &msg)) {
continue;
}
message_handler(&msg, storage_info);
}
if ((signals & PSA_ITS_REMOVE_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_ITS_REMOVE_MSK, &msg)) {
continue;
}
message_handler(&msg, storage_remove);
}
if ((signals & PSA_ITS_RESET_MSK) != 0) {
if (PSA_SUCCESS != psa_get(PSA_ITS_RESET_MSK, &msg)) {
continue;
}
message_handler(&msg, storage_reset);
}
}
}
#ifdef __cplusplus
}
#endif

View File

@ -1,53 +0,0 @@
{
"name": "ITS",
"type": "APPLICATION-ROT",
"priority": "NORMAL",
"id": "0x0000000A",
"entry_point": "its_entry",
"stack_size": "0x800",
"heap_size": "0x400",
"services": [{
"name": "PSA_ITS_GET",
"identifier": "0x00011A00",
"signal": "PSA_ITS_GET_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_ITS_SET",
"identifier": "0x00011A01",
"signal": "PSA_ITS_SET_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_ITS_INFO",
"identifier": "0x00011A02",
"signal": "PSA_ITS_INFO_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_ITS_REMOVE",
"identifier": "0x00011A03",
"signal": "PSA_ITS_REMOVE_MSK",
"non_secure_clients": true,
"minor_version": 1,
"minor_policy": "RELAXED"
},
{
"name": "PSA_ITS_RESET",
"identifier": "0x00011A04",
"signal": "PSA_ITS_RESET_MSK",
"non_secure_clients": false,
"minor_version": 1,
"minor_policy": "RELAXED"
}
],
"source_files": [
"COMPONENT_SPE/its_partition.c"
]
}

View File

@ -2102,7 +2102,6 @@ PREDEFINED = DOXYGEN_ONLY \
DEVICE_QSPI \
DEVICE_STORAGE \
DEVICE_WATCHDOG \
COMPONENT_SPE \
"TFM_LVL=1" \
"MBED_DEPRECATED_SINCE(d, m)=" \
"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=" \

View File

@ -6,7 +6,7 @@
"SEARCH_INCLUDES": "YES",
"INCLUDE_PATH": "",
"INCLUDE_FILE_PATTERNS": "",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG DEVICE_RESET_REASON COMPONENT_SPE \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG DEVICE_RESET_REASON \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",

View File

@ -89,13 +89,13 @@ static void reset_storage_for_compliance_test()
static void inject_entropy()
{
#if defined(MBEDTLS_ENTROPY_NV_SEED) || defined(COMPONENT_PSA_SRV_IPC)
#if defined(MBEDTLS_ENTROPY_NV_SEED)
uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = { 0 };
for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) {
seed[i] = i;
}
mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE);
#endif // defined(MBEDTLS_ENTROPY_NV_SEED) || defined(COMPONENT_PSA_SRV_IPC)
#endif // defined(MBEDTLS_ENTROPY_NV_SEED)
}

View File

@ -1,522 +0,0 @@
/**
* \file psa/crypto_struct.h
*
* \brief PSA cryptography module: Mbed TLS structured type implementations
*
* \note This file may not be included directly. Applications must
* include psa/crypto.h.
*
* This file contains the definitions of some data structures with
* implementation-specific definitions.
*
* In implementations with isolation between the application and the
* cryptography module, it is expected that the front-end and the back-end
* would have different versions of this file.
*
* <h3>Design notes about multipart operation structures</h3>
*
* Each multipart operation structure contains a `psa_algorithm_t alg`
* field which indicates which specific algorithm the structure is for.
* When the structure is not in use, `alg` is 0. Most of the structure
* consists of a union which is discriminated by `alg`.
*
* Note that when `alg` is 0, the content of other fields is undefined.
* In particular, it is not guaranteed that a freshly-initialized structure
* is all-zero: we initialize structures to something like `{0, 0}`, which
* is only guaranteed to initializes the first member of the union;
* GCC and Clang initialize the whole structure to 0 (at the time of writing),
* but MSVC and CompCert don't.
*
* In Mbed Crypto, multipart operation structures live independently from
* the key. This allows Mbed Crypto to free the key objects when destroying
* a key slot. If a multipart operation needs to remember the key after
* the setup function returns, the operation structure needs to contain a
* copy of the key.
*/
/*
* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_STRUCT_H
#define PSA_CRYPTO_STRUCT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Include the Mbed TLS configuration file, the way Mbed TLS does it
* in each of its header files. */
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbedtls/cipher.h"
#include "mbedtls/cmac.h"
#include "mbedtls/gcm.h"
#include "mbedtls/md.h"
#include "mbedtls/md2.h"
#include "mbedtls/md4.h"
#include "mbedtls/md5.h"
#include "mbedtls/ripemd160.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
struct psa_hash_operation_s
{
psa_algorithm_t alg;
union
{
unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
#if defined(MBEDTLS_MD2_C)
mbedtls_md2_context md2;
#endif
#if defined(MBEDTLS_MD4_C)
mbedtls_md4_context md4;
#endif
#if defined(MBEDTLS_MD5_C)
mbedtls_md5_context md5;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
mbedtls_ripemd160_context ripemd160;
#endif
#if defined(MBEDTLS_SHA1_C)
mbedtls_sha1_context sha1;
#endif
#if defined(MBEDTLS_SHA256_C)
mbedtls_sha256_context sha256;
#endif
#if defined(MBEDTLS_SHA512_C)
mbedtls_sha512_context sha512;
#endif
} ctx;
};
#define PSA_HASH_OPERATION_INIT {0, {0}}
static inline struct psa_hash_operation_s psa_hash_operation_init( void )
{
const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT;
return( v );
}
#if defined(MBEDTLS_MD_C)
typedef struct
{
/** The hash context. */
struct psa_hash_operation_s hash_ctx;
/** The HMAC part of the context. */
uint8_t opad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
} psa_hmac_internal_data;
#endif /* MBEDTLS_MD_C */
struct psa_mac_operation_s
{
psa_algorithm_t alg;
unsigned int key_set : 1;
unsigned int iv_required : 1;
unsigned int iv_set : 1;
unsigned int has_input : 1;
unsigned int is_sign : 1;
uint8_t mac_size;
union
{
unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
#if defined(MBEDTLS_MD_C)
psa_hmac_internal_data hmac;
#endif
#if defined(MBEDTLS_CMAC_C)
mbedtls_cipher_context_t cmac;
#endif
} ctx;
};
#define PSA_MAC_OPERATION_INIT {0, 0, 0, 0, 0, 0, 0, {0}}
static inline struct psa_mac_operation_s psa_mac_operation_init( void )
{
const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT;
return( v );
}
struct psa_cipher_operation_s
{
psa_algorithm_t alg;
unsigned int key_set : 1;
unsigned int iv_required : 1;
unsigned int iv_set : 1;
uint8_t iv_size;
uint8_t block_size;
union
{
unsigned dummy; /* Enable easier initializing of the union. */
mbedtls_cipher_context_t cipher;
} ctx;
};
#define PSA_CIPHER_OPERATION_INIT {0, 0, 0, 0, 0, 0, {0}}
static inline struct psa_cipher_operation_s psa_cipher_operation_init( void )
{
const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT;
return( v );
}
struct psa_aead_operation_s
{
psa_algorithm_t alg;
unsigned int key_set : 1;
unsigned int iv_set : 1;
uint8_t iv_size;
uint8_t block_size;
union
{
unsigned dummy; /* Enable easier initializing of the union. */
mbedtls_cipher_context_t cipher;
} ctx;
};
#define PSA_AEAD_OPERATION_INIT {0, 0, 0, 0, 0, {0}}
static inline struct psa_aead_operation_s psa_aead_operation_init( void )
{
const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT;
return( v );
}
#if defined(MBEDTLS_MD_C)
typedef struct
{
uint8_t *info;
size_t info_length;
psa_hmac_internal_data hmac;
uint8_t prk[PSA_HASH_MAX_SIZE];
uint8_t output_block[PSA_HASH_MAX_SIZE];
#if PSA_HASH_MAX_SIZE > 0xff
#error "PSA_HASH_MAX_SIZE does not fit in uint8_t"
#endif
uint8_t offset_in_block;
uint8_t block_number;
unsigned int state : 2;
unsigned int info_set : 1;
} psa_hkdf_key_derivation_t;
#endif /* MBEDTLS_MD_C */
#if defined(MBEDTLS_MD_C)
typedef enum
{
TLS12_PRF_STATE_INIT, /* no input provided */
TLS12_PRF_STATE_SEED_SET, /* seed has been set */
TLS12_PRF_STATE_KEY_SET, /* key has been set */
TLS12_PRF_STATE_LABEL_SET, /* label has been set */
TLS12_PRF_STATE_OUTPUT /* output has been started */
} psa_tls12_prf_key_derivation_state_t;
typedef struct psa_tls12_prf_key_derivation_s
{
#if PSA_HASH_MAX_SIZE > 0xff
#error "PSA_HASH_MAX_SIZE does not fit in uint8_t"
#endif
/* Indicates how many bytes in the current HMAC block have
* not yet been read by the user. */
uint8_t left_in_block;
/* The 1-based number of the block. */
uint8_t block_number;
psa_tls12_prf_key_derivation_state_t state;
uint8_t *seed;
size_t seed_length;
uint8_t *label;
size_t label_length;
psa_hmac_internal_data hmac;
uint8_t Ai[PSA_HASH_MAX_SIZE];
/* `HMAC_hash( prk, A(i) + seed )` in the notation of RFC 5246, Sect. 5. */
uint8_t output_block[PSA_HASH_MAX_SIZE];
} psa_tls12_prf_key_derivation_t;
#endif /* MBEDTLS_MD_C */
struct psa_key_derivation_s
{
psa_algorithm_t alg;
unsigned int can_output_key : 1;
size_t capacity;
union
{
/* Make the union non-empty even with no supported algorithms. */
uint8_t dummy;
#if defined(MBEDTLS_MD_C)
psa_hkdf_key_derivation_t hkdf;
psa_tls12_prf_key_derivation_t tls12_prf;
#endif
} ctx;
};
/* This only zeroes out the first byte in the union, the rest is unspecified. */
#define PSA_KEY_DERIVATION_OPERATION_INIT {0, 0, 0, {0}}
static inline struct psa_key_derivation_s psa_key_derivation_operation_init( void )
{
const struct psa_key_derivation_s v = PSA_KEY_DERIVATION_OPERATION_INIT;
return( v );
}
struct psa_key_policy_s
{
psa_key_usage_t usage;
psa_algorithm_t alg;
psa_algorithm_t alg2;
};
typedef struct psa_key_policy_s psa_key_policy_t;
#define PSA_KEY_POLICY_INIT {0, 0, 0}
static inline struct psa_key_policy_s psa_key_policy_init( void )
{
const struct psa_key_policy_s v = PSA_KEY_POLICY_INIT;
return( v );
}
/* The type used internally for key sizes.
* Public interfaces use size_t, but internally we use a smaller type. */
typedef uint16_t psa_key_bits_t;
/* The maximum value of the type used to represent bit-sizes.
* This is used to mark an invalid key size. */
#define PSA_KEY_BITS_TOO_LARGE ( (psa_key_bits_t) ( -1 ) )
/* The maximum size of a key in bits.
* Currently defined as the maximum that can be represented, rounded down
* to a whole number of bytes.
* This is an uncast value so that it can be used in preprocessor
* conditionals. */
#define PSA_MAX_KEY_BITS 0xfff8
/** A mask of flags that can be stored in key attributes.
*
* This type is also used internally to store flags in slots. Internal
* flags are defined in library/psa_crypto_core.h. Internal flags may have
* the same value as external flags if they are properly handled during
* key creation and in psa_get_key_attributes.
*/
typedef uint16_t psa_key_attributes_flag_t;
#define MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER \
( (psa_key_attributes_flag_t) 0x0001 )
/* A mask of key attribute flags used externally only.
* Only meant for internal checks inside the library. */
#define MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ( \
MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER | \
0 )
/* A mask of key attribute flags used both internally and externally.
* Currently there aren't any. */
#define MBEDTLS_PSA_KA_MASK_DUAL_USE ( \
0 )
typedef struct
{
psa_key_type_t type;
psa_key_lifetime_t lifetime;
psa_key_id_t id;
psa_key_policy_t policy;
psa_key_bits_t bits;
psa_key_attributes_flag_t flags;
} psa_core_key_attributes_t;
/* The server must be able to interpret the attributes as specified by the
* client. The server works with the psa_key_id_t encoding the key owner, but
* the client works with the psa_key_id_t not containing the key owner (pure
* psa_app_key_id_t. */
typedef struct
{
psa_key_type_t type;
psa_key_lifetime_t lifetime;
psa_app_key_id_t id;
psa_key_policy_t policy;
psa_key_bits_t bits;
psa_key_attributes_flag_t flags;
} psa_client_core_key_attributes_t;
#define PSA_CORE_KEY_ATTRIBUTES_INIT {0, 0, PSA_KEY_ID_INIT, PSA_KEY_POLICY_INIT, 0, 0}
struct psa_key_attributes_s
{
psa_core_key_attributes_t core;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_key_slot_number_t slot_number;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
void *domain_parameters;
size_t domain_parameters_size;
};
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, 0, NULL, 0}
#else
#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, NULL, 0}
#endif
typedef struct psa_client_key_attributes_s
{
psa_client_core_key_attributes_t core;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_key_slot_number_t slot_number;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
void *domain_parameters;
size_t domain_parameters_size;
} psa_client_key_attributes_t;
static inline struct psa_key_attributes_s psa_key_attributes_init( void )
{
const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT;
return( v );
}
static void psa_core_attributes_to_client(
const psa_core_key_attributes_t *server,
psa_client_core_key_attributes_t *client)
{
client->type = server->type;
client->lifetime = server->lifetime;
client->id = server->id.key_id;
client->policy = server->policy;
client->bits = server->bits;
client->flags = server->flags;
}
static void psa_core_attributes_to_server(
const psa_client_core_key_attributes_t *client,
psa_key_owner_id_t owner,
psa_core_key_attributes_t *server)
{
server->type = client->type;
server->lifetime = client->lifetime;
server->id.key_id = client->id;
server->id.owner = owner;
server->policy = client->policy;
server->bits = client->bits;
server->flags = client->flags;
}
static inline void psa_set_key_id(psa_key_attributes_t *attributes,
psa_key_id_t id)
{
attributes->core.id = id;
if( attributes->core.lifetime == PSA_KEY_LIFETIME_VOLATILE )
attributes->core.lifetime = PSA_KEY_LIFETIME_PERSISTENT;
}
static inline psa_key_id_t psa_get_key_id(
const psa_key_attributes_t *attributes)
{
return( attributes->core.id );
}
static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes,
psa_key_lifetime_t lifetime)
{
attributes->core.lifetime = lifetime;
if( lifetime == PSA_KEY_LIFETIME_VOLATILE )
{
#ifdef MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER
attributes->core.id.key_id = 0;
attributes->core.id.owner = 0;
#else
attributes->core.id = 0;
#endif
}
}
static inline psa_key_lifetime_t psa_get_key_lifetime(
const psa_key_attributes_t *attributes)
{
return( attributes->core.lifetime );
}
static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes,
psa_key_usage_t usage_flags)
{
attributes->core.policy.usage = usage_flags;
}
static inline psa_key_usage_t psa_get_key_usage_flags(
const psa_key_attributes_t *attributes)
{
return( attributes->core.policy.usage );
}
static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes,
psa_algorithm_t alg)
{
attributes->core.policy.alg = alg;
}
static inline psa_algorithm_t psa_get_key_algorithm(
const psa_key_attributes_t *attributes)
{
return( attributes->core.policy.alg );
}
/* This function is declared in crypto_extra.h, which comes after this
* header file, but we need the function here, so repeat the declaration. */
psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
psa_key_type_t type,
const uint8_t *data,
size_t data_length);
static inline void psa_set_key_type(psa_key_attributes_t *attributes,
psa_key_type_t type)
{
if( attributes->domain_parameters == NULL )
{
/* Common case: quick path */
attributes->core.type = type;
}
else
{
/* Call the bigger function to free the old domain paramteres.
* Ignore any errors which may arise due to type requiring
* non-default domain parameters, since this function can't
* report errors. */
(void) psa_set_key_domain_parameters( attributes, type, NULL, 0 );
}
}
static inline psa_key_type_t psa_get_key_type(
const psa_key_attributes_t *attributes)
{
return( attributes->core.type );
}
static inline void psa_set_key_bits(psa_key_attributes_t *attributes,
size_t bits)
{
if( bits > PSA_MAX_KEY_BITS )
attributes->core.bits = PSA_KEY_BITS_TOO_LARGE;
else
attributes->core.bits = (psa_key_bits_t) bits;
}
static inline size_t psa_get_key_bits(
const psa_key_attributes_t *attributes)
{
return( attributes->core.bits );
}
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_STRUCT_H */

View File

@ -1,73 +0,0 @@
/** \addtogroup hal */
/** @{*/
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SPM_API_H__
#define __SPM_API_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SPM-HAL SPM HAL API
* The HAL functions for PSA SPM
* @{
*/
/* ------------------------------------ HAL-SPE API ------------------------- */
#if defined(COMPONENT_SPE)
/**
* Start running the NSPE.
*
* Secure Processing Environment (SPE) expected to boot first. Once all
* the initializations are done, Nonsecure Processing Environment (NSPE)
* should be booted.
*
* @note The function must be implemented by target specific code.
*/
void spm_hal_start_nspe(void);
/**
* Configure memory protection mechanism.
*
* Apply memory protection schemes to ensure secure memory can only be accessed
* from secure-state.
*
* @note The function must be implemented by target specific code.
*
*/
void spm_hal_memory_protection_init(void);
#endif // defined(COMPONENT_SPE)
#ifdef __cplusplus
}
#endif
#endif // __SPM_API_H__
/** @}*/

View File

@ -1077,7 +1077,7 @@ extern "C" long PREFIX(_flen)(FILEHANDLE fh)
}
// Do not compile this code for TFM secure target
#if !defined(COMPONENT_SPE) || !defined(TARGET_TFM)
#if !defined(TARGET_TFM)
#if !defined(__MICROLIB)
__asm(".global __use_two_region_memory\n\t");
@ -1138,7 +1138,7 @@ MBED_USED extern "C" __value_in_regs struct __initial_stackheap __user_setup_sta
return _mbed_user_setup_stackheap(R0, R1, R2, R3);
}
#endif // !defined(COMPONENT_SPE) || !defined(TARGET_TFM)
#endif // !defined(TARGET_TFM)
#endif