blob: 1544ae16240435592427cd9212daa2e49997e48d [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/*******************************************************************************
111 * This function looks for a Secure Partition that has a Secure Service
112 * identified by the given UUID. It returns a handle that the client can use to
113 * access the service, and an SPCI_*** error code.
114 ******************************************************************************/
115static uint64_t spci_service_handle_open_poll(void *handle, u_register_t x1,
116 u_register_t x2, u_register_t x3, u_register_t x4,
117 u_register_t x5, u_register_t x6, u_register_t x7)
118{
119 unsigned int i;
120 sp_context_t *sp_ptr;
121 uint16_t service_handle;
122
123 /* Bits 31:16 of w7 are reserved (MBZ). */
124 assert((x7 & 0xFFFF0000U) == 0);
125
126 uint16_t client_id = x7 & 0x0000FFFFU;
127 uint32_t uuid[4] = { x1, x2, x3, x4 };
128
129 /* Get pointer to the Secure Partition that handles this service */
130 sp_ptr = spm_sp_get_by_uuid(&uuid);
131 if (sp_ptr == NULL) {
132 WARN("SPCI: Service requested by client 0x%04x not found\n",
133 client_id);
134 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
135 PRINT_UUID_ARGS(uuid));
136
137 SMC_RET2(handle, SPCI_NOT_PRESENT, 0);
138 }
139
140 /* Get lock of the array of handles */
141 spin_lock(&spci_handles_lock);
142
143 /*
144 * We need to record the client ID and Secure Partition that correspond
145 * to this handle. Look for the first free entry in the array.
146 */
147 for (i = 0; i < PLAT_SPCI_HANDLES_MAX_NUM; i++) {
148 if (spci_handles[i].status == HANDLE_STATUS_CLOSED) {
149 break;
150 }
151 }
152
153 if (i == PLAT_SPCI_HANDLES_MAX_NUM) {
154 spin_unlock(&spci_handles_lock);
155
156 WARN("SPCI: Can't open more handles. Client 0x%04x\n",
157 client_id);
158 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
159 PRINT_UUID_ARGS(uuid));
160
161 SMC_RET2(handle, SPCI_NO_MEMORY, 0);
162 }
163
164 /* Create new handle value */
165 if (spci_create_handle_value(&service_handle) != 0) {
166 spin_unlock(&spci_handles_lock);
167
168 WARN("SPCI: Can't create a new handle value. Client 0x%04x\n",
169 client_id);
170 WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n",
171 PRINT_UUID_ARGS(uuid));
172
173 SMC_RET2(handle, SPCI_NO_MEMORY, 0);
174 }
175
176 /* Save all information about this handle */
177 spci_handles[i].status = HANDLE_STATUS_OPEN;
178 spci_handles[i].client_id = client_id;
179 spci_handles[i].handle = service_handle;
180 spci_handles[i].num_active_requests = 0U;
181 spci_handles[i].sp_ctx = sp_ptr;
182
183 /* Release lock of the array of handles */
184 spin_unlock(&spci_handles_lock);
185
186 VERBOSE("SPCI: Service handle request by client 0x%04x: 0x%04x\n",
187 client_id, service_handle);
188 VERBOSE("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid));
189
190 /* The handle is returned in the top 16 bits of x1 */
191 SMC_RET2(handle, SPCI_SUCCESS, ((uint32_t)service_handle) << 16);
192}
193
194/*******************************************************************************
195 * This function closes a handle that a specific client uses to access a Secure
196 * Service. It returns a SPCI_*** error code.
197 ******************************************************************************/
198static uint64_t spci_service_handle_close(void *handle, u_register_t x1)
199{
200 spci_handle_t *handle_info;
201 uint16_t client_id = x1 & 0x0000FFFFU;
202 uint16_t service_handle = (x1 >> 16) & 0x0000FFFFU;
203
204 spin_lock(&spci_handles_lock);
205
206 handle_info = spci_handle_info_get(service_handle, client_id);
207
208 if (handle_info == NULL) {
209 spin_unlock(&spci_handles_lock);
210
211 WARN("SPCI: Tried to close invalid handle 0x%04x by client 0x%04x\n",
212 service_handle, client_id);
213
214 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
215 }
216
217 if (handle_info->status != HANDLE_STATUS_OPEN) {
218 spin_unlock(&spci_handles_lock);
219
220 WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x in status %d\n",
221 service_handle, client_id, handle_info->status);
222
223 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
224 }
225
226 if (handle_info->num_active_requests != 0U) {
227 spin_unlock(&spci_handles_lock);
228
229 /* A handle can't be closed if there are requests left */
230 WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x with %d requests left\n",
231 service_handle, client_id,
232 handle_info->num_active_requests);
233
234 SMC_RET1(handle, SPCI_BUSY);
235 }
236
237 memset(handle_info, 0, sizeof(spci_handle_t));
238
239 handle_info->status = HANDLE_STATUS_CLOSED;
240
241 spin_unlock(&spci_handles_lock);
242
243 VERBOSE("SPCI: Closed handle 0x%04x by client 0x%04x.\n",
244 service_handle, client_id);
245
246 SMC_RET1(handle, SPCI_SUCCESS);
247}
248
249/*******************************************************************************
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000250 * This function requests a Secure Service from a given handle and client ID.
251 ******************************************************************************/
252static uint64_t spci_service_request_blocking(void *handle,
253 uint32_t smc_fid, u_register_t x1, u_register_t x2,
254 u_register_t x3, u_register_t x4, u_register_t x5,
255 u_register_t x6, u_register_t x7)
256{
257 spci_handle_t *handle_info;
258 sp_context_t *sp_ctx;
259 cpu_context_t *cpu_ctx;
260 uint32_t rx0;
261 u_register_t rx1, rx2, rx3;
262 uint16_t request_handle, client_id;
263
264 /* Get handle array lock */
265 spin_lock(&spci_handles_lock);
266
267 /* Get pointer to struct of this open handle and client ID. */
268 request_handle = (x7 >> 16U) & 0x0000FFFFU;
269 client_id = x7 & 0x0000FFFFU;
270
271 handle_info = spci_handle_info_get(request_handle, client_id);
272 if (handle_info == NULL) {
273 spin_unlock(&spci_handles_lock);
274
275 WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n");
276 WARN(" Handle 0x%04x. Client ID 0x%04x\n", request_handle,
277 client_id);
278
279 SMC_RET1(handle, SPCI_BUSY);
280 }
281
282 /* Get pointer to the Secure Partition that handles the service */
283 sp_ctx = handle_info->sp_ctx;
284 assert(sp_ctx != NULL);
285 cpu_ctx = &(sp_ctx->cpu_ctx);
286
287 /* Blocking requests are only allowed if the queue is empty */
288 if (handle_info->num_active_requests > 0) {
289 spin_unlock(&spci_handles_lock);
290
291 SMC_RET1(handle, SPCI_BUSY);
292 }
293
Antonio Nino Diaz44ef4eb2018-07-03 19:54:59 +0100294 if (spm_sp_request_increase_if_zero(sp_ctx) == -1) {
295 spin_unlock(&spci_handles_lock);
296
297 SMC_RET1(handle, SPCI_BUSY);
298 }
299
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000300 /* Prevent this handle from being closed */
301 handle_info->num_active_requests += 1;
302
303 /* Release handle lock */
304 spin_unlock(&spci_handles_lock);
305
306 /* Save the Normal world context */
307 cm_el1_sysregs_context_save(NON_SECURE);
308
309 /* Wait until the Secure Partition is idle and set it to busy. */
310 sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY);
311
312 /* Pass arguments to the Secure Partition */
313 struct sprt_queue_entry_message message = {
314 .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
315 .client_id = client_id,
316 .service_handle = request_handle,
317 .session_id = x6,
318 .token = 0, /* No token needed for blocking requests */
319 .args = {smc_fid, x1, x2, x3, x4, x5}
320 };
321
322 spin_lock(&(sp_ctx->spm_sp_buffer_lock));
323 int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
324 SPRT_QUEUE_NUM_BLOCKING);
325 spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
326 if (rc != 0) {
327 /*
328 * This shouldn't happen, blocking requests can only be made if
329 * the request queue is empty.
330 */
331 assert(rc == -ENOMEM);
332 ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
333 panic();
334 }
335
336 /* Jump to the Secure Partition. */
337 rx0 = spm_sp_synchronous_entry(sp_ctx);
338
339 /* Verify returned value */
340 if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
341 ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0);
342 panic();
343 }
344
345 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
346 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
347 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
348
349 /* Flag Secure Partition as idle. */
350 assert(sp_ctx->state == SP_STATE_BUSY);
351 sp_state_set(sp_ctx, SP_STATE_IDLE);
352
353 /* Decrease count of requests. */
354 spin_lock(&spci_handles_lock);
355 handle_info->num_active_requests -= 1;
356 spin_unlock(&spci_handles_lock);
Antonio Nino Diaz44ef4eb2018-07-03 19:54:59 +0100357 spm_sp_request_decrease(sp_ctx);
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000358
359 /* Restore non-secure state */
360 cm_el1_sysregs_context_restore(NON_SECURE);
361 cm_set_next_eret_context(NON_SECURE);
362
363 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
364}
365
366/*******************************************************************************
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000367 * This function handles all SMCs in the range reserved for SPCI.
368 ******************************************************************************/
369uint64_t spci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
370 uint64_t x3, uint64_t x4, void *cookie, void *handle,
371 uint64_t flags)
372{
373 uint32_t spci_fid;
374
375 /* SPCI only supported from the Non-secure world for now */
376 if (is_caller_non_secure(flags) == SMC_FROM_SECURE) {
377 SMC_RET1(handle, SMC_UNK);
378 }
379
380 if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) {
381
382 /* Miscellaneous calls */
383
384 spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK;
385
386 switch (spci_fid) {
387
388 case SPCI_FID_VERSION:
389 SMC_RET1(handle, SPCI_VERSION_COMPILED);
390
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +0000391 case SPCI_FID_SERVICE_HANDLE_OPEN:
392 {
393 if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) {
394 /* Not supported for now */
395 WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n");
396 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
397 }
398
399 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
400 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
401 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
402
403 return spci_service_handle_open_poll(handle, x1, x2, x3,
404 x4, x5, x6, x7);
405 }
406 case SPCI_FID_SERVICE_HANDLE_CLOSE:
407 return spci_service_handle_close(handle, x1);
408
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000409 case SPCI_FID_SERVICE_REQUEST_BLOCKING:
410 {
411 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
412 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
413 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
414
415 return spci_service_request_blocking(handle,
416 smc_fid, x1, x2, x3, x4, x5, x6, x7);
417 }
418
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000419 default:
420 break;
421 }
422
423 } else {
424
425 /* Tunneled calls */
426
427 }
428
429 WARN("SPCI: Unsupported call 0x%08x\n", smc_fid);
430 SMC_RET1(handle, SPCI_NOT_SUPPORTED);
431}