1 /*
2  * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
3  * Copyright (c) 2022-2023 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 
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     struct service_t *service;
22     struct connection_t *p_connection;
23     int32_t client_id;
24     psa_handle_t handle;
25     bool ns_caller = tfm_spm_is_ns_caller();
26     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
27 
28     /*
29      * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
30      * platform.
31      */
32     service = tfm_spm_get_service_by_sid(sid);
33     if (!service) {
34         return PSA_ERROR_CONNECTION_REFUSED;
35     }
36 
37     /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
38     if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
39         return PSA_ERROR_PROGRAMMER_ERROR;
40     }
41 
42     /*
43      * It is a PROGRAMMER ERROR if the caller is not authorized to access the
44      * RoT Service.
45      */
46     if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
47         return PSA_ERROR_CONNECTION_REFUSED;
48     }
49 
50     /*
51      * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
52      * not supported on the platform.
53      */
54     if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
55         return PSA_ERROR_CONNECTION_REFUSED;
56     }
57 
58     client_id = tfm_spm_get_client_id(ns_caller);
59 
60     /*
61      * Create connection handle here since it is possible to return the error
62      * code to client when creation fails.
63      */
64     CRITICAL_SECTION_ENTER(cs_assert);
65     p_connection = spm_allocate_connection();
66     CRITICAL_SECTION_LEAVE(cs_assert);
67     if (!p_connection) {
68         return PSA_ERROR_CONNECTION_BUSY;
69     }
70 
71     handle = connection_to_handle(p_connection);
72     spm_fill_message(p_connection, service, handle, PSA_IPC_CONNECT, client_id);
73 
74     return backend_messaging(service, p_connection);
75 }
76 
tfm_spm_client_psa_close(psa_handle_t handle)77 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
78 {
79     struct service_t *service;
80     struct connection_t *p_connection;
81     int32_t client_id;
82     bool ns_caller = tfm_spm_is_ns_caller();
83 
84     /* It will have no effect if called with the NULL handle */
85     if (handle == PSA_NULL_HANDLE) {
86         return PSA_SUCCESS;
87     }
88 
89     /* It is a PROGRAMMER ERROR if called with a stateless handle. */
90     if (IS_STATIC_HANDLE(handle)) {
91         return PSA_ERROR_PROGRAMMER_ERROR;
92     }
93 
94     client_id = tfm_spm_get_client_id(ns_caller);
95 
96     /*
97      * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
98      * the null handle.
99      */
100     p_connection = spm_get_client_connection(handle, client_id);
101     if (!p_connection) {
102         return PSA_ERROR_PROGRAMMER_ERROR;
103     }
104 
105     service = p_connection->service;
106     if (!service) {
107         /* FixMe: Need to implement one mechanism to resolve this failure. */
108         return PSA_ERROR_PROGRAMMER_ERROR;
109     }
110 
111     /*
112      * It is a PROGRAMMER ERROR if the connection is currently handling a
113      * request.
114      */
115     if (p_connection->status == TFM_HANDLE_STATUS_ACTIVE) {
116         return PSA_ERROR_PROGRAMMER_ERROR;
117     }
118 
119     spm_fill_message(p_connection, service, handle, PSA_IPC_DISCONNECT, client_id);
120 
121     return backend_messaging(service, p_connection);
122 }
123 
tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle,void * rhandle)124 void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
125 {
126     struct connection_t *handle;
127 
128     /* It is a fatal error if message handle is invalid */
129     handle = spm_msg_handle_to_connection(msg_handle);
130     if (!handle) {
131         tfm_core_panic();
132     }
133 
134     /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
135     if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) {
136         tfm_core_panic();
137     }
138 
139     handle->msg.rhandle = rhandle;
140     handle->rhandle = rhandle;
141 }
142