blob: 44a0acd6f93c58f0712a8ffda41f24aca50e1910 [file] [log] [blame]
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +00001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +00007#include <assert.h>
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +00008#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009#include <string.h>
10
11#include <common/debug.h>
12#include <lib/el3_runtime/context_mgmt.h>
13#include <lib/smccc.h>
14#include <lib/spinlock.h>
15#include <lib/utils.h>
16#include <services/spci_svc.h>
17#include <services/sprt_svc.h>
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +000018#include <smccc_helpers.h>
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +000019#include <sprt_host.h>
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +000020
21#include "spm_private.h"
22
23/*******************************************************************************
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +000024 * Macros to print UUIDs.
25 ******************************************************************************/
26#define PRINT_UUID_FORMAT "%08x-%08x-%08x-%08x"
27#define PRINT_UUID_ARGS(x) x[0], x[1], x[2], x[3]
28
29/*******************************************************************************
30 * Array of structs that contains information about all handles of Secure
31 * Services that are currently open.
32 ******************************************************************************/
33typedef enum spci_handle_status {
34 HANDLE_STATUS_CLOSED = 0,
35 HANDLE_STATUS_OPEN,
36} spci_handle_status_t;
37
38typedef struct spci_handle {
39 /* 16-bit value used as reference in all SPCI calls */
40 uint16_t handle;
41
42 /* Client ID of the client that requested the handle */
43 uint16_t client_id;
44
45 /* Current status of the handle */
46 spci_handle_status_t status;
47
48 /*
49 * Context of the Secure Partition that provides the Secure Service
50 * referenced by this handle.
51 */
52 sp_context_t *sp_ctx;
53
54 /*
55 * The same handle might be used for multiple requests, keep a reference
56 * counter of them.
57 */
58 unsigned int num_active_requests;
59} spci_handle_t;
60
61static spci_handle_t spci_handles[PLAT_SPCI_HANDLES_MAX_NUM];
62static spinlock_t spci_handles_lock;
63
64/*
65 * Given a handle and a client ID, return the element of the spci_handles
66 * array that contains the information of the handle. It can only return open
67 * handles. It returns NULL if it couldn't find the element in the array.
68 */
69static spci_handle_t *spci_handle_info_get(uint16_t handle, uint16_t client_id)
70{
71 size_t i;
72
73 for (i = 0; i < ARRAY_SIZE(spci_handles); i++) {
74 spci_handle_t *h = &(spci_handles[i]);
75
76 /* Only check for open handles */
77 if (h->status == HANDLE_STATUS_CLOSED) {
78 continue;
79 }
80
81 /* Check if either the handle or the client ID are different */
82 if ((h->handle != handle) || (h->client_id != client_id)) {
83 continue;
84 }
85
86 return h;
87 }
88
89 return NULL;
90}
91
92/*
93 * Returns a unique value for a handle. This function must be called while
94 * spci_handles_lock is locked. It returns 0 on success, -1 on error.
95 */
96static int spci_create_handle_value(uint16_t *handle)
97{
98 /*
99 * Trivial implementation that relies on the fact that any handle will
100 * be closed before 2^16 more handles have been opened.
101 */
102 static uint16_t handle_count;
103
104 *handle = handle_count;
105
106 handle_count++;
107
108 return 0;
109}
110
111/*******************************************************************************
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000112 * Returns a unique token for a Secure Service request.
113 ******************************************************************************/
114static uint32_t spci_create_token_value(void)
115{
116 /*
117 * Trivial implementation that relies on the fact that any response will
118 * be read before 2^32 more service requests have been done.
119 */
120 static uint32_t token_count;
121
122 return token_count++;
123}
124
125/*******************************************************************************
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +0000126 * This function looks for a Secure Partition that has a Secure Service
127 * identified by the given UUID. It returns a handle that the client can use to
128 * access the service, and an SPCI_*** error code.
129 ******************************************************************************/
130static uint64_t spci_service_handle_open_poll(void *handle, u_register_t x1,
131 u_register_t x2, u_register_t x3, u_register_t x4,
132 u_register_t x5, u_register_t x6, u_register_t x7)
133{
134 unsigned int i;
135 sp_context_t *sp_ptr;
136 uint16_t service_handle;
137
138 /* Bits 31:16 of w7 are reserved (MBZ). */
139 assert((x7 & 0xFFFF0000U) == 0);
140
141 uint16_t client_id = x7 & 0x0000FFFFU;
142 uint32_t uuid[4] = { x1, x2, x3, x4 };
143
144 /* Get pointer to the Secure Partition that handles this service */
145 sp_ptr = spm_sp_get_by_uuid(&uuid);
146 if (sp_ptr == NULL) {
147 WARN("SPCI: Service requested by client 0x%04x not found\n",
148 client_id);
149 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
150 PRINT_UUID_ARGS(uuid));
151
152 SMC_RET2(handle, SPCI_NOT_PRESENT, 0);
153 }
154
155 /* Get lock of the array of handles */
156 spin_lock(&spci_handles_lock);
157
158 /*
159 * We need to record the client ID and Secure Partition that correspond
160 * to this handle. Look for the first free entry in the array.
161 */
162 for (i = 0; i < PLAT_SPCI_HANDLES_MAX_NUM; i++) {
163 if (spci_handles[i].status == HANDLE_STATUS_CLOSED) {
164 break;
165 }
166 }
167
168 if (i == PLAT_SPCI_HANDLES_MAX_NUM) {
169 spin_unlock(&spci_handles_lock);
170
171 WARN("SPCI: Can't open more handles. Client 0x%04x\n",
172 client_id);
173 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
174 PRINT_UUID_ARGS(uuid));
175
176 SMC_RET2(handle, SPCI_NO_MEMORY, 0);
177 }
178
179 /* Create new handle value */
180 if (spci_create_handle_value(&service_handle) != 0) {
181 spin_unlock(&spci_handles_lock);
182
183 WARN("SPCI: Can't create a new handle value. Client 0x%04x\n",
184 client_id);
185 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
186 PRINT_UUID_ARGS(uuid));
187
188 SMC_RET2(handle, SPCI_NO_MEMORY, 0);
189 }
190
191 /* Save all information about this handle */
192 spci_handles[i].status = HANDLE_STATUS_OPEN;
193 spci_handles[i].client_id = client_id;
194 spci_handles[i].handle = service_handle;
195 spci_handles[i].num_active_requests = 0U;
196 spci_handles[i].sp_ctx = sp_ptr;
197
198 /* Release lock of the array of handles */
199 spin_unlock(&spci_handles_lock);
200
201 VERBOSE("SPCI: Service handle request by client 0x%04x: 0x%04x\n",
202 client_id, service_handle);
203 VERBOSE("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid));
204
205 /* The handle is returned in the top 16 bits of x1 */
206 SMC_RET2(handle, SPCI_SUCCESS, ((uint32_t)service_handle) << 16);
207}
208
209/*******************************************************************************
210 * This function closes a handle that a specific client uses to access a Secure
211 * Service. It returns a SPCI_*** error code.
212 ******************************************************************************/
213static uint64_t spci_service_handle_close(void *handle, u_register_t x1)
214{
215 spci_handle_t *handle_info;
216 uint16_t client_id = x1 & 0x0000FFFFU;
217 uint16_t service_handle = (x1 >> 16) & 0x0000FFFFU;
218
219 spin_lock(&spci_handles_lock);
220
221 handle_info = spci_handle_info_get(service_handle, client_id);
222
223 if (handle_info == NULL) {
224 spin_unlock(&spci_handles_lock);
225
226 WARN("SPCI: Tried to close invalid handle 0x%04x by client 0x%04x\n",
227 service_handle, client_id);
228
229 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
230 }
231
232 if (handle_info->status != HANDLE_STATUS_OPEN) {
233 spin_unlock(&spci_handles_lock);
234
235 WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x in status %d\n",
236 service_handle, client_id, handle_info->status);
237
238 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
239 }
240
241 if (handle_info->num_active_requests != 0U) {
242 spin_unlock(&spci_handles_lock);
243
244 /* A handle can't be closed if there are requests left */
245 WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x with %d requests left\n",
246 service_handle, client_id,
247 handle_info->num_active_requests);
248
249 SMC_RET1(handle, SPCI_BUSY);
250 }
251
252 memset(handle_info, 0, sizeof(spci_handle_t));
253
254 handle_info->status = HANDLE_STATUS_CLOSED;
255
256 spin_unlock(&spci_handles_lock);
257
258 VERBOSE("SPCI: Closed handle 0x%04x by client 0x%04x.\n",
259 service_handle, client_id);
260
261 SMC_RET1(handle, SPCI_SUCCESS);
262}
263
264/*******************************************************************************
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000265 * This function requests a Secure Service from a given handle and client ID.
266 ******************************************************************************/
267static uint64_t spci_service_request_blocking(void *handle,
268 uint32_t smc_fid, u_register_t x1, u_register_t x2,
269 u_register_t x3, u_register_t x4, u_register_t x5,
270 u_register_t x6, u_register_t x7)
271{
272 spci_handle_t *handle_info;
273 sp_context_t *sp_ctx;
274 cpu_context_t *cpu_ctx;
275 uint32_t rx0;
276 u_register_t rx1, rx2, rx3;
277 uint16_t request_handle, client_id;
278
279 /* Get handle array lock */
280 spin_lock(&spci_handles_lock);
281
282 /* Get pointer to struct of this open handle and client ID. */
283 request_handle = (x7 >> 16U) & 0x0000FFFFU;
284 client_id = x7 & 0x0000FFFFU;
285
286 handle_info = spci_handle_info_get(request_handle, client_id);
287 if (handle_info == NULL) {
288 spin_unlock(&spci_handles_lock);
289
290 WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n");
291 WARN(" Handle 0x%04x. Client ID 0x%04x\n", request_handle,
292 client_id);
293
294 SMC_RET1(handle, SPCI_BUSY);
295 }
296
297 /* Get pointer to the Secure Partition that handles the service */
298 sp_ctx = handle_info->sp_ctx;
299 assert(sp_ctx != NULL);
300 cpu_ctx = &(sp_ctx->cpu_ctx);
301
302 /* Blocking requests are only allowed if the queue is empty */
303 if (handle_info->num_active_requests > 0) {
304 spin_unlock(&spci_handles_lock);
305
306 SMC_RET1(handle, SPCI_BUSY);
307 }
308
Antonio Nino Diaz44ef4eb2018-07-03 19:54:59 +0100309 if (spm_sp_request_increase_if_zero(sp_ctx) == -1) {
310 spin_unlock(&spci_handles_lock);
311
312 SMC_RET1(handle, SPCI_BUSY);
313 }
314
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000315 /* Prevent this handle from being closed */
316 handle_info->num_active_requests += 1;
317
318 /* Release handle lock */
319 spin_unlock(&spci_handles_lock);
320
321 /* Save the Normal world context */
322 cm_el1_sysregs_context_save(NON_SECURE);
323
324 /* Wait until the Secure Partition is idle and set it to busy. */
325 sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY);
326
327 /* Pass arguments to the Secure Partition */
328 struct sprt_queue_entry_message message = {
329 .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
330 .client_id = client_id,
331 .service_handle = request_handle,
332 .session_id = x6,
333 .token = 0, /* No token needed for blocking requests */
334 .args = {smc_fid, x1, x2, x3, x4, x5}
335 };
336
337 spin_lock(&(sp_ctx->spm_sp_buffer_lock));
338 int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
339 SPRT_QUEUE_NUM_BLOCKING);
340 spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
341 if (rc != 0) {
342 /*
343 * This shouldn't happen, blocking requests can only be made if
344 * the request queue is empty.
345 */
346 assert(rc == -ENOMEM);
347 ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
348 panic();
349 }
350
351 /* Jump to the Secure Partition. */
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100352 rx0 = spm_sp_synchronous_entry(sp_ctx, 0);
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000353
354 /* Verify returned value */
355 if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
356 ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0);
357 panic();
358 }
359
360 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
361 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
362 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
363
364 /* Flag Secure Partition as idle. */
365 assert(sp_ctx->state == SP_STATE_BUSY);
366 sp_state_set(sp_ctx, SP_STATE_IDLE);
367
368 /* Decrease count of requests. */
369 spin_lock(&spci_handles_lock);
370 handle_info->num_active_requests -= 1;
371 spin_unlock(&spci_handles_lock);
Antonio Nino Diaz44ef4eb2018-07-03 19:54:59 +0100372 spm_sp_request_decrease(sp_ctx);
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000373
374 /* Restore non-secure state */
375 cm_el1_sysregs_context_restore(NON_SECURE);
376 cm_set_next_eret_context(NON_SECURE);
377
378 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
379}
380
381/*******************************************************************************
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000382 * This function requests a Secure Service from a given handle and client ID.
383 ******************************************************************************/
384static uint64_t spci_service_request_start(void *handle,
385 uint32_t smc_fid, u_register_t x1, u_register_t x2,
386 u_register_t x3, u_register_t x4, u_register_t x5,
387 u_register_t x6, u_register_t x7)
388{
389 spci_handle_t *handle_info;
390 sp_context_t *sp_ctx;
391 cpu_context_t *cpu_ctx;
392 uint16_t request_handle, client_id;
393 uint32_t token;
394
395 /* Get handle array lock */
396 spin_lock(&spci_handles_lock);
397
398 /* Get pointer to struct of this open handle and client ID. */
399 request_handle = (x7 >> 16U) & 0x0000FFFFU;
400 client_id = x7 & 0x0000FFFFU;
401
402 handle_info = spci_handle_info_get(request_handle, client_id);
403 if (handle_info == NULL) {
404 spin_unlock(&spci_handles_lock);
405
406 WARN("SPCI_SERVICE_TUN_REQUEST_START: Not found.\n"
407 " Handle 0x%04x. Client ID 0x%04x\n", request_handle,
408 client_id);
409
410 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
411 }
412
413 /* Get pointer to the Secure Partition that handles the service */
414 sp_ctx = handle_info->sp_ctx;
415 assert(sp_ctx != NULL);
416 cpu_ctx = &(sp_ctx->cpu_ctx);
417
418 /* Prevent this handle from being closed */
419 handle_info->num_active_requests += 1;
420
421 spm_sp_request_increase(sp_ctx);
422
423 /* Create new token for this request */
424 token = spci_create_token_value();
425
426 /* Release handle lock */
427 spin_unlock(&spci_handles_lock);
428
429 /* Pass arguments to the Secure Partition */
430 struct sprt_queue_entry_message message = {
431 .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
432 .client_id = client_id,
433 .service_handle = request_handle,
434 .session_id = x6,
435 .token = token,
436 .args = {smc_fid, x1, x2, x3, x4, x5}
437 };
438
439 spin_lock(&(sp_ctx->spm_sp_buffer_lock));
440 int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
441 SPRT_QUEUE_NUM_NON_BLOCKING);
442 spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
443 if (rc != 0) {
444 WARN("SPCI_SERVICE_TUN_REQUEST_START: SPRT queue full.\n"
445 " Handle 0x%04x. Client ID 0x%04x\n", request_handle,
446 client_id);
447 SMC_RET1(handle, SPCI_NO_MEMORY);
448 }
449
450 /* Try to enter the partition. If it's not possible, simply return. */
451 if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
452 SMC_RET2(handle, SPCI_SUCCESS, token);
453 }
454
455 /* Save the Normal world context */
456 cm_el1_sysregs_context_save(NON_SECURE);
457
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100458 /*
459 * This request is non-blocking and needs to be interruptible by
460 * non-secure interrupts. Enable their routing to EL3 during the
461 * processing of the Secure Partition's service on this core.
462 */
463
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000464 /* Jump to the Secure Partition. */
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100465 uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000466
467 /* Verify returned values */
468 if (ret == SPRT_PUT_RESPONSE_AARCH64) {
469 uint32_t token;
470 uint64_t rx1, rx2, rx3, x6;
471
472 token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1);
473 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
474 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
475 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
476 x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6);
477
478 uint16_t client_id = x6 & 0xFFFFU;
479 uint16_t service_handle = x6 >> 16;
480
481 int rc = spm_response_add(client_id, service_handle, token,
482 rx1, rx2, rx3);
483 if (rc != 0) {
484 /*
485 * This is error fatal because we can't return to the SP
486 * from this SMC. The SP has crashed.
487 */
488 panic();
489 }
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100490 } else if ((ret != SPRT_YIELD_AARCH64) &&
491 (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000492 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
493 panic();
494 }
495
496 /* Flag Secure Partition as idle. */
497 assert(sp_ctx->state == SP_STATE_BUSY);
498 sp_state_set(sp_ctx, SP_STATE_IDLE);
499
500 /* Restore non-secure state */
501 cm_el1_sysregs_context_restore(NON_SECURE);
502 cm_set_next_eret_context(NON_SECURE);
503
504 SMC_RET2(handle, SPCI_SUCCESS, token);
505}
506
507/*******************************************************************************
508 * This function returns the response of a Secure Service given a handle, a
509 * client ID and a token. If not available, it will schedule a Secure Partition
510 * and give it CPU time.
511 ******************************************************************************/
512static uint64_t spci_service_request_resume(void *handle, u_register_t x1,
513 u_register_t x7)
514{
515 int rc;
516 u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
517 spci_handle_t *handle_info;
518 sp_context_t *sp_ctx;
519 cpu_context_t *cpu_ctx;
520 uint32_t token = (uint32_t) x1;
521 uint16_t client_id = x7 & 0x0000FFFF;
522 uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
523
524 /* Get pointer to struct of this open handle and client ID. */
525 spin_lock(&spci_handles_lock);
526
527 handle_info = spci_handle_info_get(service_handle, client_id);
528 if (handle_info == NULL) {
529 spin_unlock(&spci_handles_lock);
530 WARN("SPCI_SERVICE_REQUEST_RESUME: Not found.\n"
531 "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
532 client_id, service_handle, token);
533
534 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
535 }
536
537 /* Get pointer to the Secure Partition that handles the service */
538 sp_ctx = handle_info->sp_ctx;
539 assert(sp_ctx != NULL);
540 cpu_ctx = &(sp_ctx->cpu_ctx);
541
542 spin_unlock(&spci_handles_lock);
543
544 /* Look for a valid response in the global queue */
545 rc = spm_response_get(client_id, service_handle, token,
546 &rx1, &rx2, &rx3);
547 if (rc == 0) {
548 /* Decrease request count */
549 spin_lock(&spci_handles_lock);
550 handle_info->num_active_requests -= 1;
551 spin_unlock(&spci_handles_lock);
552 spm_sp_request_decrease(sp_ctx);
553
554 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
555 }
556
557 /* Try to enter the partition. If it's not possible, simply return. */
558 if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
559 SMC_RET1(handle, SPCI_QUEUED);
560 }
561
562 /* Save the Normal world context */
563 cm_el1_sysregs_context_save(NON_SECURE);
564
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100565 /*
566 * This request is non-blocking and needs to be interruptible by
567 * non-secure interrupts. Enable their routing to EL3 during the
568 * processing of the Secure Partition's service on this core.
569 */
570
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000571 /* Jump to the Secure Partition. */
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100572 uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000573
574 /* Verify returned values */
575 if (ret == SPRT_PUT_RESPONSE_AARCH64) {
576 uint32_t token;
577 uint64_t rx1, rx2, rx3, x6;
578
579 token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1);
580 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
581 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
582 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
583 x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6);
584
585 uint16_t client_id = x6 & 0xFFFFU;
586 uint16_t service_handle = x6 >> 16;
587
588 int rc = spm_response_add(client_id, service_handle, token,
589 rx1, rx2, rx3);
590 if (rc != 0) {
591 /*
592 * This is error fatal because we can't return to the SP
593 * from this SMC. The SP has crashed.
594 */
595 panic();
596 }
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100597 } else if ((ret != SPRT_YIELD_AARCH64) &&
598 (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000599 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
600 panic();
601 }
602
603 /* Flag Secure Partition as idle. */
604 assert(sp_ctx->state == SP_STATE_BUSY);
605 sp_state_set(sp_ctx, SP_STATE_IDLE);
606
607 /* Restore non-secure state */
608 cm_el1_sysregs_context_restore(NON_SECURE);
609 cm_set_next_eret_context(NON_SECURE);
610
611 /* Look for a valid response in the global queue */
612 rc = spm_response_get(client_id, service_handle, token,
613 &rx1, &rx2, &rx3);
614 if (rc != 0) {
615 SMC_RET1(handle, SPCI_QUEUED);
616 }
617
618 /* Decrease request count */
619 spin_lock(&spci_handles_lock);
620 handle_info->num_active_requests -= 1;
621 spin_unlock(&spci_handles_lock);
622 spm_sp_request_decrease(sp_ctx);
623
624 /* Return response */
625 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
626}
627
628/*******************************************************************************
629 * This function returns the response of a Secure Service given a handle, a
630 * client ID and a token.
631 ******************************************************************************/
632static uint64_t spci_service_get_response(void *handle, u_register_t x1,
633 u_register_t x7)
634
635{
636 int rc;
637 u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
638 spci_handle_t *handle_info;
639 uint32_t token = (uint32_t) x1;
640 uint16_t client_id = x7 & 0x0000FFFF;
641 uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
642
643 /* Get pointer to struct of this open handle and client ID. */
644
645 spin_lock(&spci_handles_lock);
646
647 handle_info = spci_handle_info_get(service_handle, client_id);
648 if (handle_info == NULL) {
649 spin_unlock(&spci_handles_lock);
650 WARN("SPCI_SERVICE_GET_RESPONSE: Not found.\n"
651 "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
652 client_id, service_handle, token);
653
654 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
655 }
656
657 spin_unlock(&spci_handles_lock);
658
659 /* Look for a valid response in the global queue */
660 rc = spm_response_get(client_id, service_handle, token,
661 &rx1, &rx2, &rx3);
662
663 if (rc != 0) {
664 SMC_RET1(handle, SPCI_QUEUED);
665 }
666
667 /* Decrease request count */
668 spin_lock(&spci_handles_lock);
669 handle_info->num_active_requests -= 1;
670 sp_context_t *sp_ctx;
671 sp_ctx = handle_info->sp_ctx;
672 spin_unlock(&spci_handles_lock);
673 spm_sp_request_decrease(sp_ctx);
674
675 /* Return response */
676 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
677}
678
679/*******************************************************************************
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000680 * This function handles all SMCs in the range reserved for SPCI.
681 ******************************************************************************/
682uint64_t spci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
683 uint64_t x3, uint64_t x4, void *cookie, void *handle,
684 uint64_t flags)
685{
686 uint32_t spci_fid;
687
688 /* SPCI only supported from the Non-secure world for now */
689 if (is_caller_non_secure(flags) == SMC_FROM_SECURE) {
690 SMC_RET1(handle, SMC_UNK);
691 }
692
693 if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) {
694
695 /* Miscellaneous calls */
696
697 spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK;
698
699 switch (spci_fid) {
700
701 case SPCI_FID_VERSION:
702 SMC_RET1(handle, SPCI_VERSION_COMPILED);
703
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +0000704 case SPCI_FID_SERVICE_HANDLE_OPEN:
705 {
706 if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) {
707 /* Not supported for now */
708 WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n");
709 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
710 }
711
712 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
713 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
714 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
715
716 return spci_service_handle_open_poll(handle, x1, x2, x3,
717 x4, x5, x6, x7);
718 }
719 case SPCI_FID_SERVICE_HANDLE_CLOSE:
720 return spci_service_handle_close(handle, x1);
721
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000722 case SPCI_FID_SERVICE_REQUEST_BLOCKING:
723 {
724 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
725 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
726 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
727
728 return spci_service_request_blocking(handle,
729 smc_fid, x1, x2, x3, x4, x5, x6, x7);
730 }
731
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000732 case SPCI_FID_SERVICE_REQUEST_START:
733 {
734 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
735 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
736 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
737
738 return spci_service_request_start(handle,
739 smc_fid, x1, x2, x3, x4, x5, x6, x7);
740 }
741
742 case SPCI_FID_SERVICE_GET_RESPONSE:
743 {
744 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
745
746 return spci_service_get_response(handle, x1, x7);
747 }
748
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000749 default:
750 break;
751 }
752
753 } else {
754
755 /* Tunneled calls */
756
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000757 spci_fid = (smc_fid >> SPCI_FID_TUN_SHIFT) & SPCI_FID_TUN_MASK;
758
759 switch (spci_fid) {
760
761 case SPCI_FID_SERVICE_REQUEST_RESUME:
762 {
763 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
764
765 return spci_service_request_resume(handle, x1, x7);
766 }
767
768 default:
769 break;
770 }
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000771 }
772
773 WARN("SPCI: Unsupported call 0x%08x\n", smc_fid);
774 SMC_RET1(handle, SPCI_NOT_SUPPORTED);
775}