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