blob: 445904a91b3315d178a937dd211dae6d163c72fa [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;
Zhen Kongab19b062015-10-08 18:33:05 -0700858 void *rsp_buf_temp = NULL;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800859 uint32_t size = 0;
860
861 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
862 dprintf(CRITICAL, "%s: cmd buffer or response buffer is null\n",
863 __func__);
864 return GENERIC_ERROR;
865 }
866 dprintf(SPEW, "%s called\n", __func__);
867
Zhen Kongab19b062015-10-08 18:33:05 -0700868 if (req->cmd_req_len > (UINT_MAX - req->resp_len)) {
869 dprintf(CRITICAL, "%s:Integer overflow\n", __func__);
870 dprintf(CRITICAL, "req->cmd_req_len: %u\n", req->cmd_req_len);
871 dprintf(CRITICAL, "req->resp_len: %u\n", req->resp_len);
872 return GENERIC_ERROR;
873 }
874
875 if ((req->cmd_req_len + req->resp_len) > (RPMB_SND_RCV_BUF_SZ * 1024 * 1024)) {
876 dprintf(CRITICAL, "%s:Cmd + Rsp len greater than TA buf\n", __func__);
877 dprintf(CRITICAL, "req->cmd_req_len: %u\n", req->cmd_req_len);
878 dprintf(CRITICAL, "req->resp_len: %u\n", req->resp_len);
879 return GENERIC_ERROR;
880 }
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800881
882 /* The req rsp buffer will be xPU protected by TZ during a TZ APP call
883 * This will still be protected during a listener call and there is a
884 * possibility of prefetching happening, which will cause xPU violation.
885 * Hence using (device memory with xN set) to prevent I or D prefetching.
886 * This is a contiguous region of 1MB used only for this, hence will not
887 * free this.
888 */
889 buf = (void *)RPMB_SND_RCV_BUF;
890 if (!buf) {
891 dprintf(CRITICAL, "%s: Aloc failed for app_id:%d of size:%d\n",
892 __func__, app_id, size);
893 return GENERIC_ERROR;
894 }
895
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800896 send_data_req.qsee_cmd_id = QSEE_CLIENT_SEND_DATA_COMMAND;
897 send_data_req.app_id = app_id;
898
899 /* Currently on 8994 only 32-bit phy addr is supported
900 * Hence downcasting is okay
901 */
902 send_data_req.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
903 send_data_req.req_len = req->cmd_req_len;
Zhen Kongab19b062015-10-08 18:33:05 -0700904 size = ROUNDUP(req->cmd_req_len, PAGE_SIZE);
905 rsp_buf_temp = (uint8_t *)buf + size;
906 send_data_req.rsp_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t)rsp_buf_temp);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800907 send_data_req.rsp_len = req->resp_len;
908
Zhen Kongab19b062015-10-08 18:33:05 -0700909 memscpy(buf, (RPMB_SND_RCV_BUF_SZ * 1024 * 1024), req->cmd_req_buf, req->cmd_req_len);
910 memscpy(rsp_buf_temp, req->resp_len, req->resp_buf, req->resp_len);
911
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800912 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
913 (void *)&send_data_req,
914 sizeof(send_data_req), (void *)&resp, sizeof(resp));
915
Zhen Kongab19b062015-10-08 18:33:05 -0700916 memscpy(req->cmd_req_buf, req->cmd_req_len, (void *)buf, send_data_req.req_len);
917 memscpy(req->resp_buf, req->resp_len, (void *)rsp_buf_temp, send_data_req.rsp_len);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800918 return ret;
919}
920
921/**
922* Start a Secure App
923*
924* @param char* app_name
925* App name of the Secure App to be started
926*
927* @return int
928* Success: handle to be used for all calls to
929* Secure app. Always greater than zero.
930* Failure: Error code (negative only).
931*/
932int qseecom_start_app(char *app_name)
933{
934 int32_t ret = GENERIC_ERROR;
935 int handle = 0;
936 struct qseecom_registered_app_list *entry = NULL;
937 unsigned int app_id = 0;
938
939 if (!app_name) {
940 dprintf(CRITICAL, "%s: Input error\n", __func__);
941 goto err;
942 }
943 dprintf(SPEW, "%s called\n", __func__);
944
945
946 mutex_acquire(&qseecom.global_data_lock);
947 if ((!qseecom.qseecom_init_done)
948 || (!qseecom.qseecom_tz_init_done)){
949 dprintf(CRITICAL, "%s qseecom_init not done\n",
950 __func__);
951 mutex_release(&qseecom.global_data_lock);
952 return ret;
953 }
Zhen Kong91657682015-09-30 16:27:16 -0700954 mutex_release(&qseecom.global_data_lock);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800955 /* Load commonlib image*/
956 if (!qseecom.cmnlib_loaded) {
957 ret = qseecom_load_commonlib_image("cmnlib");
958 if (ret) {
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800959 dprintf(CRITICAL, "%s qseecom_load_commonlib_image failed with status:%d\n",
960 __func__, ret);
961 goto err;
962 }
Zhen Kongab19b062015-10-08 18:33:05 -0700963 dprintf(DEBUG, "Loading cmnlib done\n");
964#if ENABLE_CMNLIB64_LOADING
965 ret = qseecom_load_commonlib_image("cmnlib64");
966 if (ret) {
967 dprintf(CRITICAL, "%s qseecom_load_commonlib_image failed with status:%d\n",
968 __func__, ret);
969 goto err;
970 }
971 dprintf(DEBUG, "Loading cmnlib64 done\n");
972#endif
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800973 qseecom.cmnlib_loaded = 1;
974 }
975 /* Check if App already exits, if exits increase ref_cnt
976 * and return handle, else load the app from partition,
977 * call into TZ to load it, add to list and then return
978 * handle.
979 */
Zhen Kong91657682015-09-30 16:27:16 -0700980 mutex_acquire(&qseecom.global_data_lock);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -0800981 entry = __qseecom_check_app_exists(app_name);
982 if (!entry) {
983 mutex_release(&qseecom.global_data_lock);
984 /* load the app and get the app_id */
985 dprintf(INFO, "%s: Loading app %s for the first time'\n",
986 __func__, app_name);
987
988 ret = __qseecom_load_app(app_name, &app_id);
989 if ((ret < 0) || (app_id ==0)) {
990 dprintf(CRITICAL, "%s: __qseecom_load_app failed with err:%d for app:%s\n",
991 __func__, ret, app_name);
992 ret = GENERIC_ERROR;
993 goto err;
994 }
995 mutex_acquire(&qseecom.global_data_lock);
996 entry = __qseecom_add_app_entry(app_name, app_id);
997 if (!entry)
998 {
999 dprintf(CRITICAL, "%s: __qseecom_add_app_entry failed\n", __func__);
1000 ret = GENERIC_ERROR;
1001 mutex_release(&qseecom.global_data_lock);
1002 goto err;
1003 }
1004 qseecom.handle++;
1005 entry->handle = qseecom.handle;
1006 handle = entry->handle;
1007 mutex_release(&qseecom.global_data_lock);
1008 }
1009 else {
1010 entry->ref_cnt++;
1011 handle = entry->handle;
1012 mutex_release(&qseecom.global_data_lock);
1013 }
1014 return handle;
1015err:
1016 return ret;
1017}
1018
1019/**
1020* Shutdown a Secure App
1021*
1022* @param int handle
1023* Handle of the Secure App to be shutdown
1024*
1025* @return int
1026* Status:
1027* 0 - Success
1028* Negative value indicates failure.
1029*/
1030int qseecom_shutdown_app(int handle)
1031{
1032 int ret = GENERIC_ERROR;
1033 int ref_cnt = 0;
1034 struct qseecom_registered_app_list *entry = NULL;
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001035
1036 if (handle <= 0) {
1037 dprintf(CRITICAL, "%s: Invalid Handle %d\n", __func__, handle);
1038 goto err;
1039 }
1040 dprintf(SPEW, "%s called\n", __func__);
1041 mutex_acquire(&qseecom.global_data_lock);
1042 if ((!qseecom.qseecom_init_done)
1043 || (!qseecom.qseecom_tz_init_done)) {
1044 dprintf(CRITICAL, "%s qseecom_init not done\n",
1045 __func__);
1046 mutex_release(&qseecom.global_data_lock);
1047 return ret;
1048 }
1049 entry = __qseecom_check_handle_exists(handle);
1050 if (!entry) {
1051 dprintf(CRITICAL, "%s: Shutdown on an app that was never loaded handle:%d\n",
1052 __func__, handle);
1053 ret = GENERIC_ERROR;
1054 mutex_release(&qseecom.global_data_lock);
1055 goto err;
1056 }
1057
1058 /* Decrement ref_cnt by 1, if ref_cnt is 0 after
1059 * decrementing unload the app by calling into
1060 * TZ else just return.
1061 */
1062
1063 if(entry->ref_cnt != 0)
1064 entry->ref_cnt--;
1065 ref_cnt = entry->ref_cnt;
1066 mutex_release(&qseecom.global_data_lock);
1067 if (ref_cnt == 0) {
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001068 ret = qseecom_unload_app(entry->app_id);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001069 if(ret) {
1070 dprintf(CRITICAL, "%s: qseecom_unload_app failed with err:%d for handle:%d\n",
1071 __func__, ret, handle);
1072 goto err;
1073 }
1074 mutex_acquire(&qseecom.global_data_lock);
1075 ret = __qseecom_remove_app_entry(entry);
1076 mutex_release(&qseecom.global_data_lock);
1077 if(ret) {
1078 dprintf(CRITICAL, "%s: __qseecom_remove_app_entry failed with err:%d for handle:%d\n",
1079 __func__, ret, handle);
1080 goto err;
1081 }
1082 }
1083 ret = 0;
1084err:
1085 return ret;
1086}
1087
1088/**
1089* Send cmd to a Secure App
1090*
1091* @param int handle
1092* Handle of the Secure App to send the cmd
1093*
1094* @param void *send_buf
1095* Pointer to the App request buffer
1096*
1097* @param uint32_t sbuf_len
1098* Size of the request buffer
1099*
1100* @param void *resp_buf
1101* Pointer to the App response buffer
1102*
1103* @param uint32_t rbuf_len
1104* Size of the response buffer
1105*
1106* @return int
1107* Status:
1108* 0 - Success
1109* Negative value indicates failure.
1110*/
1111int qseecom_send_command(int handle, void *send_buf,
1112 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1113{
1114 int ret = GENERIC_ERROR;
1115 uint32_t app_id = 0;
1116 struct qseecom_registered_app_list *entry = NULL;
1117 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001118
1119 if (handle <= 0) {
1120 dprintf(CRITICAL, "%s Handle is Invalid\n", __func__);
1121 return GENERIC_ERROR;
1122 }
1123
1124 if((!send_buf) || (!resp_buf)) {
1125 dprintf(CRITICAL, "%s: Input Buffers invalid\n", __func__);
1126 return GENERIC_ERROR;
1127 }
1128 dprintf(SPEW, "%s called\n", __func__);
1129 mutex_acquire(&qseecom.global_data_lock);
1130 if ((!qseecom.qseecom_init_done)
1131 || (!qseecom.qseecom_tz_init_done)) {
1132 dprintf(CRITICAL, "%s qseecom_init not done\n",
1133 __func__);
1134 mutex_release(&qseecom.global_data_lock);
1135 return ret;
1136 }
1137 entry = __qseecom_check_handle_exists(handle);
1138 if (!entry) {
1139 dprintf(CRITICAL, "%s: Send cmd on an app that was never loaded handle:%d\n",
1140 __func__, handle);
1141 ret = GENERIC_ERROR;
1142 mutex_release(&qseecom.global_data_lock);
1143 goto err;
1144 }
1145
1146 app_id = entry->app_id;
1147 mutex_release(&qseecom.global_data_lock);
1148
1149 req.cmd_req_len = sbuf_len;
1150 req.resp_len = rbuf_len;
1151 req.cmd_req_buf = send_buf;
1152 req.resp_buf = resp_buf;
1153
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001154 ret = __qseecom_send_cmd(app_id, &req);
1155 if (ret) {
1156 dprintf(CRITICAL, "%s __qseecom_send_cmd failed with err:%d for handle:%d\n",
1157 __func__, ret, handle);
1158 goto err;
1159 }
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001160
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001161 ret = 0;
1162 dprintf(SPEW, "sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1163 req.resp_len, req.resp_buf);
1164err:
1165 return ret;
1166}
1167
1168/**
1169* Registers a Listener Service with QSEE
1170*
1171* @param uint32_t listnr_id
1172* Pre-defined Listener ID to be registered
1173*
1174* @param uint32_t sb_size
1175* Shared buffer size required for the listener
1176* service.
1177*
1178* @return int
1179* Status:
1180* 0 - Success
1181* Negative value indicates failure.
1182*/
1183int qseecom_register_listener(struct qseecom_listener_services *listnr)
1184{
1185 int ret = GENERIC_ERROR;
1186 struct qseecom_registered_listener_list *new_entry = NULL;
1187 struct qseecom_register_listener_ireq req;
1188 struct qseecom_command_scm_resp resp;
1189
1190 mutex_acquire(&qseecom.global_data_lock);
1191 if (!qseecom.qseecom_init_done) {
1192 dprintf(CRITICAL, "%s qseecom_init not done\n",
1193 __func__);
1194 mutex_release(&qseecom.global_data_lock);
1195 return ret;
1196 }
1197 mutex_release(&qseecom.global_data_lock);
1198
1199 mutex_acquire(&qseecom.registered_listener_list_lock);
1200
1201 if ((!listnr)) {
1202 dprintf(CRITICAL, "%s Invalid Input listnr\n", __func__);
1203 return GENERIC_ERROR;
1204 }
1205
1206 if ((!listnr->id) || (!listnr->sb_size) || (!listnr->service_cmd_handler)) {
1207 dprintf(CRITICAL, "%s Invalid Input listnr_id:%d sb_size:%d\n",
1208 __func__, listnr->id, listnr->sb_size);
1209 return GENERIC_ERROR;
1210 }
1211 dprintf(SPEW, "%s called\n", __func__);
1212 new_entry = __qseecom_check_listener_exists(listnr->id);
1213 if (new_entry) {
1214 dprintf(CRITICAL, "Service is not unique and is already registered\n");
1215 ret = LISTENER_ALREADY_PRESENT_ERROR;
1216 goto err;
1217 }
1218
1219 new_entry = malloc(sizeof(*new_entry));
1220 if (!new_entry) {
1221 dprintf(CRITICAL, "%s new_entry malloc failed for size:%d\n", __func__, sizeof(*new_entry));
1222 ret = GENERIC_ERROR;
1223 goto err;
1224 }
1225 memset(new_entry, 0, sizeof(*new_entry));
1226 new_entry->svc.listener_id = listnr->id;
1227 new_entry->svc.sb_size = listnr->sb_size;
1228 new_entry->CallbackFn = listnr->service_cmd_handler;
1229
1230 new_entry->svc.virt_sb_base = memalign(PAGE_SIZE, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1231 if (!new_entry->svc.virt_sb_base) {
1232 dprintf(CRITICAL, "%s virt_sb_base malloc failed for size:%d\n", __func__, listnr->sb_size);
1233 ret = GENERIC_ERROR;
1234 goto err;
1235 }
1236 memset(new_entry->svc.virt_sb_base, 0, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1237 arch_clean_invalidate_cache_range((addr_t) new_entry->svc.virt_sb_base, ROUNDUP(listnr->sb_size, PAGE_SIZE));
1238
1239 req.qsee_cmd_id = QSEE_REGISTER_LISTENER;
1240 req.listener_id = new_entry->svc.listener_id;
1241 req.sb_len = new_entry->svc.sb_size;
1242 /* convert to 32bit addr for tz */
1243 req.sb_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) new_entry->svc.virt_sb_base);
1244
1245 resp.result = QSEOS_RESULT_INCOMPLETE;
1246
1247 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1248 sizeof(req), &resp, sizeof(resp));
1249 if (ret) {
1250 dprintf(CRITICAL, "qseecom_scm_call failed with err: %d\n", ret);
1251 ret = GENERIC_ERROR;
1252 goto err;
1253 }
1254 /* Add entry to Listener list */
1255 list_add_tail(&qseecom.registered_listener_list_head, &new_entry->node);
1256err:
1257 if ((ret) &&
1258 (ret != LISTENER_ALREADY_PRESENT_ERROR)) {
1259 if ((new_entry) &&
1260 (new_entry->svc.virt_sb_base))
1261 free(new_entry->svc.virt_sb_base);
1262 if (new_entry)
1263 free(new_entry);
1264 }
1265 mutex_release(&qseecom.registered_listener_list_lock);
1266 return ret;
1267}
1268
1269/**
1270* De-Registers a Listener Service with QSEE
1271*
1272* @param uint32_t listnr_id
1273* Pre-defined Listener ID to be de-registered
1274*
1275* @return int
1276* Status:
1277* 0 - Success
1278* Negative value indicates failure.
1279*/
1280int qseecom_deregister_listener(uint32_t listnr_id)
1281{
1282 int ret = GENERIC_ERROR;
1283 struct qseecom_registered_listener_list *new_entry = NULL;
1284 struct qseecom_unregister_listener_ireq req;
1285 struct qseecom_command_scm_resp resp;
1286
1287 mutex_acquire(&qseecom.global_data_lock);
1288 if (!qseecom.qseecom_init_done) {
1289 dprintf(CRITICAL, "%s qseecom_init not done\n",
1290 __func__);
1291 mutex_release(&qseecom.global_data_lock);
1292 return ret;
1293 }
1294 mutex_release(&qseecom.global_data_lock);
1295
1296 mutex_acquire(&qseecom.registered_listener_list_lock);
1297 dprintf(SPEW, "%s called\n", __func__);
1298 new_entry = __qseecom_check_listener_exists(listnr_id);
1299 if (!new_entry) {
1300 dprintf(CRITICAL, "Service not present\n");
1301 ret = GENERIC_ERROR;
1302 goto err;
1303 }
1304
1305 req.qsee_cmd_id = QSEE_DEREGISTER_LISTENER;
1306 req.listener_id = listnr_id;
1307 resp.result = QSEOS_RESULT_INCOMPLETE;
1308
1309 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1310 sizeof(req), &resp, sizeof(resp));
1311 if (ret) {
1312 dprintf(CRITICAL, "scm_call() failed with err: %d (lstnr id=%d)\n",
1313 ret, req.listener_id);
1314 ret = GENERIC_ERROR;
1315 goto err;
1316 }
1317
1318 list_delete(&new_entry->node);
1319
1320err:
1321 if (ret == 0) {
1322 if (new_entry)
1323 free(new_entry);
1324 }
1325 mutex_release(&qseecom.registered_listener_list_lock);
1326 return ret;
1327}
1328
1329int qseecom_tz_init()
1330{
1331 struct qsee_apps_region_info_ireq req;
1332 struct qseecom_command_scm_resp resp;
1333 int rc = GENERIC_ERROR;
1334 /* register log buffer scm request */
1335 void *buf = NULL;
1336 /* Register app region with TZ */
1337 req.qsee_cmd_id = QSEE_APP_REGION_NOTIFICATION;
1338 req.addr = APP_REGION_ADDR;
1339 req.size = APP_REGION_SIZE;
1340 dprintf(ALWAYS, "secure app region addr=0x%x size=0x%x",
1341 req.addr, req.size);
1342 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1343 &req, sizeof(req),
1344 &resp, sizeof(resp));
1345 dprintf(ALWAYS, "TZ App region notif returned with status:%d addr:%x size:%d\n",
1346 rc, req.addr, req.size);
1347 if (rc)
1348 goto err;
1349 buf = memalign(PAGE_SIZE, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
1350 if (!buf) {
1351 rc = GENERIC_ERROR;
1352 goto err;
1353 }
1354 memset(buf, 0, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
Channagoud Kadabicf3afe42015-08-07 16:08:08 -07001355 /* Make sure the buffer given to TZ is flushed */
1356 arch_clean_invalidate_cache_range((addr_t) buf, QSEE_LOG_BUF_SIZE);
Dinesh K Garg6bbbb702015-01-30 11:13:31 -08001357 logbuf_req.qsee_cmd_id = QSEE_REGISTER_LOG_BUF_COMMAND;
1358 logbuf_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
1359 logbuf_req.len = QSEE_LOG_BUF_SIZE;
1360
1361 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1362 &logbuf_req, sizeof(logbuf_req),
1363 &resp, sizeof(resp));
1364 dprintf(ALWAYS, "TZ App log region register returned with status:%d addr:%x size:%d\n",
1365 rc, logbuf_req.phy_addr, logbuf_req.len);
1366 if (rc)
1367 goto err;
1368err:
1369 if (!rc) {
1370 qseecom.qseecom_tz_init_done = 1;
1371 dprintf(ALWAYS, "Qseecom TZ Init Done in Appsbl\n");
1372 }
1373 return rc;
1374}
1375
1376int qseecom_init()
1377{
1378 int rc = GENERIC_ERROR;
1379
1380 memset (&qseecom, 0, sizeof(struct qseecom_control));
1381 dprintf(SPEW, "%s called\n", __func__);
1382 mutex_init(&(qseecom.global_data_lock));
1383 mutex_init(&(qseecom.registered_app_list_lock));
1384 mutex_init(&(qseecom.registered_listener_list_lock));
1385
1386 list_initialize(&(qseecom.registered_app_list_head));
1387 list_initialize(&(qseecom.registered_listener_list_head));
1388
1389 qseecom.qseos_version = QSEOS_VERSION_14;
1390 rc = 0;
1391
1392 if (!rc) {
1393 qseecom.qseecom_init_done = 1;
1394 dprintf(ALWAYS, "Qseecom Init Done in Appsbl\n");
1395 }
1396 return rc;
1397}
1398
1399int qseecom_exit()
1400{
1401 dprintf(SPEW, "%s called\n", __func__);
1402
1403 if (logbuf_req.phy_addr)
1404 free((void *)logbuf_req.phy_addr);
1405 qseecom.qseecom_init_done = 0;
1406 dprintf(ALWAYS, "Qseecom De-Init Done in Appsbl\n");
1407 return 0;
1408}