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