blob: 28a49256765b303f9116c550edb3a5da0d8f0ef0 [file] [log] [blame]
Tamas Ban53ac24f2022-01-18 16:32:18 +01001/*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdint.h>
8#include <string.h>
9
10#include <common/debug.h>
11#include <drivers/arm/mhu.h>
12#include <drivers/arm/rss_comms.h>
13#include <initial_attestation.h>
14#include <psa/client.h>
15
16#include <platform_def.h>
17
18#define TYPE_OFFSET U(16)
19#define TYPE_MASK (0xFFFFUL << TYPE_OFFSET)
20#define IN_LEN_OFFSET U(8)
21#define IN_LEN_MASK (0xFFUL << IN_LEN_OFFSET)
22#define OUT_LEN_OFFSET U(0)
23#define OUT_LEN_MASK (0xFFUL << OUT_LEN_OFFSET)
24
25#define PARAM_PACK(type, in_len, out_len) \
26 (((((uint32_t)type) << TYPE_OFFSET) & TYPE_MASK) | \
27 ((((uint32_t)in_len) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
28 ((((uint32_t)out_len) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
29
30#define PARAM_UNPACK_IN_LEN(ctrl_param) \
31 ((size_t)(((ctrl_param) & IN_LEN_MASK) >> IN_LEN_OFFSET))
32
33/* Message types */
34struct __packed packed_psa_call_t {
35 uint8_t protocol_ver;
36 uint8_t seq_num;
37 uint16_t client_id;
38 psa_handle_t handle;
39 uint32_t ctrl_param; /* type, in_len, out_len */
40 uint16_t io_size[4];
41};
42
43struct __packed packed_psa_reply_t {
44 uint8_t protocol_ver;
45 uint8_t seq_num;
46 uint16_t client_id;
47 int32_t return_val;
48 uint16_t out_size[4];
49};
50
51/*
52 * In the current implementation the RoT Service request that requires the
53 * biggest message buffer is the RSS_ATTEST_GET_TOKEN. The maximum required
54 * buffer size is calculated based on the platform-specific needs of
55 * this request.
56 */
57#define MAX_REQUEST_PAYLOAD_SIZE (PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64 \
58 + PLAT_ATTEST_TOKEN_MAX_SIZE)
59
60/* Buffer to store the messages to be sent/received. */
61static uint8_t message_buf[MAX_REQUEST_PAYLOAD_SIZE] __aligned(4);
62
63static int32_t pack_params(const psa_invec *invecs,
64 size_t in_len,
65 uint8_t *buf,
66 size_t *buf_len)
67{
68 uint32_t i;
69 size_t payload_size = 0U;
70
71 for (i = 0U; i < in_len; ++i) {
72 if (invecs[i].len > *buf_len - payload_size) {
73 return -1;
74 }
75 memcpy(buf + payload_size, invecs[i].base, invecs[i].len);
76 payload_size += invecs[i].len;
77 }
78
79 *buf_len = payload_size;
80 return 0;
81}
82
83static int serialise_message(const struct packed_psa_call_t *msg,
84 const psa_invec *invecs,
85 uint8_t *payload_buf,
86 size_t *payload_len)
87{
88 size_t message_len = 0U;
89 size_t len;
90
91 /* Copy the message header into the payload buffer. */
92 len = sizeof(*msg);
93 if (len > *payload_len) {
94 ERROR("[RSS-COMMS] Message buffer too small.\n");
95 return -1;
96 }
97 memcpy(payload_buf, (const void *)msg, len);
98 message_len += len;
99
100 /* The input data will follow the message header in the payload buffer. */
101 len = *payload_len - message_len;
102 if (pack_params(invecs, PARAM_UNPACK_IN_LEN(msg->ctrl_param),
103 payload_buf + message_len, &len) != 0) {
104 ERROR("[RSS-COMMS] Message buffer too small.\n");
105 return -1;
106 }
107 message_len += len;
108
109 *payload_len = message_len;
110 return 0;
111}
112
113static void unpack_params(const uint8_t *buf,
114 psa_outvec *outvecs,
115 size_t out_len)
116{
117 size_t i;
118
119 for (i = 0U; i < out_len; ++i) {
120 memcpy(outvecs[i].base, buf, outvecs[i].len);
121 buf += outvecs[i].len;
122 }
123}
124
125static void deserialise_reply(struct packed_psa_reply_t *reply,
126 psa_outvec *outvecs,
127 size_t outlen,
128 const uint8_t *message,
129 size_t message_len)
130{
131 uint32_t i;
132
133 memcpy(reply, message, sizeof(*reply));
134
135 /* Outvecs */
136 for (i = 0U; i < outlen; ++i) {
137 outvecs[i].len = reply->out_size[i];
138 }
139
140 unpack_params(message + sizeof(*reply), outvecs, outlen);
141}
142
143psa_status_t psa_call(psa_handle_t handle, int32_t type,
144 const psa_invec *in_vec, size_t in_len,
145 psa_outvec *out_vec, size_t out_len)
146{
147 enum mhu_error_t err;
148 static uint32_t seq_num = 1U;
149 struct packed_psa_call_t msg = {
150 .protocol_ver = 0U,
151 .seq_num = seq_num,
152 /* No need to distinguish callers (currently concurrent calls are not supported). */
153 .client_id = 1U,
154 .handle = handle,
155 .ctrl_param = PARAM_PACK(type, in_len, out_len),
156 };
157
158 struct packed_psa_reply_t reply = {0};
159 size_t message_size;
160 uint32_t i;
161
162 /* Fill msg iovec lengths */
163 for (i = 0U; i < in_len; ++i) {
164 msg.io_size[i] = in_vec[i].len;
165 }
166 for (i = 0U; i < out_len; ++i) {
167 msg.io_size[in_len + i] = out_vec[i].len;
168 }
169
170 message_size = sizeof(message_buf);
171 if (serialise_message(&msg, in_vec, message_buf, &message_size)) {
172 /* Local buffer is probably too small. */
173 return PSA_ERROR_INSUFFICIENT_MEMORY;
174 }
175
176 err = mhu_send_data(message_buf, message_size);
177 if (err != MHU_ERR_NONE) {
178 return PSA_ERROR_COMMUNICATION_FAILURE;
179 }
180
181 message_size = sizeof(message_buf);
182#if DEBUG
183 /*
184 * Poisoning the message buffer (with a known pattern).
185 * Helps in detecting hypothetical RSS communication bugs.
186 */
187 memset(message_buf, 0xA5, message_size);
188#endif
189 err = mhu_receive_data(message_buf, &message_size);
190 if (err != MHU_ERR_NONE) {
191 return PSA_ERROR_COMMUNICATION_FAILURE;
192 }
193
194 deserialise_reply(&reply, out_vec, out_len, message_buf, message_size);
195
196 seq_num++;
197
198 VERBOSE("[RSS-COMMS] Received reply\n");
199 VERBOSE("protocol_ver=%d\n", reply.protocol_ver);
200 VERBOSE("seq_num=%d\n", reply.seq_num);
201 VERBOSE("client_id=%d\n", reply.client_id);
202 VERBOSE("return_val=%d\n", reply.return_val);
203 VERBOSE("out_size[0]=%d\n", reply.out_size[0]);
204
205 return reply.return_val;
206}
207
208int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
209{
210 enum mhu_error_t err;
211
212 err = mhu_init_sender(mhu_sender_base);
213 if (err != MHU_ERR_NONE) {
214 ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err);
215 return -1;
216 }
217
218 err = mhu_init_receiver(mhu_receiver_base);
219 if (err != MHU_ERR_NONE) {
220 ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err);
221 return -1;
222 }
223
224 return 0;
225}