blob: cbb0f3cc379dc12f52340c950f82f8081fc98469 [file] [log] [blame]
Antonio Nino Diaze8ce60a2018-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 Diaz56ae9792018-11-08 14:20:07 +00007#include <assert.h>
Antonio Nino Diazd54f0ca2018-11-08 14:21:19 +00008#include <context_mgmt.h>
Antonio Nino Diaze8ce60a2018-11-08 14:12:40 +00009#include <debug.h>
Antonio Nino Diazd54f0ca2018-11-08 14:21:19 +000010#include <errno.h>
Antonio Nino Diaze8ce60a2018-11-08 14:12:40 +000011#include <smccc.h>
12#include <smccc_helpers.h>
13#include <spci_svc.h>
Antonio Nino Diaz56ae9792018-11-08 14:20:07 +000014#include <spinlock.h>
Antonio Nino Diazd54f0ca2018-11-08 14:21:19 +000015#include <sprt_host.h>
16#include <sprt_svc.h>
Antonio Nino Diaz56ae9792018-11-08 14:20:07 +000017#include <string.h>
Antonio Nino Diaze8ce60a2018-11-08 14:12:40 +000018#include <utils.h>
19
20#include "spm_private.h"
21
22/*******************************************************************************
Antonio Nino Diaz56ae9792018-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 Diazd54f0ca2018-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
294 /* Prevent this handle from being closed */
295 handle_info->num_active_requests += 1;
296
297 /* Release handle lock */
298 spin_unlock(&spci_handles_lock);
299
300 /* Save the Normal world context */
301 cm_el1_sysregs_context_save(NON_SECURE);
302
303 /* Wait until the Secure Partition is idle and set it to busy. */
304 sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY);
305
306 /* Pass arguments to the Secure Partition */
307 struct sprt_queue_entry_message message = {
308 .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
309 .client_id = client_id,
310 .service_handle = request_handle,
311 .session_id = x6,
312 .token = 0, /* No token needed for blocking requests */
313 .args = {smc_fid, x1, x2, x3, x4, x5}
314 };
315
316 spin_lock(&(sp_ctx->spm_sp_buffer_lock));
317 int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
318 SPRT_QUEUE_NUM_BLOCKING);
319 spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
320 if (rc != 0) {
321 /*
322 * This shouldn't happen, blocking requests can only be made if
323 * the request queue is empty.
324 */
325 assert(rc == -ENOMEM);
326 ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
327 panic();
328 }
329
330 /* Jump to the Secure Partition. */
331 rx0 = spm_sp_synchronous_entry(sp_ctx);
332
333 /* Verify returned value */
334 if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
335 ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0);
336 panic();
337 }
338
339 rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
340 rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
341 rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
342
343 /* Flag Secure Partition as idle. */
344 assert(sp_ctx->state == SP_STATE_BUSY);
345 sp_state_set(sp_ctx, SP_STATE_IDLE);
346
347 /* Decrease count of requests. */
348 spin_lock(&spci_handles_lock);
349 handle_info->num_active_requests -= 1;
350 spin_unlock(&spci_handles_lock);
351
352 /* Restore non-secure state */
353 cm_el1_sysregs_context_restore(NON_SECURE);
354 cm_set_next_eret_context(NON_SECURE);
355
356 SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
357}
358
359/*******************************************************************************
Antonio Nino Diaze8ce60a2018-11-08 14:12:40 +0000360 * This function handles all SMCs in the range reserved for SPCI.
361 ******************************************************************************/
362uint64_t spci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
363 uint64_t x3, uint64_t x4, void *cookie, void *handle,
364 uint64_t flags)
365{
366 uint32_t spci_fid;
367
368 /* SPCI only supported from the Non-secure world for now */
369 if (is_caller_non_secure(flags) == SMC_FROM_SECURE) {
370 SMC_RET1(handle, SMC_UNK);
371 }
372
373 if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) {
374
375 /* Miscellaneous calls */
376
377 spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK;
378
379 switch (spci_fid) {
380
381 case SPCI_FID_VERSION:
382 SMC_RET1(handle, SPCI_VERSION_COMPILED);
383
Antonio Nino Diaz56ae9792018-11-08 14:20:07 +0000384 case SPCI_FID_SERVICE_HANDLE_OPEN:
385 {
386 if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) {
387 /* Not supported for now */
388 WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n");
389 SMC_RET1(handle, SPCI_INVALID_PARAMETER);
390 }
391
392 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
393 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
394 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
395
396 return spci_service_handle_open_poll(handle, x1, x2, x3,
397 x4, x5, x6, x7);
398 }
399 case SPCI_FID_SERVICE_HANDLE_CLOSE:
400 return spci_service_handle_close(handle, x1);
401
Antonio Nino Diazd54f0ca2018-11-08 14:21:19 +0000402 case SPCI_FID_SERVICE_REQUEST_BLOCKING:
403 {
404 uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
405 uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
406 uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
407
408 return spci_service_request_blocking(handle,
409 smc_fid, x1, x2, x3, x4, x5, x6, x7);
410 }
411
Antonio Nino Diaze8ce60a2018-11-08 14:12:40 +0000412 default:
413 break;
414 }
415
416 } else {
417
418 /* Tunneled calls */
419
420 }
421
422 WARN("SPCI: Unsupported call 0x%08x\n", smc_fid);
423 SMC_RET1(handle, SPCI_NOT_SUPPORTED);
424}