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