blob: c83888c6777f2019ec220107e2474a51a05266f7 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <attestation.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00007#include <debug.h>
8#include <granule.h>
9#include <measurement.h>
10#include <realm.h>
AlexeiFedorov5b186ad2023-04-26 14:43:18 +010011#include <rsi-handler.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <smc-rsi.h>
13#include <smc.h>
14#include <string.h>
15#include <utils_def.h>
16
17#define MAX_EXTENDED_SIZE (64U)
18
19/*
20 * Return the Realm Personalization Value.
21 *
22 * Arguments:
23 * rd - The Realm descriptor.
Mate Toth-Pal071aa562023-07-04 09:09:26 +020024 * claim_ptr - The start address of the Realm Personalization Value claim
25 * claim_len - The length of the Realm Personalization Value claim
Soby Mathewb4c6df42022-11-09 11:13:29 +000026 */
Mate Toth-Pal071aa562023-07-04 09:09:26 +020027static void get_rpv(struct rd *rd, void **claim_ptr, size_t *claim_len)
Soby Mathewb4c6df42022-11-09 11:13:29 +000028{
Mate Toth-Pal071aa562023-07-04 09:09:26 +020029 *claim_ptr = (uint8_t *)&(rd->rpv[0]);
30 *claim_len = RPV_SIZE;
Soby Mathewb4c6df42022-11-09 11:13:29 +000031}
32
33/*
34 * Save the input parameters in the context for later iterations to check for
35 * consistency.
36 */
37static void save_input_parameters(struct rec *rec)
38{
39 rec->token_sign_ctx.token_ipa = rec->regs[1];
40 (void)memcpy(rec->token_sign_ctx.challenge, &rec->regs[2],
41 ATTEST_CHALLENGE_SIZE);
42}
43
44/*
45 * Verify that in all the iterations the input parameters are the same
46 * as in the initial call.
47 */
48static bool verify_input_parameters_consistency(struct rec *rec)
49{
50 return rec->token_sign_ctx.token_ipa == rec->regs[1];
51}
52
53/*
AlexeiFedorov97844202023-04-27 15:17:35 +010054 * Function to continue with the sign operation
Soby Mathewb4c6df42022-11-09 11:13:29 +000055 */
56static void attest_token_continue_sign_state(struct rec *rec,
AlexeiFedorov97844202023-04-27 15:17:35 +010057 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +000058{
59 /*
60 * Sign and finish creating the token.
61 */
62 enum attest_token_err_t ret =
63 attest_realm_token_sign(&(rec->token_sign_ctx.ctx),
Mate Toth-Pal071aa562023-07-04 09:09:26 +020064 &(rec->rmm_realm_token_len));
Soby Mathewb4c6df42022-11-09 11:13:29 +000065
66 if ((ret == ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS) ||
67 (ret == ATTEST_TOKEN_ERR_SUCCESS)) {
68 /*
69 * Return to RSI handler function after each iteration
70 * to check is there anything else to do (pending IRQ)
71 * or next signing iteration can be executed.
72 */
Soby Mathewb4c6df42022-11-09 11:13:29 +000073 res->smc_res.x[0] = RSI_INCOMPLETE;
74
75 /* If this was the last signing cycle */
76 if (ret == ATTEST_TOKEN_ERR_SUCCESS) {
77 rec->token_sign_ctx.state =
78 ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS;
79 }
80 } else {
81 /* Accessible only in case of failure during token signing */
82 ERROR("FATAL_ERROR: Realm token creation failed\n");
83 panic();
84 }
85}
86
87/*
AlexeiFedorov97844202023-04-27 15:17:35 +010088 * Function to continue with the token write operation
Soby Mathewb4c6df42022-11-09 11:13:29 +000089 */
90static void attest_token_continue_write_state(struct rec *rec,
AlexeiFedorov97844202023-04-27 15:17:35 +010091 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +000092{
Soby Mathewb4c6df42022-11-09 11:13:29 +000093 struct granule *gr;
94 uint8_t *realm_att_token;
95 unsigned long realm_att_token_ipa = rec->regs[1];
96 enum s2_walk_status walk_status;
97 struct s2_walk_result walk_res = { 0UL };
Mate Toth-Pal071aa562023-07-04 09:09:26 +020098 size_t attest_token_len;
Soby Mathewb4c6df42022-11-09 11:13:29 +000099
100 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000101 * Translate realm granule IPA to PA. If returns with
102 * WALK_SUCCESS then the last level page table (llt),
103 * which holds the realm_att_token_buf mapping, is locked.
104 */
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +0100105 walk_status = realm_ipa_to_pa(rec, realm_att_token_ipa, &walk_res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000106
107 /* Walk parameter validity was checked by RSI_ATTESTATION_TOKEN_INIT */
108 assert(walk_status != WALK_INVALID_PARAMS);
109
110 if (walk_status == WALK_FAIL) {
AlexeiFedorovd2e1bbd2023-04-18 15:18:39 +0100111 if (walk_res.ripas_val == RIPAS_EMPTY) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000112 res->smc_res.x[0] = RSI_ERROR_INPUT;
113 } else {
114 /*
AlexeiFedorov97844202023-04-27 15:17:35 +0100115 * Translation failed, IPA is not mapped.
116 * Return to NS host to fix the issue.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117 */
AlexeiFedorov97844202023-04-27 15:17:35 +0100118 res->action = STAGE_2_TRANSLATION_FAULT;
119 res->rtt_level = walk_res.rtt_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120 }
121 return;
122 }
123
124 /* Map realm data granule to RMM address space */
125 gr = find_granule(walk_res.pa);
126 realm_att_token = granule_map(gr, SLOT_RSI_CALL);
127
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200128 attest_token_len = attest_cca_token_create(realm_att_token,
129 ATTEST_TOKEN_BUFFER_SIZE,
130 (void *)rec->rmm_realm_token_buf,
131 rec->rmm_realm_token_len);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000132
133 /* Unmap realm granule */
134 buffer_unmap(realm_att_token);
135
136 /* Unlock last level page table (walk_res.g_llt) */
137 granule_unlock(walk_res.llt);
138
139 /* Write output parameters */
140 if (attest_token_len == 0) {
141 res->smc_res.x[0] = RSI_ERROR_INPUT;
142 } else {
143 res->smc_res.x[0] = RSI_SUCCESS;
144 res->smc_res.x[1] = attest_token_len;
145 }
146
147 /* The signing has either succeeded or failed. Reset the state. */
148 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
149}
150
AlexeiFedorov97844202023-04-27 15:17:35 +0100151void handle_rsi_attest_token_init(struct rec *rec, struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000152{
153 struct rd *rd = NULL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000154 unsigned long realm_buf_ipa = rec->regs[1];
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200155 void *rpv_ptr;
156 size_t rpv_len;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000157 int att_ret;
158
159 assert(rec != NULL);
160
AlexeiFedorov97844202023-04-27 15:17:35 +0100161 res->action = UPDATE_REC_RETURN_TO_REALM;
162
Soby Mathewb4c6df42022-11-09 11:13:29 +0000163 /*
164 * Calling RSI_ATTESTATION_TOKEN_INIT any time aborts any ongoing
165 * operation.
166 * TODO: This can be moved to attestation lib
167 */
168 if (rec->token_sign_ctx.state != ATTEST_SIGN_NOT_STARTED) {
169 int restart;
170
171 rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
172 restart = attestation_heap_reinit_pe(rec->aux_data.attest_heap_buf,
AlexeiFedoroveaec0c42023-02-01 18:13:32 +0000173 REC_HEAP_SIZE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000174 if (restart != 0) {
175 /* There is no provision for this failure so panic */
176 panic();
177 }
178 }
179
180 if (!GRANULE_ALIGNED(realm_buf_ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100181 res->smc_res.x[0] = RSI_ERROR_INPUT;
182 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000183 }
184
185 /*
186 * rd lock is acquired so that measurement cannot be updated
187 * simultaneously by another rec
188 */
189 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
190 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
191 if (!addr_in_par(rd, realm_buf_ipa)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100192 res->smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000193 goto out_unmap_rd;
194 }
195
196 /*
197 * Save the input parameters in the context for later iterations
198 * to check.
199 */
200 save_input_parameters(rec);
201
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200202 get_rpv(rd, &rpv_ptr, &rpv_len);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000203 att_ret = attest_realm_token_create(rd->algorithm, rd->measurement,
204 MEASUREMENT_SLOT_NR,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200205 rpv_ptr,
206 rpv_len,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000207 &rec->token_sign_ctx,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200208 rec->rmm_realm_token_buf,
209 sizeof(rec->rmm_realm_token_buf));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000210 if (att_ret != 0) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100211 ERROR("FATAL_ERROR: Realm token creation failed\n");
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212 panic();
213 }
214
215 rec->token_sign_ctx.state = ATTEST_SIGN_IN_PROGRESS;
AlexeiFedorov97844202023-04-27 15:17:35 +0100216 res->smc_res.x[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000217
218out_unmap_rd:
219 buffer_unmap(rd);
220 granule_unlock(rec->realm_info.g_rd);
AlexeiFedorov97844202023-04-27 15:17:35 +0100221}
222
223/*
224 * Return 'false' if no IRQ is pending,
225 * return 'true' if there is an IRQ pending, and need to return to Host.
226 */
227static bool check_pending_irq(void)
228{
229 return (read_isr_el1() != 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000230}
231
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232void handle_rsi_attest_token_continue(struct rec *rec,
AlexeiFedorov97844202023-04-27 15:17:35 +0100233 struct rmi_rec_exit *rec_exit,
234 struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000235{
236 assert(rec != NULL);
AlexeiFedorov97844202023-04-27 15:17:35 +0100237 assert(rec_exit != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000238
AlexeiFedorov97844202023-04-27 15:17:35 +0100239 res->action = UPDATE_REC_RETURN_TO_REALM;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240
241 if (!verify_input_parameters_consistency(rec)) {
242 res->smc_res.x[0] = RSI_ERROR_INPUT;
243 return;
244 }
245
AlexeiFedorov97844202023-04-27 15:17:35 +0100246 while (true) {
247 switch (rec->token_sign_ctx.state) {
248 case ATTEST_SIGN_NOT_STARTED:
249 /*
250 * Before this call the initial attestation token call
251 * (SMC_RSI_ATTEST_TOKEN_INIT) must have been executed
252 * successfully.
253 */
254 res->smc_res.x[0] = RSI_ERROR_STATE;
255 break;
256 case ATTEST_SIGN_IN_PROGRESS:
257 attest_token_continue_sign_state(rec, res);
258 break;
259 case ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS:
260 attest_token_continue_write_state(rec, res);
261 break;
262 default:
263 /* Any other state is considered an error */
264 panic();
265 }
266
267 if (res->smc_res.x[0] == RSI_INCOMPLETE) {
268 if (check_pending_irq()) {
269 res->action = UPDATE_REC_EXIT_TO_HOST;
270 res->smc_res.x[0] = RSI_INCOMPLETE;
271 rec_exit->exit_reason = RMI_EXIT_IRQ;
272 break;
273 }
274 if ((res->action & FLAG_EXIT_TO_HOST) != 0) {
275 break;
276 }
277 } else {
278 break;
279 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000280 }
281}
282
AlexeiFedorov97844202023-04-27 15:17:35 +0100283void handle_rsi_measurement_extend(struct rec *rec, struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000284{
285 struct granule *g_rd;
286 struct rd *rd;
287 unsigned long index;
288 unsigned long rd_addr;
289 size_t size;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000290 void *extend_measurement;
291 unsigned char *current_measurement;
292 int __unused meas_ret;
293
AlexeiFedorov97844202023-04-27 15:17:35 +0100294 assert(rec != NULL);
295
296 res->action = UPDATE_REC_RETURN_TO_REALM;
297
Soby Mathewb4c6df42022-11-09 11:13:29 +0000298 /*
299 * rd lock is acquired so that measurement cannot be updated
300 * simultaneously by another rec
301 */
302 rd_addr = granule_addr(rec->realm_info.g_rd);
303 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
304
305 assert(g_rd != NULL);
306
307 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
308
309 /*
310 * X1: index
311 * X2: size
312 * X3-X10: measurement value
313 */
314 index = rec->regs[1];
315
316 if ((index == RIM_MEASUREMENT_SLOT) ||
317 (index >= MEASUREMENT_SLOT_NR)) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100318 res->smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000319 goto out_unmap_rd;
320 }
321
322 size = rec->regs[2];
323
324 if (size > MAX_EXTENDED_SIZE) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100325 res->smc_res.x[0] = RSI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000326 goto out_unmap_rd;
327 }
328
329 extend_measurement = &rec->regs[3];
330 current_measurement = rd->measurement[index];
331
332 measurement_extend(rd->algorithm,
333 current_measurement,
334 extend_measurement,
335 size,
336 current_measurement);
337
AlexeiFedorov97844202023-04-27 15:17:35 +0100338 res->smc_res.x[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000339
340out_unmap_rd:
341 buffer_unmap(rd);
342 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000343}
344
AlexeiFedorov97844202023-04-27 15:17:35 +0100345void handle_rsi_measurement_read(struct rec *rec, struct rsi_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000346{
347 struct rd *rd;
348 unsigned long idx;
349 size_t measurement_size;
350
351 assert(rec != NULL);
352
AlexeiFedorov97844202023-04-27 15:17:35 +0100353 res->action = UPDATE_REC_RETURN_TO_REALM;
354
Soby Mathewb4c6df42022-11-09 11:13:29 +0000355 /* X1: Index */
356 idx = rec->regs[1];
357
358 if (idx >= MEASUREMENT_SLOT_NR) {
AlexeiFedorov97844202023-04-27 15:17:35 +0100359 res->smc_res.x[0] = RSI_ERROR_INPUT;
360 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000361 }
362
363 /*
364 * rd lock is acquired so that measurement cannot be updated
365 * simultaneously by another rec
366 */
367 granule_lock(rec->realm_info.g_rd, GRANULE_STATE_RD);
368 rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
369
370 measurement_size = measurement_get_size(rd->algorithm);
371
372 (void)memcpy(&rec->regs[1], rd->measurement[idx], measurement_size);
373
374 /* Zero-initialize the unused area */
375 if (measurement_size < MAX_MEASUREMENT_SIZE) {
376 (void)memset((char *)(&rec->regs[1]) + measurement_size,
377 0, MAX_MEASUREMENT_SIZE - measurement_size);
378 }
379
380 buffer_unmap(rd);
381 granule_unlock(rec->realm_info.g_rd);
382
AlexeiFedorov97844202023-04-27 15:17:35 +0100383 res->smc_res.x[0] = RSI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000384}