1 /*
2 * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "critical_section.h"
9 #include "internal_status_code.h"
10 #include "spm.h"
11 #include "tfm_pools.h"
12 #include "load/service_defs.h"
13
14 #if !(defined CONFIG_TFM_CONN_HANDLE_MAX_NUM) || (CONFIG_TFM_CONN_HANDLE_MAX_NUM == 0)
15 #error "CONFIG_TFM_CONN_HANDLE_MAX_NUM must be defined and not zero."
16 #endif
17
18 /* Pools */
19 TFM_POOL_DECLARE(connection_pool, sizeof(struct connection_t),
20 CONFIG_TFM_CONN_HANDLE_MAX_NUM);
21
22 /*********************** Connection handle conversion APIs *******************/
23
24 #define CONVERSION_FACTOR_BITOFFSET 3
25 #define CONVERSION_FACTOR_VALUE (1 << CONVERSION_FACTOR_BITOFFSET)
26 /* Set 32 as the maximum */
27 #define CONVERSION_FACTOR_VALUE_MAX 0x20
28
29 #if CONVERSION_FACTOR_VALUE > CONVERSION_FACTOR_VALUE_MAX
30 #error "CONVERSION FACTOR OUT OF RANGE"
31 #endif
32
33 static uint32_t loop_index;
34
35 /*
36 * A connection instance connection_t allocated inside SPM is actually a memory
37 * address among the connection pool. Return this connection to the client directly
38 * exposes information of secure memory address. In this case, converting the
39 * connection into another handle value does not represent the memory address
40 * to avoid exposing secure memory directly to clients.
41 *
42 * This function converts the connection instance into another value by scaling
43 * the connection in pool offset, the converted value is named as a user handle.
44 *
45 * The formula:
46 * handle = (p_connection - POOL_START) * CONVERSION_FACTOR_VALUE +
47 * CLIENT_HANDLE_VALUE_MIN + loop_index
48 * where:
49 * CONVERSION_FACTOR_VALUE = 1 << CONVERSION_FACTOR_BITOFFSET, and should not
50 * exceed CONVERSION_FACTOR_VALUE_MAX.
51 *
52 * p_connection in RANGE[POOL_START, POOL_END]
53 * handle in RANGE[CLIENT_HANDLE_VALUE_MIN, 0x3FFFFFFF]
54 * loop_index in RANGE[0, CONVERSION_FACTOR_VALUE - 1]
55 *
56 * note:
57 * loop_index is used to promise same connection instance is converted into
58 * different user handles in short time.
59 */
connection_to_handle(struct connection_t * p_connection)60 psa_handle_t connection_to_handle(struct connection_t *p_connection)
61 {
62 psa_handle_t handle;
63
64 loop_index = (loop_index + 1) % CONVERSION_FACTOR_VALUE;
65 handle = (psa_handle_t)((((uintptr_t)p_connection -
66 (uintptr_t)connection_pool) << CONVERSION_FACTOR_BITOFFSET) +
67 CLIENT_HANDLE_VALUE_MIN + loop_index);
68
69 return handle;
70 }
71
72 /*
73 * This function converts a user handle into a corresponded connection instance.
74 * The converted value is validated before returning, an invalid handle instance
75 * is returned as NULL.
76 *
77 * The formula:
78 * p_connection = ((handle - CLIENT_HANDLE_VALUE_MIN) /
79 * CONVERSION_FACTOR_VALUE) + POOL_START
80 * where:
81 * CONVERSION_FACTOR_VALUE = 1 << CONVERSION_FACTOR_BITOFFSET, and should not
82 * exceed CONVERSION_FACTOR_VALUE_MAX.
83 *
84 * p_connection in RANGE[POOL_START, POOL_END]
85 * handle in RANGE[CLIENT_HANDLE_VALUE_MIN, 0x3FFFFFFF]
86 * loop_index in RANGE[0, CONVERSION_FACTOR_VALUE - 1]
87 */
handle_to_connection(psa_handle_t handle)88 struct connection_t *handle_to_connection(psa_handle_t handle)
89 {
90 struct connection_t *p_connection;
91
92 if (handle == PSA_NULL_HANDLE) {
93 return NULL;
94 }
95
96 p_connection = (struct connection_t *)((((uintptr_t)handle -
97 CLIENT_HANDLE_VALUE_MIN) >> CONVERSION_FACTOR_BITOFFSET) +
98 (uintptr_t)connection_pool);
99
100 return p_connection;
101 }
102
103 /* Service handle management functions */
spm_init_connection_space(void)104 void spm_init_connection_space(void)
105 {
106 if (tfm_pool_init(connection_pool,
107 POOL_BUFFER_SIZE(connection_pool),
108 sizeof(struct connection_t),
109 CONFIG_TFM_CONN_HANDLE_MAX_NUM) != PSA_SUCCESS) {
110 tfm_core_panic();
111 }
112 }
113
spm_allocate_connection(void)114 struct connection_t *spm_allocate_connection(void)
115 {
116 /* Get buffer for handle list structure from handle pool */
117 return (struct connection_t *)tfm_pool_alloc(connection_pool);
118 }
119
spm_validate_connection(const struct connection_t * p_connection)120 psa_status_t spm_validate_connection(const struct connection_t *p_connection)
121 {
122 /* Check the handle address is valid */
123 if (is_valid_chunk_data_in_pool(connection_pool,
124 (uint8_t *)p_connection) != true) {
125 return SPM_ERROR_GENERIC;
126 }
127
128 return PSA_SUCCESS;
129 }
130
spm_free_connection(struct connection_t * p_connection)131 void spm_free_connection(struct connection_t *p_connection)
132 {
133 struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
134
135 SPM_ASSERT(p_connection != NULL);
136
137 CRITICAL_SECTION_ENTER(cs_assert);
138 /* Back handle buffer to pool */
139 tfm_pool_free(connection_pool, p_connection);
140 CRITICAL_SECTION_LEAVE(cs_assert);
141 }
142