2 * Copyright (c) 2018, Arm Limited. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
8 #include <context_mgmt.h>
12 #include <smccc_helpers.h>
15 #include <sprt_host.h>
20 #include "spm_private.h"
22 /*******************************************************************************
23 * 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]
28 /*******************************************************************************
29 * Array of structs that contains information about all handles of Secure
30 * Services that are currently open.
31 ******************************************************************************/
32 typedef enum spci_handle_status
{
33 HANDLE_STATUS_CLOSED
= 0,
35 } spci_handle_status_t
;
37 typedef struct spci_handle
{
38 /* 16-bit value used as reference in all SPCI calls */
41 /* Client ID of the client that requested the handle */
44 /* Current status of the handle */
45 spci_handle_status_t status
;
48 * Context of the Secure Partition that provides the Secure Service
49 * referenced by this handle.
54 * The same handle might be used for multiple requests, keep a reference
57 unsigned int num_active_requests
;
60 static spci_handle_t spci_handles
[PLAT_SPCI_HANDLES_MAX_NUM
];
61 static spinlock_t spci_handles_lock
;
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.
68 static spci_handle_t
*spci_handle_info_get(uint16_t handle
, uint16_t client_id
)
72 for (i
= 0; i
< ARRAY_SIZE(spci_handles
); i
++) {
73 spci_handle_t
*h
= &(spci_handles
[i
]);
75 /* Only check for open handles */
76 if (h
->status
== HANDLE_STATUS_CLOSED
) {
80 /* Check if either the handle or the client ID are different */
81 if ((h
->handle
!= handle
) || (h
->client_id
!= client_id
)) {
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.
95 static int spci_create_handle_value(uint16_t *handle
)
98 * Trivial implementation that relies on the fact that any handle will
99 * be closed before 2^16 more handles have been opened.
101 static uint16_t handle_count
;
103 *handle
= handle_count
;
110 /*******************************************************************************
111 * Returns a unique token for a Secure Service request.
112 ******************************************************************************/
113 static uint32_t spci_create_token_value(void)
116 * Trivial implementation that relies on the fact that any response will
117 * be read before 2^32 more service requests have been done.
119 static uint32_t token_count
;
121 return token_count
++;
124 /*******************************************************************************
125 * 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 ******************************************************************************/
129 static 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
)
134 sp_context_t
*sp_ptr
;
135 uint16_t service_handle
;
137 /* Bits 31:16 of w7 are reserved (MBZ). */
138 assert((x7
& 0xFFFF0000U
) == 0);
140 uint16_t client_id
= x7
& 0x0000FFFFU
;
141 uint32_t uuid
[4] = { x1
, x2
, x3
, x4
};
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",
148 WARN("SPCI: UUID: " PRINT_UUID_FORMAT
"\n",
149 PRINT_UUID_ARGS(uuid
));
151 SMC_RET2(handle
, SPCI_NOT_PRESENT
, 0);
154 /* Get lock of the array of handles */
155 spin_lock(&spci_handles_lock
);
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.
161 for (i
= 0; i
< PLAT_SPCI_HANDLES_MAX_NUM
; i
++) {
162 if (spci_handles
[i
].status
== HANDLE_STATUS_CLOSED
) {
167 if (i
== PLAT_SPCI_HANDLES_MAX_NUM
) {
168 spin_unlock(&spci_handles_lock
);
170 WARN("SPCI: Can't open more handles. Client 0x%04x\n",
172 WARN("SPCI: UUID: " PRINT_UUID_FORMAT
"\n",
173 PRINT_UUID_ARGS(uuid
));
175 SMC_RET2(handle
, SPCI_NO_MEMORY
, 0);
178 /* Create new handle value */
179 if (spci_create_handle_value(&service_handle
) != 0) {
180 spin_unlock(&spci_handles_lock
);
182 WARN("SPCI: Can't create a new handle value. Client 0x%04x\n",
184 WARN("SPCI: UUID: " PRINT_UUID_FORMAT
"\n",
185 PRINT_UUID_ARGS(uuid
));
187 SMC_RET2(handle
, SPCI_NO_MEMORY
, 0);
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
;
197 /* Release lock of the array of handles */
198 spin_unlock(&spci_handles_lock
);
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
));
204 /* The handle is returned in the top 16 bits of x1 */
205 SMC_RET2(handle
, SPCI_SUCCESS
, ((uint32_t)service_handle
) << 16);
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 ******************************************************************************/
212 static uint64_t spci_service_handle_close(void *handle
, u_register_t x1
)
214 spci_handle_t
*handle_info
;
215 uint16_t client_id
= x1
& 0x0000FFFFU
;
216 uint16_t service_handle
= (x1
>> 16) & 0x0000FFFFU
;
218 spin_lock(&spci_handles_lock
);
220 handle_info
= spci_handle_info_get(service_handle
, client_id
);
222 if (handle_info
== NULL
) {
223 spin_unlock(&spci_handles_lock
);
225 WARN("SPCI: Tried to close invalid handle 0x%04x by client 0x%04x\n",
226 service_handle
, client_id
);
228 SMC_RET1(handle
, SPCI_INVALID_PARAMETER
);
231 if (handle_info
->status
!= HANDLE_STATUS_OPEN
) {
232 spin_unlock(&spci_handles_lock
);
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
);
237 SMC_RET1(handle
, SPCI_INVALID_PARAMETER
);
240 if (handle_info
->num_active_requests
!= 0U) {
241 spin_unlock(&spci_handles_lock
);
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
);
248 SMC_RET1(handle
, SPCI_BUSY
);
251 memset(handle_info
, 0, sizeof(spci_handle_t
));
253 handle_info
->status
= HANDLE_STATUS_CLOSED
;
255 spin_unlock(&spci_handles_lock
);
257 VERBOSE("SPCI: Closed handle 0x%04x by client 0x%04x.\n",
258 service_handle
, client_id
);
260 SMC_RET1(handle
, SPCI_SUCCESS
);
263 /*******************************************************************************
264 * This function requests a Secure Service from a given handle and client ID.
265 ******************************************************************************/
266 static 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
)
271 spci_handle_t
*handle_info
;
272 sp_context_t
*sp_ctx
;
273 cpu_context_t
*cpu_ctx
;
275 u_register_t rx1
, rx2
, rx3
;
276 uint16_t request_handle
, client_id
;
278 /* Get handle array lock */
279 spin_lock(&spci_handles_lock
);
281 /* Get pointer to struct of this open handle and client ID. */
282 request_handle
= (x7
>> 16U) & 0x0000FFFFU
;
283 client_id
= x7
& 0x0000FFFFU
;
285 handle_info
= spci_handle_info_get(request_handle
, client_id
);
286 if (handle_info
== NULL
) {
287 spin_unlock(&spci_handles_lock
);
289 WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n");
290 WARN(" Handle 0x%04x. Client ID 0x%04x\n", request_handle
,
293 SMC_RET1(handle
, SPCI_BUSY
);
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
);
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
);
305 SMC_RET1(handle
, SPCI_BUSY
);
308 if (spm_sp_request_increase_if_zero(sp_ctx
) == -1) {
309 spin_unlock(&spci_handles_lock
);
311 SMC_RET1(handle
, SPCI_BUSY
);
314 /* Prevent this handle from being closed */
315 handle_info
->num_active_requests
+= 1;
317 /* Release handle lock */
318 spin_unlock(&spci_handles_lock
);
320 /* Save the Normal world context */
321 cm_el1_sysregs_context_save(NON_SECURE
);
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
);
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
,
332 .token
= 0, /* No token needed for blocking requests */
333 .args
= {smc_fid
, x1
, x2
, x3
, x4
, x5
}
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
));
342 * This shouldn't happen, blocking requests can only be made if
343 * the request queue is empty.
345 assert(rc
== -ENOMEM
);
346 ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
350 /* Jump to the Secure Partition. */
351 rx0
= spm_sp_synchronous_entry(sp_ctx
, 0);
353 /* Verify returned value */
354 if (rx0
!= SPRT_PUT_RESPONSE_AARCH64
) {
355 ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__
, rx0
);
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
);
363 /* Flag Secure Partition as idle. */
364 assert(sp_ctx
->state
== SP_STATE_BUSY
);
365 sp_state_set(sp_ctx
, SP_STATE_IDLE
);
367 /* Decrease count of requests. */
368 spin_lock(&spci_handles_lock
);
369 handle_info
->num_active_requests
-= 1;
370 spin_unlock(&spci_handles_lock
);
371 spm_sp_request_decrease(sp_ctx
);
373 /* Restore non-secure state */
374 cm_el1_sysregs_context_restore(NON_SECURE
);
375 cm_set_next_eret_context(NON_SECURE
);
377 SMC_RET4(handle
, SPCI_SUCCESS
, rx1
, rx2
, rx3
);
380 /*******************************************************************************
381 * This function requests a Secure Service from a given handle and client ID.
382 ******************************************************************************/
383 static 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
)
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
;
394 /* Get handle array lock */
395 spin_lock(&spci_handles_lock
);
397 /* Get pointer to struct of this open handle and client ID. */
398 request_handle
= (x7
>> 16U) & 0x0000FFFFU
;
399 client_id
= x7
& 0x0000FFFFU
;
401 handle_info
= spci_handle_info_get(request_handle
, client_id
);
402 if (handle_info
== NULL
) {
403 spin_unlock(&spci_handles_lock
);
405 WARN("SPCI_SERVICE_TUN_REQUEST_START: Not found.\n"
406 " Handle 0x%04x. Client ID 0x%04x\n", request_handle
,
409 SMC_RET1(handle
, SPCI_INVALID_PARAMETER
);
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
);
417 /* Prevent this handle from being closed */
418 handle_info
->num_active_requests
+= 1;
420 spm_sp_request_increase(sp_ctx
);
422 /* Create new token for this request */
423 token
= spci_create_token_value();
425 /* Release handle lock */
426 spin_unlock(&spci_handles_lock
);
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
,
435 .args
= {smc_fid
, x1
, x2
, x3
, x4
, x5
}
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
));
443 WARN("SPCI_SERVICE_TUN_REQUEST_START: SPRT queue full.\n"
444 " Handle 0x%04x. Client ID 0x%04x\n", request_handle
,
446 SMC_RET1(handle
, SPCI_NO_MEMORY
);
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
);
454 /* Save the Normal world context */
455 cm_el1_sysregs_context_save(NON_SECURE
);
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.
463 /* Jump to the Secure Partition. */
464 uint64_t ret
= spm_sp_synchronous_entry(sp_ctx
, 1);
466 /* Verify returned values */
467 if (ret
== SPRT_PUT_RESPONSE_AARCH64
) {
469 uint64_t rx1
, rx2
, rx3
, x6
;
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
);
477 uint16_t client_id
= x6
& 0xFFFFU
;
478 uint16_t service_handle
= x6
>> 16;
480 int rc
= spm_response_add(client_id
, service_handle
, token
,
484 * This is error fatal because we can't return to the SP
485 * from this SMC. The SP has crashed.
489 } else if ((ret
!= SPRT_YIELD_AARCH64
) &&
490 (ret
!= SPM_SECURE_PARTITION_PREEMPTED
)) {
491 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__
, ret
);
495 /* Flag Secure Partition as idle. */
496 assert(sp_ctx
->state
== SP_STATE_BUSY
);
497 sp_state_set(sp_ctx
, SP_STATE_IDLE
);
499 /* Restore non-secure state */
500 cm_el1_sysregs_context_restore(NON_SECURE
);
501 cm_set_next_eret_context(NON_SECURE
);
503 SMC_RET2(handle
, SPCI_SUCCESS
, token
);
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 ******************************************************************************/
511 static uint64_t spci_service_request_resume(void *handle
, u_register_t x1
,
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;
523 /* Get pointer to struct of this open handle and client ID. */
524 spin_lock(&spci_handles_lock
);
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
);
533 SMC_RET1(handle
, SPCI_INVALID_PARAMETER
);
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
);
541 spin_unlock(&spci_handles_lock
);
543 /* Look for a valid response in the global queue */
544 rc
= spm_response_get(client_id
, service_handle
, token
,
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
);
553 SMC_RET4(handle
, SPCI_SUCCESS
, rx1
, rx2
, rx3
);
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
);
561 /* Save the Normal world context */
562 cm_el1_sysregs_context_save(NON_SECURE
);
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.
570 /* Jump to the Secure Partition. */
571 uint64_t ret
= spm_sp_synchronous_entry(sp_ctx
, 1);
573 /* Verify returned values */
574 if (ret
== SPRT_PUT_RESPONSE_AARCH64
) {
576 uint64_t rx1
, rx2
, rx3
, x6
;
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
);
584 uint16_t client_id
= x6
& 0xFFFFU
;
585 uint16_t service_handle
= x6
>> 16;
587 int rc
= spm_response_add(client_id
, service_handle
, token
,
591 * This is error fatal because we can't return to the SP
592 * from this SMC. The SP has crashed.
596 } else if ((ret
!= SPRT_YIELD_AARCH64
) &&
597 (ret
!= SPM_SECURE_PARTITION_PREEMPTED
)) {
598 ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__
, ret
);
602 /* Flag Secure Partition as idle. */
603 assert(sp_ctx
->state
== SP_STATE_BUSY
);
604 sp_state_set(sp_ctx
, SP_STATE_IDLE
);
606 /* Restore non-secure state */
607 cm_el1_sysregs_context_restore(NON_SECURE
);
608 cm_set_next_eret_context(NON_SECURE
);
610 /* Look for a valid response in the global queue */
611 rc
= spm_response_get(client_id
, service_handle
, token
,
614 SMC_RET1(handle
, SPCI_QUEUED
);
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
);
623 /* Return response */
624 SMC_RET4(handle
, SPCI_SUCCESS
, rx1
, rx2
, rx3
);
627 /*******************************************************************************
628 * This function returns the response of a Secure Service given a handle, a
629 * client ID and a token.
630 ******************************************************************************/
631 static uint64_t spci_service_get_response(void *handle
, u_register_t x1
,
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;
642 /* Get pointer to struct of this open handle and client ID. */
644 spin_lock(&spci_handles_lock
);
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
);
653 SMC_RET1(handle
, SPCI_INVALID_PARAMETER
);
656 spin_unlock(&spci_handles_lock
);
658 /* Look for a valid response in the global queue */
659 rc
= spm_response_get(client_id
, service_handle
, token
,
663 SMC_RET1(handle
, SPCI_QUEUED
);
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
);
674 /* Return response */
675 SMC_RET4(handle
, SPCI_SUCCESS
, rx1
, rx2
, rx3
);
678 /*******************************************************************************
679 * This function handles all SMCs in the range reserved for SPCI.
680 ******************************************************************************/
681 uint64_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
,
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
);
692 if ((smc_fid
& SPCI_FID_TUN_FLAG
) == 0) {
694 /* Miscellaneous calls */
696 spci_fid
= (smc_fid
>> SPCI_FID_MISC_SHIFT
) & SPCI_FID_MISC_MASK
;
700 case SPCI_FID_VERSION
:
701 SMC_RET1(handle
, SPCI_VERSION_COMPILED
);
703 case SPCI_FID_SERVICE_HANDLE_OPEN
:
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
);
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
);
715 return spci_service_handle_open_poll(handle
, x1
, x2
, x3
,
718 case SPCI_FID_SERVICE_HANDLE_CLOSE
:
719 return spci_service_handle_close(handle
, x1
);
721 case SPCI_FID_SERVICE_REQUEST_BLOCKING
:
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
);
727 return spci_service_request_blocking(handle
,
728 smc_fid
, x1
, x2
, x3
, x4
, x5
, x6
, x7
);
731 case SPCI_FID_SERVICE_REQUEST_START
:
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
);
737 return spci_service_request_start(handle
,
738 smc_fid
, x1
, x2
, x3
, x4
, x5
, x6
, x7
);
741 case SPCI_FID_SERVICE_GET_RESPONSE
:
743 uint64_t x7
= SMC_GET_GP(handle
, CTX_GPREG_X7
);
745 return spci_service_get_response(handle
, x1
, x7
);
756 spci_fid
= (smc_fid
>> SPCI_FID_TUN_SHIFT
) & SPCI_FID_TUN_MASK
;
760 case SPCI_FID_SERVICE_REQUEST_RESUME
:
762 uint64_t x7
= SMC_GET_GP(handle
, CTX_GPREG_X7
);
764 return spci_service_request_resume(handle
, x1
, x7
);
772 WARN("SPCI: Unsupported call 0x%08x\n", smc_fid
);
773 SMC_RET1(handle
, SPCI_NOT_SUPPORTED
);