blob: 1ee986af4285b8b7ebae6092e54b811d56c83c2f [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/*******************************************************************************
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000383 * This function requests a Secure Service from a given handle and client ID.
384 ******************************************************************************/
385static uint64_t spci_service_request_start(void *handle,
386 uint32_t smc_fid, u_register_t x1, u_register_t x2,
387 u_register_t x3, u_register_t x4, u_register_t x5,
388 u_register_t x6, u_register_t x7)
389{
390 spci_handle_t *handle_info;
391 sp_context_t *sp_ctx;
392 cpu_context_t *cpu_ctx;
393 uint16_t request_handle, client_id;
394 uint32_t token;
395
396 /* Get handle array lock */
397 spin_lock(&spci_handles_lock);
398
399 /* Get pointer to struct of this open handle and client ID. */
400 request_handle = (x7 >> 16U) & 0x0000FFFFU;
401 client_id = x7 & 0x0000FFFFU;
402
403 handle_info = spci_handle_info_get(request_handle, client_id);
404 if (handle_info == NULL) {
405 spin_unlock(&spci_handles_lock);
406
407 WARN("SPCI_SERVICE_TUN_REQUEST_START: Not found.\n"
408 " Handle 0x%04x. Client ID 0x%04x\n", request_handle,
409 client_id);
410
411 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
412 }
413
414 /* Get pointer to the Secure Partition that handles the service */
415 sp_ctx = handle_info->sp_ctx;
416 assert(sp_ctx != NULL);
417 cpu_ctx = &(sp_ctx->cpu_ctx);
418
419 /* Prevent this handle from being closed */
420 handle_info->num_active_requests += 1;
421
422 spm_sp_request_increase(sp_ctx);
423
424 /* Create new token for this request */
425 token = spci_create_token_value();
426
427 /* Release handle lock */
428 spin_unlock(&spci_handles_lock);
429
430 /* Pass arguments to the Secure Partition */
431 struct sprt_queue_entry_message message = {
432 .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
433 .client_id = client_id,
434 .service_handle = request_handle,
435 .session_id = x6,
436 .token = token,
437 .args = {smc_fid, x1, x2, x3, x4, x5}
438 };
439
440 spin_lock(&(sp_ctx->spm_sp_buffer_lock));
441 int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
442 SPRT_QUEUE_NUM_NON_BLOCKING);
443 spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
444 if (rc != 0) {
445 WARN("SPCI_SERVICE_TUN_REQUEST_START: SPRT queue full.\n"
446 " Handle 0x%04x. Client ID 0x%04x\n", request_handle,
447 client_id);
448 SMC_RET1(handle, SPCI_NO_MEMORY);
449 }
450
451 /* Try to enter the partition. If it's not possible, simply return. */
452 if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
453 SMC_RET2(handle, SPCI_SUCCESS, token);
454 }
455
456 /* Save the Normal world context */
457 cm_el1_sysregs_context_save(NON_SECURE);
458
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100459 /*
460 * This request is non-blocking and needs to be interruptible by
461 * non-secure interrupts. Enable their routing to EL3 during the
462 * processing of the Secure Partition's service on this core.
463 */
464
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000465 /* Jump to the Secure Partition. */
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100466 uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000467
468 /* Verify returned values */
469 if (ret == SPRT_PUT_RESPONSE_AARCH64) {
470 uint32_t token;
471 uint64_t rx1, rx2, rx3, x6;
472
473 token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1);
474 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
475 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
476 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
477 x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6);
478
479 uint16_t client_id = x6 & 0xFFFFU;
480 uint16_t service_handle = x6 >> 16;
481
482 int rc = spm_response_add(client_id, service_handle, token,
483 rx1, rx2, rx3);
484 if (rc != 0) {
485 /*
486 * This is error fatal because we can't return to the SP
487 * from this SMC. The SP has crashed.
488 */
489 panic();
490 }
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100491 } else if ((ret != SPRT_YIELD_AARCH64) &&
492 (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000493 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
494 panic();
495 }
496
497 /* Flag Secure Partition as idle. */
498 assert(sp_ctx->state == SP_STATE_BUSY);
499 sp_state_set(sp_ctx, SP_STATE_IDLE);
500
501 /* Restore non-secure state */
502 cm_el1_sysregs_context_restore(NON_SECURE);
503 cm_set_next_eret_context(NON_SECURE);
504
505 SMC_RET2(handle, SPCI_SUCCESS, token);
506}
507
508/*******************************************************************************
509 * This function returns the response of a Secure Service given a handle, a
510 * client ID and a token. If not available, it will schedule a Secure Partition
511 * and give it CPU time.
512 ******************************************************************************/
513static uint64_t spci_service_request_resume(void *handle, u_register_t x1,
514 u_register_t x7)
515{
516 int rc;
517 u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
518 spci_handle_t *handle_info;
519 sp_context_t *sp_ctx;
520 cpu_context_t *cpu_ctx;
521 uint32_t token = (uint32_t) x1;
522 uint16_t client_id = x7 & 0x0000FFFF;
523 uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
524
525 /* Get pointer to struct of this open handle and client ID. */
526 spin_lock(&spci_handles_lock);
527
528 handle_info = spci_handle_info_get(service_handle, client_id);
529 if (handle_info == NULL) {
530 spin_unlock(&spci_handles_lock);
531 WARN("SPCI_SERVICE_REQUEST_RESUME: Not found.\n"
532 "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
533 client_id, service_handle, token);
534
535 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
536 }
537
538 /* Get pointer to the Secure Partition that handles the service */
539 sp_ctx = handle_info->sp_ctx;
540 assert(sp_ctx != NULL);
541 cpu_ctx = &(sp_ctx->cpu_ctx);
542
543 spin_unlock(&spci_handles_lock);
544
545 /* Look for a valid response in the global queue */
546 rc = spm_response_get(client_id, service_handle, token,
547 &rx1, &rx2, &rx3);
548 if (rc == 0) {
549 /* Decrease request count */
550 spin_lock(&spci_handles_lock);
551 handle_info->num_active_requests -= 1;
552 spin_unlock(&spci_handles_lock);
553 spm_sp_request_decrease(sp_ctx);
554
555 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
556 }
557
558 /* Try to enter the partition. If it's not possible, simply return. */
559 if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
560 SMC_RET1(handle, SPCI_QUEUED);
561 }
562
563 /* Save the Normal world context */
564 cm_el1_sysregs_context_save(NON_SECURE);
565
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100566 /*
567 * This request is non-blocking and needs to be interruptible by
568 * non-secure interrupts. Enable their routing to EL3 during the
569 * processing of the Secure Partition's service on this core.
570 */
571
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000572 /* Jump to the Secure Partition. */
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100573 uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000574
575 /* Verify returned values */
576 if (ret == SPRT_PUT_RESPONSE_AARCH64) {
577 uint32_t token;
578 uint64_t rx1, rx2, rx3, x6;
579
580 token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1);
581 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
582 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
583 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
584 x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6);
585
586 uint16_t client_id = x6 & 0xFFFFU;
587 uint16_t service_handle = x6 >> 16;
588
589 int rc = spm_response_add(client_id, service_handle, token,
590 rx1, rx2, rx3);
591 if (rc != 0) {
592 /*
593 * This is error fatal because we can't return to the SP
594 * from this SMC. The SP has crashed.
595 */
596 panic();
597 }
Antonio Nino Diazfb763962018-07-03 16:54:33 +0100598 } else if ((ret != SPRT_YIELD_AARCH64) &&
599 (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000600 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
601 panic();
602 }
603
604 /* Flag Secure Partition as idle. */
605 assert(sp_ctx->state == SP_STATE_BUSY);
606 sp_state_set(sp_ctx, SP_STATE_IDLE);
607
608 /* Restore non-secure state */
609 cm_el1_sysregs_context_restore(NON_SECURE);
610 cm_set_next_eret_context(NON_SECURE);
611
612 /* Look for a valid response in the global queue */
613 rc = spm_response_get(client_id, service_handle, token,
614 &rx1, &rx2, &rx3);
615 if (rc != 0) {
616 SMC_RET1(handle, SPCI_QUEUED);
617 }
618
619 /* Decrease request count */
620 spin_lock(&spci_handles_lock);
621 handle_info->num_active_requests -= 1;
622 spin_unlock(&spci_handles_lock);
623 spm_sp_request_decrease(sp_ctx);
624
625 /* Return response */
626 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
627}
628
629/*******************************************************************************
630 * This function returns the response of a Secure Service given a handle, a
631 * client ID and a token.
632 ******************************************************************************/
633static uint64_t spci_service_get_response(void *handle, u_register_t x1,
634 u_register_t x7)
635
636{
637 int rc;
638 u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
639 spci_handle_t *handle_info;
640 uint32_t token = (uint32_t) x1;
641 uint16_t client_id = x7 & 0x0000FFFF;
642 uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
643
644 /* Get pointer to struct of this open handle and client ID. */
645
646 spin_lock(&spci_handles_lock);
647
648 handle_info = spci_handle_info_get(service_handle, client_id);
649 if (handle_info == NULL) {
650 spin_unlock(&spci_handles_lock);
651 WARN("SPCI_SERVICE_GET_RESPONSE: Not found.\n"
652 "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
653 client_id, service_handle, token);
654
655 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
656 }
657
658 spin_unlock(&spci_handles_lock);
659
660 /* Look for a valid response in the global queue */
661 rc = spm_response_get(client_id, service_handle, token,
662 &rx1, &rx2, &rx3);
663
664 if (rc != 0) {
665 SMC_RET1(handle, SPCI_QUEUED);
666 }
667
668 /* Decrease request count */
669 spin_lock(&spci_handles_lock);
670 handle_info->num_active_requests -= 1;
671 sp_context_t *sp_ctx;
672 sp_ctx = handle_info->sp_ctx;
673 spin_unlock(&spci_handles_lock);
674 spm_sp_request_decrease(sp_ctx);
675
676 /* Return response */
677 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
678}
679
680/*******************************************************************************
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000681 * This function handles all SMCs in the range reserved for SPCI.
682 ******************************************************************************/
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +0000683static uintptr_t spci_smc_handler(uint32_t smc_fid, u_register_t x1,
684 u_register_t x2, u_register_t x3,
685 u_register_t x4, void *cookie, void *handle,
686 u_register_t flags)
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000687{
688 uint32_t spci_fid;
689
690 /* SPCI only supported from the Non-secure world for now */
691 if (is_caller_non_secure(flags) == SMC_FROM_SECURE) {
692 SMC_RET1(handle, SMC_UNK);
693 }
694
695 if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) {
696
697 /* Miscellaneous calls */
698
699 spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK;
700
701 switch (spci_fid) {
702
703 case SPCI_FID_VERSION:
704 SMC_RET1(handle, SPCI_VERSION_COMPILED);
705
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +0000706 case SPCI_FID_SERVICE_HANDLE_OPEN:
707 {
708 if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) {
709 /* Not supported for now */
710 WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n");
711 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
712 }
713
714 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
715 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
716 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
717
718 return spci_service_handle_open_poll(handle, x1, x2, x3,
719 x4, x5, x6, x7);
720 }
721 case SPCI_FID_SERVICE_HANDLE_CLOSE:
722 return spci_service_handle_close(handle, x1);
723
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000724 case SPCI_FID_SERVICE_REQUEST_BLOCKING:
725 {
726 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
727 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
728 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
729
730 return spci_service_request_blocking(handle,
731 smc_fid, x1, x2, x3, x4, x5, x6, x7);
732 }
733
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000734 case SPCI_FID_SERVICE_REQUEST_START:
735 {
736 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
737 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
738 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
739
740 return spci_service_request_start(handle,
741 smc_fid, x1, x2, x3, x4, x5, x6, x7);
742 }
743
744 case SPCI_FID_SERVICE_GET_RESPONSE:
745 {
746 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
747
748 return spci_service_get_response(handle, x1, x7);
749 }
750
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000751 default:
752 break;
753 }
754
755 } else {
756
757 /* Tunneled calls */
758
Antonio Nino Diaz143091f2018-11-08 14:22:51 +0000759 spci_fid = (smc_fid >> SPCI_FID_TUN_SHIFT) & SPCI_FID_TUN_MASK;
760
761 switch (spci_fid) {
762
763 case SPCI_FID_SERVICE_REQUEST_RESUME:
764 {
765 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
766
767 return spci_service_request_resume(handle, x1, x7);
768 }
769
770 default:
771 break;
772 }
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000773 }
774
775 WARN("SPCI: Unsupported call 0x%08x\n", smc_fid);
776 SMC_RET1(handle, SPCI_NOT_SUPPORTED);
777}
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +0000778
779DECLARE_RT_SVC(
780 spci_handler,
781 OEN_SPCI_START,
782 OEN_SPCI_END,
783 SMC_TYPE_FAST,
784 NULL,
785 spci_smc_handler
786);