1 /*
2 * Copyright (c) 2026, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <common/debug.h>
9 #include <drivers/arm/sfcp.h>
10 #include "psa/client.h"
11 #include "sfcp_psa_protocol.h"
12
13 /* These are specific to the server to which we are sending PSA
14 * requests. We need the node ID for the remote node and the
15 * application ID of the PSA service
16 */
17 #define SFCP_PSA_SERVER_NODE_ID (0)
18 #define SFCP_PSA_SERVER_APPLICATION_ID (0)
19
20 /* TODO: Tune this value. Initially aim to only make use of embed message
21 * protocol if it can fit in a single MHU transfer (assuming a standard
22 * number of channels of 16 with 1 channel for message length and 1
23 * channel for signalling). This will need to be tuned per platform
24 */
25 #define SFCP_MHU_MAX_TRANSFER_SIZE ((16 - 2) * sizeof(uint32_t))
26
27 /* Use for both the message and reply, define to the larger of
28 * the two
29 *
30 * TODO: This needs to be reconsidered if reentrancy is required
31 */
32 static __aligned(4) uint8_t
33 psa_payload_buf[SFCP_BUFFER_MINIMUM_SIZE +
34 (sizeof(struct serialized_psa_msg_t) >
35 sizeof(struct serialized_psa_reply_t) ?
36 sizeof(struct serialized_psa_msg_t) :
37 sizeof(struct serialized_psa_reply_t))];
38
39 static enum sfcp_protocol_version_t
select_protocol_version(const psa_invec * in_vec,size_t in_len,const psa_outvec * out_vec,size_t out_len)40 select_protocol_version(const psa_invec *in_vec, size_t in_len,
41 const psa_outvec *out_vec, size_t out_len)
42 {
43 size_t comms_embed_msg_min_size;
44 size_t comms_embed_reply_min_size;
45 size_t in_size_total = 0;
46 size_t out_size_total = 0;
47 size_t i;
48
49 for (i = 0U; i < in_len; ++i) {
50 in_size_total += in_vec[i].len;
51 }
52 for (i = 0U; i < out_len; ++i) {
53 out_size_total += out_vec[i].len;
54 }
55
56 comms_embed_msg_min_size =
57 sizeof(struct serialized_sfcp_header_t) +
58 sizeof(struct sfcp_embed_msg_t) -
59 sizeof(((struct sfcp_embed_msg_t *)0)->payload);
60
61 comms_embed_reply_min_size =
62 sizeof(struct serialized_sfcp_header_t) +
63 sizeof(struct sfcp_embed_reply_t) -
64 sizeof(((struct sfcp_embed_reply_t *)0)->payload);
65
66 if ((comms_embed_msg_min_size + in_size_total >
67 SFCP_MHU_MAX_TRANSFER_SIZE) ||
68 (comms_embed_reply_min_size + out_size_total >
69 SFCP_MHU_MAX_TRANSFER_SIZE)) {
70 return SFCP_PROTOCOL_POINTER_ACCESS;
71 } else {
72 return SFCP_PROTOCOL_EMBED;
73 }
74 }
75
select_client_id(void)76 static uint16_t select_client_id(void)
77 {
78 /* Client ID value of 0 is reserved
79 *
80 * TODO: This needs to be reconsidered if reentrancy becomes a problem.
81 * In this case, we need to dynamically allocate a client ID to each
82 * caller
83 */
84 return 1;
85 }
86
psa_call(psa_handle_t handle,int32_t type,const psa_invec * in_vec,size_t in_len,psa_outvec * out_vec,size_t out_len)87 psa_status_t psa_call(psa_handle_t handle, int32_t type,
88 const psa_invec *in_vec, size_t in_len,
89 psa_outvec *out_vec, size_t out_len)
90 {
91 psa_status_t status;
92 enum sfcp_error_t sfcp_err;
93 struct serialized_psa_msg_t *psa_msg;
94 struct serialized_psa_reply_t *psa_reply = NULL;
95 size_t psa_msg_len;
96 size_t payload_len;
97 struct sfcp_packet_t *msg;
98 size_t msg_size;
99 struct sfcp_reply_metadata_t metadata;
100 psa_status_t return_val;
101 const uint16_t client_id = select_client_id();
102
103 if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
104 in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
105 return PSA_ERROR_INVALID_ARGUMENT;
106 }
107
108 sfcp_err = sfcp_init_msg(psa_payload_buf, sizeof(psa_payload_buf),
109 SFCP_PSA_SERVER_NODE_ID,
110 SFCP_PSA_SERVER_APPLICATION_ID, client_id,
111 true, false, 0, (uint8_t **)&psa_msg,
112 &payload_len, &msg, &msg_size, &metadata);
113 if (sfcp_err != SFCP_ERROR_SUCCESS) {
114 return PSA_ERROR_COMMUNICATION_FAILURE;
115 }
116
117 if (payload_len < sizeof(struct serialized_psa_msg_t)) {
118 return PSA_ERROR_INSUFFICIENT_STORAGE;
119 }
120
121 psa_msg->header.protocol_ver =
122 select_protocol_version(in_vec, in_len, out_vec, out_len);
123
124 VERBOSE("[SFCP] Sending message\n");
125 VERBOSE("protocol_ver=%u\n", psa_msg->header.protocol_ver);
126 for (size_t idx = 0; idx < in_len; idx++) {
127 VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
128 VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
129 }
130
131 status = sfcp_protocol_serialize_msg(handle, type, in_vec, in_len,
132 out_vec, out_len, psa_msg,
133 &psa_msg_len);
134 if (status != PSA_SUCCESS) {
135 return status;
136 }
137
138 sfcp_err = sfcp_send_msg(msg, msg_size, psa_msg_len);
139 if (sfcp_err != SFCP_ERROR_SUCCESS) {
140 return PSA_ERROR_COMMUNICATION_FAILURE;
141 }
142
143 do {
144 sfcp_err = sfcp_receive_reply(psa_payload_buf,
145 sizeof(psa_payload_buf), metadata,
146 (uint8_t **)&psa_reply,
147 &payload_len);
148 } while (sfcp_err == SFCP_ERROR_NO_REPLY_AVAILABLE);
149 if (sfcp_err != SFCP_ERROR_SUCCESS) {
150 return PSA_ERROR_COMMUNICATION_FAILURE;
151 }
152
153 VERBOSE("[SFCP] Received reply\n");
154 VERBOSE("protocol_ver=%u\n", psa_reply->header.protocol_ver);
155
156 status = sfcp_protocol_deserialize_reply(out_vec, out_len, &return_val,
157 psa_reply, payload_len);
158 if (status != PSA_SUCCESS) {
159 return status;
160 }
161
162 VERBOSE("return_val=%d\n", return_val);
163 for (size_t idx = 0U; idx < out_len; idx++) {
164 VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
165 VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
166 }
167
168 return return_val;
169 }
170