blob: 76085091f4b86a048e407f448830617ce1e19885 [file] [log] [blame]
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
30
31#include <partition_parser.h>
32#include <qseecom_lk.h>
33#include <scm.h>
34#include <qseecomi_lk.h>
35#include "qseecom_lk_api.h"
36#include <debug.h>
37#include <kernel/mutex.h>
38#include <malloc.h>
39#include <stdlib.h>
40#include <arch/defines.h>
41#include <string.h>
42#include <platform/iomap.h>
43#include <platform.h>
44
45#define QSEOS_VERSION_14 0x14
46#define QSEEE_VERSION_00 0x400000
47#define QSEE_VERSION_20 0x800000
48
49
50#define QSEOS_CHECK_VERSION_CMD 0x00001803
51
52#define MAX_SCM_ARGS 10
53#define N_EXT_SCM_ARGS 7
54#define FIRST_EXT_ARG_IDX 3
55
56#define N_REGISTER_ARGS (MAX_SCM_ARGS - N_EXT_SCM_ARGS + 1)
57
58#define QSEE_LOG_BUF_SIZE (4096)
59#define GENERIC_ERROR -1
60#define LISTENER_ALREADY_PRESENT_ERROR -2
61
62#define TZ_CALL 6
63enum qseecom_client_handle_type {
64 QSEECOM_CLIENT_APP = 1,
65 QSEECOM_LISTENER_SERVICE,
66 QSEECOM_SECURE_SERVICE,
67 QSEECOM_GENERIC,
68 QSEECOM_UNAVAILABLE_CLIENT_APP,
69};
70
71struct qseecom_registered_listener_list {
72 struct list_node node;
73 struct qseecom_register_listener_req svc;
74 ListenerCallback CallbackFn;
75};
76
77struct qseecom_registered_app_list {
78 struct list_node node;
79 uint32_t app_id;
80 uint32_t ref_cnt;
81 char app_name[MAX_APP_NAME_SIZE];
82 int handle;
83};
84
85struct qseecom_control {
86 struct list_node registered_listener_list_head;
87 mutex_t registered_listener_list_lock;
88
89 struct list_node registered_app_list_head;
90 mutex_t registered_app_list_lock;
91
92 uint32_t qseos_version;
93 uint32_t qsee_version;
94 int handle;
95 bool commonlib_loaded;
96 mutex_t global_data_lock;
97 uint32_t cmnlib_loaded;
98 uint32_t qseecom_init_done;
99 uint32_t qseecom_tz_init_done;
100};
101
102struct qseecom_listener_handle {
103 uint32_t id;
104};
105
Zhen Kong91657682015-09-30 16:27:16 -0700106static struct qseecom_reg_log_buf_ireq logbuf_req = {0};
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800107static struct qseecom_control qseecom;
108static int __qseecom_process_incomplete_cmd(struct qseecom_command_scm_resp *resp,
109 struct qseecom_client_listener_data_irsp *send_data_rsp);
110
111/*
112 * Appsbl runs in Aarch32 when this is ported for Aarch64,
113 * change return type for uint64_t.
114 */
115static uint32_t __qseecom_uvirt_to_kphys(uint64_t virt)
116{
117 dprintf(SPEW, "%s called\n", __func__);
118 return (uint32_t)platform_get_virt_to_phys_mapping((addr_t)virt);
119}
120
121static int _disp_log_stats(struct tzdbg_log_t *log, uint32_t log_len,
122 uint32_t startOffset, uint32_t endOffset)
123{
124 uint32_t MaxBufSize = 0;
125 uint32_t LogBufSize = 0;
126 uint32_t LogBufFirstHalf = 0;
127 uint32_t len = 0;
128 char *pCurPos, *pPrintPos = NULL;
129 void *pLogBuf = NULL;
130 int ret = GENERIC_ERROR;
131
132 MaxBufSize = QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t);
133
134 dprintf(SPEW, "%s called\n", __func__);
135 if (startOffset < endOffset)
136 {
137 LogBufSize = endOffset - startOffset;
138 pLogBuf = malloc(LogBufSize);
139 if (NULL == pLogBuf)
140 {
141 ret = GENERIC_ERROR;
142 dprintf(CRITICAL, "Failed to alloc buffer to print TZ Log:%u\n", LogBufSize);
143 goto err;
144 }
145 memset(pLogBuf, 0, LogBufSize);
146 memscpy(pLogBuf, LogBufSize, (char *)((uint32_t)log->log_buf + startOffset), LogBufSize);
147 }
148 else if ( endOffset < startOffset)
149 {
150 LogBufSize = MaxBufSize - (startOffset - endOffset);
151 LogBufFirstHalf = MaxBufSize - startOffset;
152 pLogBuf = malloc(LogBufSize);
153 if (NULL == pLogBuf)
154 {
155 ret = GENERIC_ERROR;
156 dprintf(CRITICAL, "Failed to alloc buffer to print TZ Log:%u\n", LogBufSize);
157 goto err;
158 }
159 memset(pLogBuf, 0, LogBufSize);
160 memscpy(pLogBuf, LogBufSize, (char *)((uint32_t)log->log_buf + startOffset), LogBufFirstHalf);
161 memscpy((char *)((uint32_t)pLogBuf+ LogBufFirstHalf), (LogBufSize - LogBufFirstHalf), log->log_buf, endOffset);
162 }
163 else //endOffset == startOffset
164 {
165 ret = 0;
166 goto err;
167 }
168
169 /*
170 * Read from ring buff while there is data and space in return buff
171 */
172 pCurPos = pLogBuf;
173 pPrintPos = pCurPos;
174 while (len < LogBufSize)
175 {
176 //QSEE separate each line by "\r \n"
177 if ((*pCurPos == '\r')&&(*(pCurPos+1) == '\n'))
178 {
179 //update the line to dump
180 *pCurPos = '\0';
181 len++;
182 pCurPos++;
183 *pCurPos = '\0';
184 len++;
185 pCurPos++;
186 dprintf(ALWAYS, "%s\n", pPrintPos);
187 pPrintPos = pCurPos;
188 continue;
189 }
190 len++;
191 pCurPos++;
192 }
193 ret = 0;
194 free(pLogBuf);
195err:
196 return ret;
197}
198
199static int allocate_extra_arg_buffer(uint32_t fn_id, struct scm_desc *desc)
200{
201 int i;
202 int ret = GENERIC_ERROR;
203 scmcall_arg arg = {0};
204 scmcall_ret ret_arg = {0};
205 int arglen = 0;
206
207 if (!desc) {
208 dprintf(CRITICAL, "%s: Invalid input\n", __func__);
209 return GENERIC_ERROR;
210 }
211
212 dprintf(SPEW, "%s called\n", __func__);
213 arglen = desc->arginfo & 0xf;
214
215 dprintf(SPEW, "%s:fn_id:%u, desc->arginfo:%u desc->args[0]:%u desc->args[1]:%u desc->args[2]:%u desc->args[3]:%u desc->args[4]:%u\n",
216 __func__, fn_id, desc->arginfo, desc->args[0], desc->args[1], desc->args[2], desc->args[3], desc->args[4]);
217
218 arg.x0 = fn_id;
219 arg.x1 = desc->arginfo;
220 arg.x2 = desc->args[0];
221 arg.x3 = desc->args[1];
222 arg.x4 = desc->args[2];
223
224 if (arglen > FIRST_EXT_ARG_IDX) {
225 for (i = 0; i < (arglen - FIRST_EXT_ARG_IDX); i++) {
226 arg.x5[i] = desc->args[i + FIRST_EXT_ARG_IDX];
227 }
228 }
229 ret = scm_call2(&arg, &ret_arg);
230 desc->ret[0] = ret_arg.x1;
231 desc->ret[1] = ret_arg.x2;
232 desc->ret[2] = ret_arg.x3;
233
234 dprintf(SPEW, "%s:ret:%d, desc->ret[0]]:%u desc->ret[1]:%u desc->ret[2]:%u\n",
235 __func__, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
236 return ret;
237}
238
239static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
240 const void *req_buf, void *resp_buf)
241{
242 int ret = 0;
243 uint32_t smc_id = 0;
244 uint32_t qseos_cmd_id = 0;
245 struct scm_desc desc = {0};
246 struct qseecom_command_scm_resp *scm_resp = NULL;
247
248 if (!req_buf || !resp_buf) {
249 dprintf(CRITICAL, "Invalid buffer pointer\n");
250 return GENERIC_ERROR;
251 }
252 dprintf(SPEW, "%s called\n", __func__);
253
254 qseos_cmd_id = *(uint32_t *)req_buf;
255 scm_resp = (struct qseecom_command_scm_resp *)resp_buf;
256
257 switch (svc_id) {
258 case TZ_CALL: {
259 if (tz_cmd_id == 1) {
260 smc_id = TZ_INFO_IS_SVC_AVAILABLE_ID;
261 desc.arginfo = TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID;
262 desc.args[0] = TZ_INFO_GET_FEATURE_VERSION_ID;
263 } else if (tz_cmd_id == 3) {
264 smc_id = TZ_INFO_GET_FEATURE_VERSION_ID;
265 desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID;
266 desc.args[0] = *(uint32_t *)req_buf;
267 }
268 ret = allocate_extra_arg_buffer(smc_id, &desc);
269 break;
270 }
271
272 case SCM_SVC_TZSCHEDULER: {
273 switch (qseos_cmd_id) {
274 case QSEE_APP_START_COMMAND: {
275 struct qseecom_load_app_ireq *req;
276 req = (struct qseecom_load_app_ireq *)req_buf;
277 smc_id = TZ_OS_APP_START_ID;
278 desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID;
279 desc.args[0] = req->mdt_len;
280 desc.args[1] = req->img_len;
281 desc.args[2] = req->phy_addr;
282 dprintf(SPEW, "args[0]:%u args[1]:%u args[2]:%u\n",
283 desc.args[0], desc.args[1], desc.args[2]);
284 dprintf(SPEW, "mdt_len:%u img_len:%u phy_addr:%u\n",
285 req->mdt_len, req->img_len, req->phy_addr);
286 ret = allocate_extra_arg_buffer(smc_id, &desc);
287
288 break;
289 }
290 case QSEE_APP_SHUTDOWN_COMMAND: {
291 struct qseecom_unload_app_ireq *req;
292 req = (struct qseecom_unload_app_ireq *)req_buf;
293 smc_id = TZ_OS_APP_SHUTDOWN_ID;
294 desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
295 desc.args[0] = req->app_id;
296 ret = allocate_extra_arg_buffer(smc_id, &desc);
297 break;
298 }
299 case QSEE_APP_REGION_NOTIFICATION: {
300 struct qsee_apps_region_info_ireq *req;
301 req = (struct qsee_apps_region_info_ireq *)req_buf;
302 smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID;
303 desc.arginfo =
304 TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID;
305 desc.args[0] = req->addr;
306 desc.args[1] = req->size;
307 ret = allocate_extra_arg_buffer(smc_id, &desc);
308 break;
309 }
310 case QSEE_LOAD_SERV_IMAGE_COMMAND: {
311 struct qseecom_load_app_ireq *req;
312 req = (struct qseecom_load_app_ireq *)req_buf;
313 smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID;
314 desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
315 desc.args[0] = req->mdt_len;
316 desc.args[1] = req->img_len;
317 desc.args[2] = req->phy_addr;
318 dprintf(SPEW, "QSEE_LOAD_SERV_IMAGE_COMMAND mdt_len:%u img_len:%u phy_addr:%u\n",
319 req->mdt_len, req->img_len, req->phy_addr);
320 ret = allocate_extra_arg_buffer(smc_id, &desc);
321 break;
322 }
323 case QSEE_UNLOAD_SERV_IMAGE_COMMAND: {
324 smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
325 desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
326 ret = allocate_extra_arg_buffer(smc_id, &desc);
327 break;
328 }
329 case QSEE_REGISTER_LISTENER: {
330 struct qseecom_register_listener_ireq *req;
331 req = (struct qseecom_register_listener_ireq *)req_buf;
332 smc_id = TZ_OS_REGISTER_LISTENER_ID;
333 desc.arginfo =
334 TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
335 desc.args[0] = req->listener_id;
336 desc.args[1] = req->sb_ptr;
337 desc.args[2] = req->sb_len;
338 ret = allocate_extra_arg_buffer(smc_id, &desc);
339 break;
340 }
341 case QSEE_DEREGISTER_LISTENER: {
342 struct qseecom_unregister_listener_ireq *req;
343 req = (struct qseecom_unregister_listener_ireq *)
344 req_buf;
345 smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
346 desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
347 desc.args[0] = req->listener_id;
348 ret = allocate_extra_arg_buffer(smc_id, &desc);
349 break;
350 }
351 case QSEE_LISTENER_DATA_RSP_COMMAND: {
352 struct qseecom_client_listener_data_irsp *req;
353 req = (struct qseecom_client_listener_data_irsp *)
354 req_buf;
355 smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID;
356 desc.arginfo =
357 TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
358 desc.args[0] = req->listener_id;
359 desc.args[1] = req->status;
360 ret = allocate_extra_arg_buffer(smc_id, &desc);
361 break;
362 }
363 case QSEE_CLIENT_SEND_DATA_COMMAND: {
364 struct qseecom_client_send_data_ireq *req;
365 req = (struct qseecom_client_send_data_ireq *)req_buf;
366 smc_id = TZ_APP_QSAPP_SEND_DATA_ID;
367 desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID;
368 desc.args[0] = req->app_id;
369 desc.args[1] = req->req_ptr;
370 desc.args[2] = req->req_len;
371 desc.args[3] = req->rsp_ptr;
372 desc.args[4] = req->rsp_len;
373 ret = allocate_extra_arg_buffer(smc_id, &desc);
374 break;
375 }
376 case QSEE_RPMB_PROVISION_KEY_COMMAND: {
377 struct qseecom_client_send_service_ireq *req;
378 req = (struct qseecom_client_send_service_ireq *)
379 req_buf;
380 smc_id = TZ_OS_RPMB_PROVISION_KEY_ID;
381 desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
382 desc.args[0] = req->key_type;
383 ret = allocate_extra_arg_buffer(smc_id, &desc);
384 break;
385 }
386 case QSEE_RPMB_ERASE_COMMAND: {
387 smc_id = TZ_OS_RPMB_ERASE_ID;
388 desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
389 ret = allocate_extra_arg_buffer(smc_id, &desc);
390 break;
391 }
392
393 case QSEE_REGISTER_LOG_BUF_COMMAND: {
394 struct qseecom_reg_log_buf_ireq *req;
395 req = (struct qseecom_reg_log_buf_ireq *)req_buf;
396 smc_id = TZ_OS_REGISTER_LOG_BUFFER_ID;
397 desc.arginfo = TZ_OS_REGISTER_LOG_BUFFER_ID_PARAM_ID;
398 desc.args[0] = req->phy_addr;
399 desc.args[1] = req->len;
400 ret = allocate_extra_arg_buffer(smc_id, &desc);
401 break;
402 }
403 default: {
404 dprintf(CRITICAL, "qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n",
405 qseos_cmd_id);
406 ret = GENERIC_ERROR;
407 break;
408 }
409 } /*end of switch (qsee_cmd_id) */
410 break;
411 } /*end of case SCM_SVC_TZSCHEDULER*/
412 default: {
413 dprintf(CRITICAL, "svc_id 0x%x is not supported by armv8 scm_call2.\n",
414 svc_id);
415 ret = GENERIC_ERROR;
416 break;
417 }
418 } /*end of switch svc_id */
419 scm_resp->result = desc.ret[0];
420 scm_resp->resp_type = desc.ret[1];
421 scm_resp->data = desc.ret[2];
422 dprintf(SPEW, "svc_id = 0x%x, tz_cmd_id = 0x%x, qseos_cmd_id = 0x%x, smc_id = 0x%x, param_id = 0x%x\n",
423 svc_id, tz_cmd_id, qseos_cmd_id, smc_id, desc.arginfo);
424 dprintf(SPEW, "scm_resp->result = 0x%x, scm_resp->resp_type = 0x%x, scm_resp->data = 0x%x\n",
425 scm_resp->result, scm_resp->resp_type, scm_resp->data);
426 return ret;
427}
428
429static int qseecom_scm_call(uint32_t svc_id, uint32_t tz_cmd_id, void *cmd_buf,
430 size_t cmd_len, void *resp_buf, size_t resp_len)
431{
432 void *req = NULL;
433 struct qseecom_command_scm_resp *resp = NULL;
434 struct qseecom_client_listener_data_irsp send_data_rsp = {0};
435 int ret = GENERIC_ERROR;
436 uint32_t qseos_cmd_id = 0;
Zhen Kong91657682015-09-30 16:27:16 -0700437 struct tzdbg_log_t *log = NULL;
438 uint32_t QseeLogStart = 0;
439 uint32_t QseeLogNewStart = 0;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800440
441 if ((!cmd_buf) || (!resp_buf))
442 return GENERIC_ERROR;
443
444 dprintf(SPEW, "%s called\n", __func__);
445 mutex_acquire(&qseecom.registered_app_list_lock);
446 req = cmd_buf;
447 qseos_cmd_id = *(uint32_t *)req;
448 resp = (struct qseecom_command_scm_resp *) resp_buf;
449
450 do {
451 if (!is_scm_armv8_support()) {
452 ret = scm_call(svc_id, tz_cmd_id, req, cmd_len,
453 resp_buf, resp_len);
454 } else {
Zhen Kong91657682015-09-30 16:27:16 -0700455 if(logbuf_req.phy_addr)
456 {
457 log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
458 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
459 QseeLogStart = (uint32_t) log->log_pos.offset;
460 }
461
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800462 ret = qseecom_scm_call2(svc_id, tz_cmd_id, req, resp);
Zhen Kong91657682015-09-30 16:27:16 -0700463 if(logbuf_req.phy_addr)
464 {
465 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
466 QseeLogNewStart = (uint32_t) log->log_pos.offset;
467 _disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr,
468 QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
469 QseeLogStart, QseeLogNewStart);
470 }
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800471 }
472
473 if (ret) {
474 dprintf(CRITICAL, "ERROR: scm_call to load failed : ret %d\n", ret);
475 ret = GENERIC_ERROR;
476 goto err;
477 }
478
479 if (svc_id == TZ_CALL) {
480 goto err;
481 }
482
483 switch (resp->result) {
484 case QSEOS_RESULT_SUCCESS:
485 if(((resp->resp_type != QSEOS_APP_ID) || (resp->data <= 0)) &&
Zhen Kong91657682015-09-30 16:27:16 -0700486 (qseos_cmd_id == QSEE_CLIENT_SEND_DATA_COMMAND))
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800487 {
488 dprintf(CRITICAL, "ERROR: Resp type %d or Resp Data %d incorrect\n",
489 resp->resp_type, resp->data);
490 ret = GENERIC_ERROR;
491 goto err;
492 }
493 goto err;
494 case QSEOS_RESULT_FAILURE:
495 dprintf(CRITICAL, "scm call failed w/response result%d\n", resp->result);
496 ret = GENERIC_ERROR;
497 goto err;
498 case QSEOS_RESULT_INCOMPLETE:
499 if(resp->resp_type != QSEOS_LISTENER_ID)
500 {
501 ret = GENERIC_ERROR;
502 dprintf(CRITICAL, "Listener service incorrect resp->result:%d resp->resp_type:%d\n",
503 resp->result, resp->resp_type);
504 goto err;
505 }
506 __qseecom_process_incomplete_cmd(resp, &send_data_rsp);
507 req = (void *)&send_data_rsp;
508 qseos_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
509 break;
510 default:
511 dprintf(CRITICAL, "scm call return unknown response %d\n", resp->result);
512 ret = GENERIC_ERROR;
513 goto err;
514 }
515 } while(true);
516
517err:
518 mutex_release(&qseecom.registered_app_list_lock);
519 return ret;
520
521}
522
523static int __qseecom_process_incomplete_cmd(struct qseecom_command_scm_resp *resp,
524 struct qseecom_client_listener_data_irsp *send_data_rsp)
525{
526 int ret = 0;
527 struct qseecom_registered_listener_list *entry;
528
529 if ((!resp) || (!send_data_rsp))
530 {
531 return GENERIC_ERROR;
532 }
533
534 dprintf(SPEW, "%s called\n", __func__);
535 mutex_acquire(&qseecom.global_data_lock);
536
537 list_for_every_entry(&qseecom.registered_listener_list_head,
538 entry, struct qseecom_registered_listener_list, node) {
539 if (resp->data == entry->svc.listener_id) {
540 arch_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
541 entry->CallbackFn(entry->svc.virt_sb_base, entry->svc.sb_size);
542 arch_clean_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
543 break;
544 }
545 }
546 send_data_rsp->qsee_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
547 send_data_rsp->listener_id = entry->svc.listener_id;
548 send_data_rsp->status = 0;
549 mutex_release(&qseecom.global_data_lock);
550 return ret;
551}
552
553static int __qseecom_load_app(const char *app_name, unsigned int *app_id)
554{
555 int index = INVALID_PTN;
556 unsigned long long ptn = 0;
557 unsigned long long size = 0;
558 void *buf = NULL;
559 void *req = NULL;
560 struct qseecom_load_app_ireq load_req = {0};
561 struct qseecom_command_scm_resp resp;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800562
563 int ret = GENERIC_ERROR;
564 uint8_t lun = 0;
565
566 if (!app_name)
567 return GENERIC_ERROR;
568
569 dprintf(SPEW, "%s called\n", __func__);
570 index = partition_get_index(app_name);
571 lun = partition_get_lun(index);
572 mmc_set_lun(lun);
573
574 size = partition_get_size(index);
575
576 buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
577 if (!buf) {
578 dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
579 __func__, app_name);
580 ret = GENERIC_ERROR;
581 goto err;
582 }
583
584 ptn = partition_get_offset(index);
585 if(ptn == 0) {
586 dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
587 ret = GENERIC_ERROR;
588 goto err;
589 }
590 if (mmc_read(ptn, (unsigned int *) buf, size)) {
591 dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
592 ret = GENERIC_ERROR;
593 goto err;
594 }
595
596 /* Currently on 8994 only 32-bit phy addr is supported
597 * Hence downcasting is okay
598 */
599 load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
600 load_req.qsee_cmd_id = QSEE_APP_START_COMMAND;
601 load_req.img_len = size;
602 load_req.mdt_len = 0;
603 dprintf(SPEW, "phy_addr:%u img_len:%u\n", load_req.phy_addr, load_req.img_len);
604
605 memscpy(&load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
606 req = (void *)&load_req;
607
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800608 arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
609 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
610 sizeof(struct qseecom_load_lib_image_ireq),
611 &resp, sizeof(resp));
612 if(ret == 0)
613 *app_id = resp.data;
614 else
615 *app_id = 0;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800616err:
617 if (buf)
618 free(buf);
619 return ret;
620}
621
622static int qseecom_load_commonlib_image(char * app_name)
623{
624 int index = INVALID_PTN;
625 unsigned long long ptn = 0;
626 unsigned long long size = 0;
627 void *buf = NULL;
628 void *req = NULL;
629 struct qseecom_load_app_ireq load_req = {0};
630 struct qseecom_command_scm_resp resp = {0};
631 int ret = GENERIC_ERROR;
632 uint8_t lun = 0;
633
634 dprintf(SPEW, "%s called\n", __func__);
635 index = partition_get_index(app_name);
636 lun = partition_get_lun(index);
637 mmc_set_lun(lun);
638
639 size = partition_get_size(index);
640
641 buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
642 if (!buf) {
643 dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
644 __func__, app_name);
645 ret = GENERIC_ERROR;
646 goto err;
647 }
648
649 ptn = partition_get_offset(index);
650 if(ptn == 0) {
651 dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
652 ret = GENERIC_ERROR;
653 goto err;
654 }
655 if (mmc_read(ptn, (unsigned int *) buf, size)) {
656 dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
657 ret = GENERIC_ERROR;
658 goto err;
659 }
660
661 /* Currently on 8994 only 32-bit phy addr is supported
662 * Hence downcasting is okay
663 */
664 load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
665 load_req.qsee_cmd_id = QSEE_LOAD_SERV_IMAGE_COMMAND;
666 load_req.img_len = size;
667 load_req.mdt_len = 0;
668
669 memscpy(load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
670 req = (void *)&load_req;
671
672 arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
673 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
674 sizeof(struct qseecom_load_lib_image_ireq),
675 &resp, sizeof(resp));
676 if(ret == 0)
677 ret = resp.data;
678
679err:
680 if (buf)
681 free(buf);
682 return ret;
683}
684
685static int qseecom_unload_commonlib_image(void)
686{
687 int ret = GENERIC_ERROR;
688 struct qseecom_unload_lib_image_ireq unload_req = {0};
689 struct qseecom_command_scm_resp resp;
690
691 dprintf(SPEW, "%s called\n", __func__);
692 /* Populate the remaining parameters */
693 unload_req.qsee_cmd_id = QSEE_UNLOAD_SERV_IMAGE_COMMAND;
694 /* SCM_CALL to load the image */
695 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
696 sizeof(struct qseecom_unload_lib_image_ireq),
697 &resp, sizeof(resp));
698 return ret;
699}
700
701/*
702 * This function is called with the global
703 * data mutex acquired.
704 */
705static struct qseecom_registered_app_list *
706 __qseecom_add_app_entry(char *app_name, uint32_t app_id)
707{
708 struct qseecom_registered_app_list *entry = NULL;
709 int32_t ret = GENERIC_ERROR;
710
711 if ((!app_name) || (app_id == 0)) {
712 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
713 return NULL;
714 }
715 dprintf(SPEW, "%s called\n", __func__);
716
717 entry = malloc(sizeof(*entry));
718 if (!entry) {
719 dprintf(CRITICAL, "malloc for app entry failed\n");
720 ret = GENERIC_ERROR;
721 goto err;
722 }
723 entry->app_id = app_id;
724 entry->ref_cnt = 1;
725 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
726
727 dprintf(SPEW, "%s: Adding app:%s app_id:%u to list\n", __func__, entry->app_name, entry->app_id);
728 list_add_tail(&qseecom.registered_app_list_head, &entry->node);
729 ret = 0;
730err:
731 if (entry && (ret < 0)) {
732 free(entry);
733 return NULL;
734 }
735 return entry;
736}
737
738/*
739 * This function is called with the global
740 * data mutex acquired.
741 */
742static int
743 __qseecom_remove_app_entry(struct qseecom_registered_app_list *entry)
744{
745 if (!entry) {
746 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
747 return GENERIC_ERROR;
748 }
749 dprintf(SPEW, "%s called\n", __func__);
750 list_delete(&entry->node);
751 free(entry);
752
753 return 0;
754}
755
756/*
757 * This function is called with the global
758 * data mutex acquired.
759 */
760struct qseecom_registered_listener_list *
761 __qseecom_check_listener_exists(uint32_t listener_id)
762{
763 struct qseecom_registered_listener_list *entry = NULL;
764 bool listener_present = false;
765
766 if (!listener_id) {
767 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
768 return NULL;
769 }
770 dprintf(SPEW, "%s called\n", __func__);
771
772 list_for_every_entry(&qseecom.registered_listener_list_head,
773 entry, struct qseecom_registered_listener_list, node) {
774 if (entry->svc.listener_id == listener_id) {
775 listener_present = true;
776 break;
777 }
778 }
779 if (listener_present)
780 return entry;
781 else
782 return NULL;
783}
784
785/*
786 * This function is called with the global
787 * data mutex acquired.
788 */
789static struct qseecom_registered_app_list
790 *__qseecom_check_handle_exists(int handle)
791{
792 struct qseecom_registered_app_list *entry;
793 bool app_present = false;
794
795 if (handle <= 0) {
796 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
797 return NULL;
798 }
799 dprintf(SPEW, "%s called\n", __func__);
800 list_for_every_entry(&qseecom.registered_app_list_head,
801 entry, struct qseecom_registered_app_list, node) {
802 if (entry->handle == handle) {
803 app_present = true;
804 break;
805 }
806 }
807
808 if (app_present == true)
809 return entry;
810 else
811 return NULL;
812
813}
814
815
816static struct qseecom_registered_app_list *
817 __qseecom_check_app_exists(char *app_name)
818{
819 struct qseecom_registered_app_list *entry = NULL;
820
821 dprintf(SPEW, "%s called\n", __func__);
822 list_for_every_entry(&qseecom.registered_app_list_head,
823 entry, struct qseecom_registered_app_list, node) {
824 if (!strncmp(app_name, entry->app_name, 32)) {
825 dprintf(SPEW, "%s: app_name:%s\n", __func__, app_name);
826 return entry;
827 }
828 }
829 return NULL;
830}
831
832static int qseecom_unload_app(uint32_t app_id)
833{
834 int ret = 0;
835 struct qseecom_command_scm_resp resp;
836 struct qseecom_unload_app_ireq req;
837
838 dprintf(SPEW, "%s called\n", __func__);
839 /* Populate the structure for sending scm call to load image */
840 req.qsee_cmd_id = QSEE_APP_SHUTDOWN_COMMAND;
841 req.app_id = app_id;
842
843 /* SCM_CALL to unload the app */
844 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
845 sizeof(struct qseecom_unload_app_ireq),
846 &resp, sizeof(resp));
847
848 return ret;
849}
850
851
852static int __qseecom_send_cmd(uint32_t app_id, struct qseecom_send_cmd_req *req)
853{
854 int ret = 0;
855 struct qseecom_client_send_data_ireq send_data_req;
856 struct qseecom_command_scm_resp resp;
857 void *buf = NULL;
858 uint32_t size = 0;
859
860 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
861 dprintf(CRITICAL, "%s: cmd buffer or response buffer is null\n",
862 __func__);
863 return GENERIC_ERROR;
864 }
865 dprintf(SPEW, "%s called\n", __func__);
866
867 /* Allocate for req or rsp len whichever is higher, both req and rsp point
868 * to the same buffer
869 */
870 size = (req->cmd_req_len > req->resp_len) ? req->cmd_req_len : req->resp_len;
871
872 /* The req rsp buffer will be xPU protected by TZ during a TZ APP call
873 * This will still be protected during a listener call and there is a
874 * possibility of prefetching happening, which will cause xPU violation.
875 * Hence using (device memory with xN set) to prevent I or D prefetching.
876 * This is a contiguous region of 1MB used only for this, hence will not
877 * free this.
878 */
879 buf = (void *)RPMB_SND_RCV_BUF;
880 if (!buf) {
881 dprintf(CRITICAL, "%s: Aloc failed for app_id:%d of size:%d\n",
882 __func__, app_id, size);
883 return GENERIC_ERROR;
884 }
885
886 memscpy(buf, ROUNDUP(size, PAGE_SIZE), req->cmd_req_buf, req->cmd_req_len);
887
888 send_data_req.qsee_cmd_id = QSEE_CLIENT_SEND_DATA_COMMAND;
889 send_data_req.app_id = app_id;
890
891 /* Currently on 8994 only 32-bit phy addr is supported
892 * Hence downcasting is okay
893 */
894 send_data_req.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
895 send_data_req.req_len = req->cmd_req_len;
896 send_data_req.rsp_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
897 send_data_req.rsp_len = req->resp_len;
898
899 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
900 (void *)&send_data_req,
901 sizeof(send_data_req), (void *)&resp, sizeof(resp));
902
903 memscpy(req->resp_buf, req->resp_len, (void *)send_data_req.rsp_ptr, send_data_req.rsp_len);
904 return ret;
905}
906
907/**
908* Start a Secure App
909*
910* @param char* app_name
911* App name of the Secure App to be started
912*
913* @return int
914* Success: handle to be used for all calls to
915* Secure app. Always greater than zero.
916* Failure: Error code (negative only).
917*/
918int qseecom_start_app(char *app_name)
919{
920 int32_t ret = GENERIC_ERROR;
921 int handle = 0;
922 struct qseecom_registered_app_list *entry = NULL;
923 unsigned int app_id = 0;
924
925 if (!app_name) {
926 dprintf(CRITICAL, "%s: Input error\n", __func__);
927 goto err;
928 }
929 dprintf(SPEW, "%s called\n", __func__);
930
931
932 mutex_acquire(&qseecom.global_data_lock);
933 if ((!qseecom.qseecom_init_done)
934 || (!qseecom.qseecom_tz_init_done)){
935 dprintf(CRITICAL, "%s qseecom_init not done\n",
936 __func__);
937 mutex_release(&qseecom.global_data_lock);
938 return ret;
939 }
Zhen Kong91657682015-09-30 16:27:16 -0700940 mutex_release(&qseecom.global_data_lock);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800941 /* Load commonlib image*/
942 if (!qseecom.cmnlib_loaded) {
943 ret = qseecom_load_commonlib_image("cmnlib");
944 if (ret) {
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800945 dprintf(CRITICAL, "%s qseecom_load_commonlib_image failed with status:%d\n",
946 __func__, ret);
947 goto err;
948 }
949 qseecom.cmnlib_loaded = 1;
950 }
951 /* Check if App already exits, if exits increase ref_cnt
952 * and return handle, else load the app from partition,
953 * call into TZ to load it, add to list and then return
954 * handle.
955 */
Zhen Kong91657682015-09-30 16:27:16 -0700956 mutex_acquire(&qseecom.global_data_lock);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800957 entry = __qseecom_check_app_exists(app_name);
958 if (!entry) {
959 mutex_release(&qseecom.global_data_lock);
960 /* load the app and get the app_id */
961 dprintf(INFO, "%s: Loading app %s for the first time'\n",
962 __func__, app_name);
963
964 ret = __qseecom_load_app(app_name, &app_id);
965 if ((ret < 0) || (app_id ==0)) {
966 dprintf(CRITICAL, "%s: __qseecom_load_app failed with err:%d for app:%s\n",
967 __func__, ret, app_name);
968 ret = GENERIC_ERROR;
969 goto err;
970 }
971 mutex_acquire(&qseecom.global_data_lock);
972 entry = __qseecom_add_app_entry(app_name, app_id);
973 if (!entry)
974 {
975 dprintf(CRITICAL, "%s: __qseecom_add_app_entry failed\n", __func__);
976 ret = GENERIC_ERROR;
977 mutex_release(&qseecom.global_data_lock);
978 goto err;
979 }
980 qseecom.handle++;
981 entry->handle = qseecom.handle;
982 handle = entry->handle;
983 mutex_release(&qseecom.global_data_lock);
984 }
985 else {
986 entry->ref_cnt++;
987 handle = entry->handle;
988 mutex_release(&qseecom.global_data_lock);
989 }
990 return handle;
991err:
992 return ret;
993}
994
995/**
996* Shutdown a Secure App
997*
998* @param int handle
999* Handle of the Secure App to be shutdown
1000*
1001* @return int
1002* Status:
1003* 0 - Success
1004* Negative value indicates failure.
1005*/
1006int qseecom_shutdown_app(int handle)
1007{
1008 int ret = GENERIC_ERROR;
1009 int ref_cnt = 0;
1010 struct qseecom_registered_app_list *entry = NULL;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001011
1012 if (handle <= 0) {
1013 dprintf(CRITICAL, "%s: Invalid Handle %d\n", __func__, handle);
1014 goto err;
1015 }
1016 dprintf(SPEW, "%s called\n", __func__);
1017 mutex_acquire(&qseecom.global_data_lock);
1018 if ((!qseecom.qseecom_init_done)
1019 || (!qseecom.qseecom_tz_init_done)) {
1020 dprintf(CRITICAL, "%s qseecom_init not done\n",
1021 __func__);
1022 mutex_release(&qseecom.global_data_lock);
1023 return ret;
1024 }
1025 entry = __qseecom_check_handle_exists(handle);
1026 if (!entry) {
1027 dprintf(CRITICAL, "%s: Shutdown on an app that was never loaded handle:%d\n",
1028 __func__, handle);
1029 ret = GENERIC_ERROR;
1030 mutex_release(&qseecom.global_data_lock);
1031 goto err;
1032 }
1033
1034 /* Decrement ref_cnt by 1, if ref_cnt is 0 after
1035 * decrementing unload the app by calling into
1036 * TZ else just return.
1037 */
1038
1039 if(entry->ref_cnt != 0)
1040 entry->ref_cnt--;
1041 ref_cnt = entry->ref_cnt;
1042 mutex_release(&qseecom.global_data_lock);
1043 if (ref_cnt == 0) {
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001044 ret = qseecom_unload_app(entry->app_id);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001045 if(ret) {
1046 dprintf(CRITICAL, "%s: qseecom_unload_app failed with err:%d for handle:%d\n",
1047 __func__, ret, handle);
1048 goto err;
1049 }
1050 mutex_acquire(&qseecom.global_data_lock);
1051 ret = __qseecom_remove_app_entry(entry);
1052 mutex_release(&qseecom.global_data_lock);
1053 if(ret) {
1054 dprintf(CRITICAL, "%s: __qseecom_remove_app_entry failed with err:%d for handle:%d\n",
1055 __func__, ret, handle);
1056 goto err;
1057 }
1058 }
1059 ret = 0;
1060err:
1061 return ret;
1062}
1063
1064/**
1065* Send cmd to a Secure App
1066*
1067* @param int handle
1068* Handle of the Secure App to send the cmd
1069*
1070* @param void *send_buf
1071* Pointer to the App request buffer
1072*
1073* @param uint32_t sbuf_len
1074* Size of the request buffer
1075*
1076* @param void *resp_buf
1077* Pointer to the App response buffer
1078*
1079* @param uint32_t rbuf_len
1080* Size of the response buffer
1081*
1082* @return int
1083* Status:
1084* 0 - Success
1085* Negative value indicates failure.
1086*/
1087int qseecom_send_command(int handle, void *send_buf,
1088 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1089{
1090 int ret = GENERIC_ERROR;
1091 uint32_t app_id = 0;
1092 struct qseecom_registered_app_list *entry = NULL;
1093 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001094
1095 if (handle <= 0) {
1096 dprintf(CRITICAL, "%s Handle is Invalid\n", __func__);
1097 return GENERIC_ERROR;
1098 }
1099
1100 if((!send_buf) || (!resp_buf)) {
1101 dprintf(CRITICAL, "%s: Input Buffers invalid\n", __func__);
1102 return GENERIC_ERROR;
1103 }
1104 dprintf(SPEW, "%s called\n", __func__);
1105 mutex_acquire(&qseecom.global_data_lock);
1106 if ((!qseecom.qseecom_init_done)
1107 || (!qseecom.qseecom_tz_init_done)) {
1108 dprintf(CRITICAL, "%s qseecom_init not done\n",
1109 __func__);
1110 mutex_release(&qseecom.global_data_lock);
1111 return ret;
1112 }
1113 entry = __qseecom_check_handle_exists(handle);
1114 if (!entry) {
1115 dprintf(CRITICAL, "%s: Send cmd on an app that was never loaded handle:%d\n",
1116 __func__, handle);
1117 ret = GENERIC_ERROR;
1118 mutex_release(&qseecom.global_data_lock);
1119 goto err;
1120 }
1121
1122 app_id = entry->app_id;
1123 mutex_release(&qseecom.global_data_lock);
1124
1125 req.cmd_req_len = sbuf_len;
1126 req.resp_len = rbuf_len;
1127 req.cmd_req_buf = send_buf;
1128 req.resp_buf = resp_buf;
1129
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001130 ret = __qseecom_send_cmd(app_id, &req);
1131 if (ret) {
1132 dprintf(CRITICAL, "%s __qseecom_send_cmd failed with err:%d for handle:%d\n",
1133 __func__, ret, handle);
1134 goto err;
1135 }
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001136
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001137 ret = 0;
1138 dprintf(SPEW, "sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1139 req.resp_len, req.resp_buf);
1140err:
1141 return ret;
1142}
1143
1144/**
1145* Registers a Listener Service with QSEE
1146*
1147* @param uint32_t listnr_id
1148* Pre-defined Listener ID to be registered
1149*
1150* @param uint32_t sb_size
1151* Shared buffer size required for the listener
1152* service.
1153*
1154* @return int
1155* Status:
1156* 0 - Success
1157* Negative value indicates failure.
1158*/
1159int qseecom_register_listener(struct qseecom_listener_services *listnr)
1160{
1161 int ret = GENERIC_ERROR;
1162 struct qseecom_registered_listener_list *new_entry = NULL;
1163 struct qseecom_register_listener_ireq req;
1164 struct qseecom_command_scm_resp resp;
1165
1166 mutex_acquire(&qseecom.global_data_lock);
1167 if (!qseecom.qseecom_init_done) {
1168 dprintf(CRITICAL, "%s qseecom_init not done\n",
1169 __func__);
1170 mutex_release(&qseecom.global_data_lock);
1171 return ret;
1172 }
1173 mutex_release(&qseecom.global_data_lock);
1174
1175 mutex_acquire(&qseecom.registered_listener_list_lock);
1176
1177 if ((!listnr)) {
1178 dprintf(CRITICAL, "%s Invalid Input listnr\n", __func__);
1179 return GENERIC_ERROR;
1180 }
1181
1182 if ((!listnr->id) || (!listnr->sb_size) || (!listnr->service_cmd_handler)) {
1183 dprintf(CRITICAL, "%s Invalid Input listnr_id:%d sb_size:%d\n",
1184 __func__, listnr->id, listnr->sb_size);
1185 return GENERIC_ERROR;
1186 }
1187 dprintf(SPEW, "%s called\n", __func__);
1188 new_entry = __qseecom_check_listener_exists(listnr->id);
1189 if (new_entry) {
1190 dprintf(CRITICAL, "Service is not unique and is already registered\n");
1191 ret = LISTENER_ALREADY_PRESENT_ERROR;
1192 goto err;
1193 }
1194
1195 new_entry = malloc(sizeof(*new_entry));
1196 if (!new_entry) {
1197 dprintf(CRITICAL, "%s new_entry malloc failed for size:%d\n", __func__, sizeof(*new_entry));
1198 ret = GENERIC_ERROR;
1199 goto err;
1200 }
1201 memset(new_entry, 0, sizeof(*new_entry));
1202 new_entry->svc.listener_id = listnr->id;
1203 new_entry->svc.sb_size = listnr->sb_size;
1204 new_entry->CallbackFn = listnr->service_cmd_handler;
1205
1206 new_entry->svc.virt_sb_base = memalign(PAGE_SIZE, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1207 if (!new_entry->svc.virt_sb_base) {
1208 dprintf(CRITICAL, "%s virt_sb_base malloc failed for size:%d\n", __func__, listnr->sb_size);
1209 ret = GENERIC_ERROR;
1210 goto err;
1211 }
1212 memset(new_entry->svc.virt_sb_base, 0, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1213 arch_clean_invalidate_cache_range((addr_t) new_entry->svc.virt_sb_base, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1214
1215 req.qsee_cmd_id = QSEE_REGISTER_LISTENER;
1216 req.listener_id = new_entry->svc.listener_id;
1217 req.sb_len = new_entry->svc.sb_size;
1218 /* convert to 32bit addr for tz */
1219 req.sb_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) new_entry->svc.virt_sb_base);
1220
1221 resp.result = QSEOS_RESULT_INCOMPLETE;
1222
1223 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1224 sizeof(req), &resp, sizeof(resp));
1225 if (ret) {
1226 dprintf(CRITICAL, "qseecom_scm_call failed with err: %d\n", ret);
1227 ret = GENERIC_ERROR;
1228 goto err;
1229 }
1230 /* Add entry to Listener list */
1231 list_add_tail(&qseecom.registered_listener_list_head, &new_entry->node);
1232err:
1233 if ((ret) &&
1234 (ret != LISTENER_ALREADY_PRESENT_ERROR)) {
1235 if ((new_entry) &&
1236 (new_entry->svc.virt_sb_base))
1237 free(new_entry->svc.virt_sb_base);
1238 if (new_entry)
1239 free(new_entry);
1240 }
1241 mutex_release(&qseecom.registered_listener_list_lock);
1242 return ret;
1243}
1244
1245/**
1246* De-Registers a Listener Service with QSEE
1247*
1248* @param uint32_t listnr_id
1249* Pre-defined Listener ID to be de-registered
1250*
1251* @return int
1252* Status:
1253* 0 - Success
1254* Negative value indicates failure.
1255*/
1256int qseecom_deregister_listener(uint32_t listnr_id)
1257{
1258 int ret = GENERIC_ERROR;
1259 struct qseecom_registered_listener_list *new_entry = NULL;
1260 struct qseecom_unregister_listener_ireq req;
1261 struct qseecom_command_scm_resp resp;
1262
1263 mutex_acquire(&qseecom.global_data_lock);
1264 if (!qseecom.qseecom_init_done) {
1265 dprintf(CRITICAL, "%s qseecom_init not done\n",
1266 __func__);
1267 mutex_release(&qseecom.global_data_lock);
1268 return ret;
1269 }
1270 mutex_release(&qseecom.global_data_lock);
1271
1272 mutex_acquire(&qseecom.registered_listener_list_lock);
1273 dprintf(SPEW, "%s called\n", __func__);
1274 new_entry = __qseecom_check_listener_exists(listnr_id);
1275 if (!new_entry) {
1276 dprintf(CRITICAL, "Service not present\n");
1277 ret = GENERIC_ERROR;
1278 goto err;
1279 }
1280
1281 req.qsee_cmd_id = QSEE_DEREGISTER_LISTENER;
1282 req.listener_id = listnr_id;
1283 resp.result = QSEOS_RESULT_INCOMPLETE;
1284
1285 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1286 sizeof(req), &resp, sizeof(resp));
1287 if (ret) {
1288 dprintf(CRITICAL, "scm_call() failed with err: %d (lstnr id=%d)\n",
1289 ret, req.listener_id);
1290 ret = GENERIC_ERROR;
1291 goto err;
1292 }
1293
1294 list_delete(&new_entry->node);
1295
1296err:
1297 if (ret == 0) {
1298 if (new_entry)
1299 free(new_entry);
1300 }
1301 mutex_release(&qseecom.registered_listener_list_lock);
1302 return ret;
1303}
1304
1305int qseecom_tz_init()
1306{
1307 struct qsee_apps_region_info_ireq req;
1308 struct qseecom_command_scm_resp resp;
1309 int rc = GENERIC_ERROR;
1310 /* register log buffer scm request */
1311 void *buf = NULL;
1312 /* Register app region with TZ */
1313 req.qsee_cmd_id = QSEE_APP_REGION_NOTIFICATION;
1314 req.addr = APP_REGION_ADDR;
1315 req.size = APP_REGION_SIZE;
1316 dprintf(ALWAYS, "secure app region addr=0x%x size=0x%x",
1317 req.addr, req.size);
1318 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1319 &req, sizeof(req),
1320 &resp, sizeof(resp));
1321 dprintf(ALWAYS, "TZ App region notif returned with status:%d addr:%x size:%d\n",
1322 rc, req.addr, req.size);
1323 if (rc)
1324 goto err;
1325 buf = memalign(PAGE_SIZE, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
1326 if (!buf) {
1327 rc = GENERIC_ERROR;
1328 goto err;
1329 }
1330 memset(buf, 0, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
Channagoud Kadabicf3afe42015-08-07 16:08:08 -07001331 /* Make sure the buffer given to TZ is flushed */
1332 arch_clean_invalidate_cache_range((addr_t) buf, QSEE_LOG_BUF_SIZE);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001333 logbuf_req.qsee_cmd_id = QSEE_REGISTER_LOG_BUF_COMMAND;
1334 logbuf_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
1335 logbuf_req.len = QSEE_LOG_BUF_SIZE;
1336
1337 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1338 &logbuf_req, sizeof(logbuf_req),
1339 &resp, sizeof(resp));
1340 dprintf(ALWAYS, "TZ App log region register returned with status:%d addr:%x size:%d\n",
1341 rc, logbuf_req.phy_addr, logbuf_req.len);
1342 if (rc)
1343 goto err;
1344err:
1345 if (!rc) {
1346 qseecom.qseecom_tz_init_done = 1;
1347 dprintf(ALWAYS, "Qseecom TZ Init Done in Appsbl\n");
1348 }
1349 return rc;
1350}
1351
1352int qseecom_init()
1353{
1354 int rc = GENERIC_ERROR;
1355
1356 memset (&qseecom, 0, sizeof(struct qseecom_control));
1357 dprintf(SPEW, "%s called\n", __func__);
1358 mutex_init(&(qseecom.global_data_lock));
1359 mutex_init(&(qseecom.registered_app_list_lock));
1360 mutex_init(&(qseecom.registered_listener_list_lock));
1361
1362 list_initialize(&(qseecom.registered_app_list_head));
1363 list_initialize(&(qseecom.registered_listener_list_head));
1364
1365 qseecom.qseos_version = QSEOS_VERSION_14;
1366 rc = 0;
1367
1368 if (!rc) {
1369 qseecom.qseecom_init_done = 1;
1370 dprintf(ALWAYS, "Qseecom Init Done in Appsbl\n");
1371 }
1372 return rc;
1373}
1374
1375int qseecom_exit()
1376{
1377 dprintf(SPEW, "%s called\n", __func__);
1378
1379 if (logbuf_req.phy_addr)
1380 free((void *)logbuf_req.phy_addr);
1381 qseecom.qseecom_init_done = 0;
1382 dprintf(ALWAYS, "Qseecom De-Init Done in Appsbl\n");
1383 return 0;
1384}