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