1 /*
2  * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
3  * Copyright (c) 2022-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 "ffm/backend.h"
12 #include "ffm/psa_api.h"
13 #include "load/service_defs.h"
14 #include "spm.h"
15 #include "utilities.h"
16 
17 /* PSA APIs only needed by connection-based services */
18 
tfm_spm_client_psa_connect(uint32_t sid,uint32_t version)19 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
20 {
21     int32_t client_id;
22     struct connection_t *p_connection;
23     psa_status_t status;
24 
25     bool ns_caller = tfm_spm_is_ns_caller();
26 
27     client_id = tfm_spm_get_client_id(ns_caller);
28     status = spm_psa_connect_client_id_associated(&p_connection, sid, version, client_id);
29     if (status != PSA_SUCCESS) {
30         return status;
31     }
32 
33     status = backend_messaging(p_connection);
34 
35     p_connection->status = TFM_HANDLE_STATUS_ACTIVE;
36     return status;
37 }
38 
spm_psa_connect_client_id_associated(struct connection_t ** p_connection,uint32_t sid,uint32_t version,int32_t client_id)39 psa_status_t spm_psa_connect_client_id_associated(struct connection_t **p_connection,
40                                                   uint32_t sid, uint32_t version, int32_t client_id)
41 {
42     const struct service_t *service;
43     struct connection_t *connection;
44     bool ns_caller = (client_id < 0) ? true : false;
45 
46     /*
47      * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
48      * platform.
49      */
50     service = tfm_spm_get_service_by_sid(sid);
51     if (!service) {
52         return PSA_ERROR_CONNECTION_REFUSED;
53     }
54 
55     /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
56     if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
57         return PSA_ERROR_PROGRAMMER_ERROR;
58     }
59 
60     /*
61      * It is a PROGRAMMER ERROR if the caller is not authorized to access the
62      * RoT Service.
63      */
64     if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
65         return PSA_ERROR_CONNECTION_REFUSED;
66     }
67 
68     /*
69      * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
70      * not supported on the platform.
71      */
72     if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
73         return PSA_ERROR_CONNECTION_REFUSED;
74     }
75 
76     /*
77      * Create connection handle here since it is possible to return the error
78      * code to client when creation fails.
79      *
80      * Current SPM doesn't support multiple context management. There is only one
81      * instance in SPM to call the connection pool allocation. It is no need to be
82      * protected.
83      * Protection should be established after the context management is implemented.
84      */
85     connection = spm_allocate_connection();
86     if (!connection) {
87         return PSA_ERROR_CONNECTION_BUSY;
88     }
89 
90     spm_init_idle_connection(connection, service, client_id);
91     connection->msg.type = PSA_IPC_CONNECT;
92 
93     *p_connection = connection;
94 
95     return PSA_SUCCESS;
96 }
97 
tfm_spm_client_psa_close(psa_handle_t handle)98 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
99 {
100     bool ns_caller = tfm_spm_is_ns_caller();
101     return spm_psa_close_client_id_associated(handle, tfm_spm_get_client_id(ns_caller));
102 }
103 
spm_psa_close_client_id_associated(psa_handle_t handle,int32_t client_id)104 psa_status_t spm_psa_close_client_id_associated(psa_handle_t handle, int32_t client_id)
105 {
106     struct connection_t *p_connection;
107     psa_status_t status;
108 
109     /* It will have no effect if called with the NULL handle */
110     if (handle == PSA_NULL_HANDLE) {
111         return PSA_SUCCESS;
112     }
113 
114     /* It is a PROGRAMMER ERROR if called with a stateless handle. */
115     if (IS_STATIC_HANDLE(handle)) {
116         return PSA_ERROR_PROGRAMMER_ERROR;
117     }
118 
119     /*
120      * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
121      * the null handle.
122      */
123     status = spm_get_idle_connection(&p_connection, handle, client_id);
124     if (status != PSA_SUCCESS) {
125         return status;
126     }
127 
128     p_connection->msg.type = PSA_IPC_DISCONNECT;
129 
130     status = backend_messaging(p_connection);
131 
132     p_connection->status = TFM_HANDLE_STATUS_TO_FREE;
133 
134     return status;
135 }
136 
tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle,void * rhandle)137 psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
138 {
139     struct connection_t *handle;
140 
141     /* It is a fatal error if message handle is invalid */
142     handle = spm_msg_handle_to_connection(msg_handle);
143     if (!handle) {
144         tfm_core_panic();
145     }
146 
147     /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
148     if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) {
149         tfm_core_panic();
150     }
151 
152     handle->msg.rhandle = rhandle;
153 
154     return PSA_SUCCESS;
155 }
156