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