blob: bd073a6ba4f6c7ea6f0eee1aba746a9e10dd29ee [file] [log] [blame]
Dinesh K Garg02ab8bf2015-08-17 15:53:33 -07001/* 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
106static struct qseecom_reg_log_buf_ireq logbuf_req;
107static 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 qseecom_scm_call(uint32_t svc_id, uint32_t tz_cmd_id, void *cmd_buf,
200 size_t cmd_len, void *resp_buf, size_t resp_len)
201{
202 void *req = NULL;
203 struct qseecom_command_scm_resp *resp = NULL;
204 struct qseecom_client_listener_data_irsp send_data_rsp = {0};
205 int ret = GENERIC_ERROR;
206 uint32_t qseos_cmd_id = 0;
207
208 if ((!cmd_buf) || (!resp_buf))
209 return GENERIC_ERROR;
210
211 dprintf(SPEW, "%s called\n", __func__);
212 mutex_acquire(&qseecom.registered_app_list_lock);
213 req = cmd_buf;
214 qseos_cmd_id = *(uint32_t *)req;
215 resp = (struct qseecom_command_scm_resp *) resp_buf;
216
217 do {
218 ret = scm_call(svc_id, tz_cmd_id, req, cmd_len,
219 resp_buf, resp_len);
220
221 if (ret) {
222 dprintf(CRITICAL, "ERROR: scm_call to load failed : ret %d\n", ret);
223 ret = GENERIC_ERROR;
224 goto err;
225 }
226
227 if (svc_id == TZ_CALL) {
228 goto err;
229 }
230
231 switch (resp->result) {
232 case QSEOS_RESULT_SUCCESS:
233 if(((resp->resp_type != QSEOS_APP_ID) || (resp->data <= 0)) &&
234 ((qseos_cmd_id == QSEE_CLIENT_SEND_DATA_COMMAND) ||
235 (qseos_cmd_id == QSEE_LISTENER_DATA_RSP_COMMAND)))
236 {
237 dprintf(CRITICAL, "ERROR: Resp type %d or Resp Data %d incorrect\n",
238 resp->resp_type, resp->data);
239 ret = GENERIC_ERROR;
240 goto err;
241 }
242 goto err;
243 case QSEOS_RESULT_FAILURE:
244 dprintf(CRITICAL, "scm call failed w/response result%d\n", resp->result);
245 ret = GENERIC_ERROR;
246 goto err;
247 case QSEOS_RESULT_INCOMPLETE:
248 if(resp->resp_type != QSEOS_LISTENER_ID)
249 {
250 ret = GENERIC_ERROR;
251 dprintf(CRITICAL, "Listener service incorrect resp->result:%d resp->resp_type:%d\n",
252 resp->result, resp->resp_type);
253 goto err;
254 }
255 __qseecom_process_incomplete_cmd(resp, &send_data_rsp);
256 req = (void *)&send_data_rsp;
257 qseos_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
258 break;
259 default:
260 dprintf(CRITICAL, "scm call return unknown response %d\n", resp->result);
261 ret = GENERIC_ERROR;
262 goto err;
263 }
264 } while(true);
265
266err:
267 mutex_release(&qseecom.registered_app_list_lock);
268 return ret;
269
270}
271
272static int __qseecom_process_incomplete_cmd(struct qseecom_command_scm_resp *resp,
273 struct qseecom_client_listener_data_irsp *send_data_rsp)
274{
275 int ret = 0;
276 struct qseecom_registered_listener_list *entry;
277
278 if ((!resp) || (!send_data_rsp))
279 {
280 return GENERIC_ERROR;
281 }
282
283 dprintf(SPEW, "%s called\n", __func__);
284 mutex_acquire(&qseecom.global_data_lock);
285
286 list_for_every_entry(&qseecom.registered_listener_list_head,
287 entry, struct qseecom_registered_listener_list, node) {
288 if (resp->data == entry->svc.listener_id) {
289 arch_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
290 entry->CallbackFn(entry->svc.virt_sb_base, entry->svc.sb_size);
291 arch_clean_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
292 break;
293 }
294 }
295 send_data_rsp->qsee_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
296 send_data_rsp->listener_id = entry->svc.listener_id;
297 send_data_rsp->status = 0;
298 mutex_release(&qseecom.global_data_lock);
299 return ret;
300}
301
302static int __qseecom_load_app(const char *app_name, unsigned int *app_id)
303{
304 int index = INVALID_PTN;
305 unsigned long long ptn = 0;
306 unsigned long long size = 0;
307 void *buf = NULL;
308 void *req = NULL;
309 struct qseecom_load_app_ireq load_req = {0};
310 struct qseecom_command_scm_resp resp;
311 struct tzdbg_log_t *log = NULL;
312 uint32_t QseeLogStart = 0;
313 uint32_t QseeLogNewStart = 0;
314
315 int ret = GENERIC_ERROR;
316 uint8_t lun = 0;
317
318 if (!app_name)
319 return GENERIC_ERROR;
320
321 dprintf(SPEW, "%s called\n", __func__);
322 index = partition_get_index(app_name);
323 lun = partition_get_lun(index);
324 mmc_set_lun(lun);
325
326 size = partition_get_size(index);
327
328 buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
329 if (!buf) {
330 dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
331 __func__, app_name);
332 ret = GENERIC_ERROR;
333 goto err;
334 }
335
336 ptn = partition_get_offset(index);
337 if(ptn == 0) {
338 dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
339 ret = GENERIC_ERROR;
340 goto err;
341 }
342 if (mmc_read(ptn, (unsigned int *) buf, size)) {
343 dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
344 ret = GENERIC_ERROR;
345 goto err;
346 }
347
348 /* Currently on 8994 only 32-bit phy addr is supported
349 * Hence downcasting is okay
350 */
351 load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
352 load_req.qsee_cmd_id = QSEE_APP_START_COMMAND;
353 load_req.img_len = size;
354 load_req.mdt_len = 0;
355 dprintf(SPEW, "phy_addr:%u img_len:%u\n", load_req.phy_addr, load_req.img_len);
356
357 memscpy(&load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
358 req = (void *)&load_req;
359
360 log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
361 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
362 QseeLogStart = (uint32_t) log->log_pos.offset;
363
364 arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
365 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
366 sizeof(struct qseecom_load_lib_image_ireq),
367 &resp, sizeof(resp));
368 if(ret == 0)
369 *app_id = resp.data;
370 else
371 *app_id = 0;
372 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
373 QseeLogNewStart = (uint32_t) log->log_pos.offset;
374
375 _disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
376 QseeLogStart, QseeLogNewStart);
377err:
378 if (buf)
379 free(buf);
380 return ret;
381}
382
383static int qseecom_load_commonlib_image(char * app_name)
384{
385 int index = INVALID_PTN;
386 unsigned long long ptn = 0;
387 unsigned long long size = 0;
388 void *buf = NULL;
389 void *req = NULL;
390 struct qseecom_load_app_ireq load_req = {0};
391 struct qseecom_command_scm_resp resp = {0};
392 int ret = GENERIC_ERROR;
393 uint8_t lun = 0;
394
395 dprintf(SPEW, "%s called\n", __func__);
396 index = partition_get_index(app_name);
397 lun = partition_get_lun(index);
398 mmc_set_lun(lun);
399
400 size = partition_get_size(index);
401
402 buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
403 if (!buf) {
404 dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
405 __func__, app_name);
406 ret = GENERIC_ERROR;
407 goto err;
408 }
409
410 ptn = partition_get_offset(index);
411 if(ptn == 0) {
412 dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
413 ret = GENERIC_ERROR;
414 goto err;
415 }
416 if (mmc_read(ptn, (unsigned int *) buf, size)) {
417 dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
418 ret = GENERIC_ERROR;
419 goto err;
420 }
421
422 /* Currently on 8994 only 32-bit phy addr is supported
423 * Hence downcasting is okay
424 */
425 load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
426 load_req.qsee_cmd_id = QSEE_LOAD_SERV_IMAGE_COMMAND;
427 load_req.img_len = size;
428 load_req.mdt_len = 0;
429
430 memscpy(load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
431 req = (void *)&load_req;
432
433 arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
434 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
435 sizeof(struct qseecom_load_lib_image_ireq),
436 &resp, sizeof(resp));
437 if(ret == 0)
438 ret = resp.data;
439
440err:
441 if (buf)
442 free(buf);
443 return ret;
444}
445
446static int qseecom_unload_commonlib_image(void)
447{
448 int ret = GENERIC_ERROR;
449 struct qseecom_unload_lib_image_ireq unload_req = {0};
450 struct qseecom_command_scm_resp resp;
451
452 dprintf(SPEW, "%s called\n", __func__);
453 /* Populate the remaining parameters */
454 unload_req.qsee_cmd_id = QSEE_UNLOAD_SERV_IMAGE_COMMAND;
455 /* SCM_CALL to load the image */
456 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
457 sizeof(struct qseecom_unload_lib_image_ireq),
458 &resp, sizeof(resp));
459 return ret;
460}
461
462/*
463 * This function is called with the global
464 * data mutex acquired.
465 */
466static struct qseecom_registered_app_list *
467 __qseecom_add_app_entry(char *app_name, uint32_t app_id)
468{
469 struct qseecom_registered_app_list *entry = NULL;
470 int32_t ret = GENERIC_ERROR;
471
472 if ((!app_name) || (app_id == 0)) {
473 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
474 return NULL;
475 }
476 dprintf(SPEW, "%s called\n", __func__);
477
478 entry = malloc(sizeof(*entry));
479 if (!entry) {
480 dprintf(CRITICAL, "malloc for app entry failed\n");
481 ret = GENERIC_ERROR;
482 goto err;
483 }
484 entry->app_id = app_id;
485 entry->ref_cnt = 1;
486 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
487
488 dprintf(SPEW, "%s: Adding app:%s app_id:%u to list\n", __func__, entry->app_name, entry->app_id);
489 list_add_tail(&qseecom.registered_app_list_head, &entry->node);
490 ret = 0;
491err:
492 if (entry && (ret < 0)) {
493 free(entry);
494 return NULL;
495 }
496 return entry;
497}
498
499/*
500 * This function is called with the global
501 * data mutex acquired.
502 */
503static int
504 __qseecom_remove_app_entry(struct qseecom_registered_app_list *entry)
505{
506 if (!entry) {
507 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
508 return GENERIC_ERROR;
509 }
510 dprintf(SPEW, "%s called\n", __func__);
511 list_delete(&entry->node);
512 free(entry);
513
514 return 0;
515}
516
517/*
518 * This function is called with the global
519 * data mutex acquired.
520 */
521struct qseecom_registered_listener_list *
522 __qseecom_check_listener_exists(uint32_t listener_id)
523{
524 struct qseecom_registered_listener_list *entry = NULL;
525 bool listener_present = false;
526
527 if (!listener_id) {
528 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
529 return NULL;
530 }
531 dprintf(SPEW, "%s called\n", __func__);
532
533 list_for_every_entry(&qseecom.registered_listener_list_head,
534 entry, struct qseecom_registered_listener_list, node) {
535 if (entry->svc.listener_id == listener_id) {
536 listener_present = true;
537 break;
538 }
539 }
540 if (listener_present)
541 return entry;
542 else
543 return NULL;
544}
545
546/*
547 * This function is called with the global
548 * data mutex acquired.
549 */
550static struct qseecom_registered_app_list
551 *__qseecom_check_handle_exists(int handle)
552{
553 struct qseecom_registered_app_list *entry;
554 bool app_present = false;
555
556 if (handle <= 0) {
557 dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
558 return NULL;
559 }
560 dprintf(SPEW, "%s called\n", __func__);
561 list_for_every_entry(&qseecom.registered_app_list_head,
562 entry, struct qseecom_registered_app_list, node) {
563 if (entry->handle == handle) {
564 app_present = true;
565 break;
566 }
567 }
568
569 if (app_present == true)
570 return entry;
571 else
572 return NULL;
573
574}
575
576
577static struct qseecom_registered_app_list *
578 __qseecom_check_app_exists(char *app_name)
579{
580 struct qseecom_registered_app_list *entry = NULL;
581
582 dprintf(SPEW, "%s called\n", __func__);
583 list_for_every_entry(&qseecom.registered_app_list_head,
584 entry, struct qseecom_registered_app_list, node) {
585 if (!strncmp(app_name, entry->app_name, 32)) {
586 dprintf(SPEW, "%s: app_name:%s\n", __func__, app_name);
587 return entry;
588 }
589 }
590 return NULL;
591}
592
593static int qseecom_unload_app(uint32_t app_id)
594{
595 int ret = 0;
596 struct qseecom_command_scm_resp resp;
597 struct qseecom_unload_app_ireq req;
598
599 dprintf(SPEW, "%s called\n", __func__);
600 /* Populate the structure for sending scm call to load image */
601 req.qsee_cmd_id = QSEE_APP_SHUTDOWN_COMMAND;
602 req.app_id = app_id;
603
604 /* SCM_CALL to unload the app */
605 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
606 sizeof(struct qseecom_unload_app_ireq),
607 &resp, sizeof(resp));
608
609 return ret;
610}
611
612
613static int __qseecom_send_cmd(uint32_t app_id, struct qseecom_send_cmd_req *req)
614{
615 int ret = 0;
616 struct qseecom_client_send_data_ireq send_data_req;
617 struct qseecom_command_scm_resp resp;
618 void *buf = NULL;
619 uint32_t size = 0;
620
621 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
622 dprintf(CRITICAL, "%s: cmd buffer or response buffer is null\n",
623 __func__);
624 return GENERIC_ERROR;
625 }
626 dprintf(SPEW, "%s called\n", __func__);
627
628 /* Allocate for req or rsp len whichever is higher, both req and rsp point
629 * to the same buffer
630 */
631 size = (req->cmd_req_len > req->resp_len) ? req->cmd_req_len : req->resp_len;
632
633 /* The req rsp buffer will be xPU protected by TZ during a TZ APP call
634 * This will still be protected during a listener call and there is a
635 * possibility of prefetching happening, which will cause xPU violation.
636 * Hence using (device memory with xN set) to prevent I or D prefetching.
637 * This is a contiguous region of 1MB used only for this, hence will not
638 * free this.
639 */
640 buf = (void *)RPMB_SND_RCV_BUF;
641 if (!buf) {
642 dprintf(CRITICAL, "%s: Aloc failed for app_id:%d of size:%d\n",
643 __func__, app_id, size);
644 return GENERIC_ERROR;
645 }
646
647 memscpy(buf, ROUNDUP(size, PAGE_SIZE), req->cmd_req_buf, req->cmd_req_len);
648
649 send_data_req.qsee_cmd_id = QSEE_CLIENT_SEND_DATA_COMMAND;
650 send_data_req.app_id = app_id;
651
652 /* Currently on 8994 only 32-bit phy addr is supported
653 * Hence downcasting is okay
654 */
655 send_data_req.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
656 send_data_req.req_len = req->cmd_req_len;
657 send_data_req.rsp_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
658 send_data_req.rsp_len = req->resp_len;
659
660 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
661 (void *)&send_data_req,
662 sizeof(send_data_req), (void *)&resp, sizeof(resp));
663
664 memscpy(req->resp_buf, req->resp_len, (void *)send_data_req.rsp_ptr, send_data_req.rsp_len);
665 return ret;
666}
667
668/**
669* Start a Secure App
670*
671* @param char* app_name
672* App name of the Secure App to be started
673*
674* @return int
675* Success: handle to be used for all calls to
676* Secure app. Always greater than zero.
677* Failure: Error code (negative only).
678*/
679int qseecom_start_app(char *app_name)
680{
681 int32_t ret = GENERIC_ERROR;
682 int handle = 0;
683 struct qseecom_registered_app_list *entry = NULL;
684 unsigned int app_id = 0;
685
686 if (!app_name) {
687 dprintf(CRITICAL, "%s: Input error\n", __func__);
688 goto err;
689 }
690 dprintf(SPEW, "%s called\n", __func__);
691
692
693 mutex_acquire(&qseecom.global_data_lock);
694 if ((!qseecom.qseecom_init_done)
695 || (!qseecom.qseecom_tz_init_done)){
696 dprintf(CRITICAL, "%s qseecom_init not done\n",
697 __func__);
698 mutex_release(&qseecom.global_data_lock);
699 return ret;
700 }
701 /* Load commonlib image*/
702 if (!qseecom.cmnlib_loaded) {
703 ret = qseecom_load_commonlib_image("cmnlib");
704 if (ret) {
705 mutex_release(&qseecom.global_data_lock);
706 dprintf(CRITICAL, "%s qseecom_load_commonlib_image failed with status:%d\n",
707 __func__, ret);
708 goto err;
709 }
710 qseecom.cmnlib_loaded = 1;
711 }
712 /* Check if App already exits, if exits increase ref_cnt
713 * and return handle, else load the app from partition,
714 * call into TZ to load it, add to list and then return
715 * handle.
716 */
717
718 entry = __qseecom_check_app_exists(app_name);
719 if (!entry) {
720 mutex_release(&qseecom.global_data_lock);
721 /* load the app and get the app_id */
722 dprintf(INFO, "%s: Loading app %s for the first time'\n",
723 __func__, app_name);
724
725 ret = __qseecom_load_app(app_name, &app_id);
726 if ((ret < 0) || (app_id ==0)) {
727 dprintf(CRITICAL, "%s: __qseecom_load_app failed with err:%d for app:%s\n",
728 __func__, ret, app_name);
729 ret = GENERIC_ERROR;
730 goto err;
731 }
732 mutex_acquire(&qseecom.global_data_lock);
733 entry = __qseecom_add_app_entry(app_name, app_id);
734 if (!entry)
735 {
736 dprintf(CRITICAL, "%s: __qseecom_add_app_entry failed\n", __func__);
737 ret = GENERIC_ERROR;
738 mutex_release(&qseecom.global_data_lock);
739 goto err;
740 }
741 qseecom.handle++;
742 entry->handle = qseecom.handle;
743 handle = entry->handle;
744 mutex_release(&qseecom.global_data_lock);
745 }
746 else {
747 entry->ref_cnt++;
748 handle = entry->handle;
749 mutex_release(&qseecom.global_data_lock);
750 }
751 return handle;
752err:
753 return ret;
754}
755
756/**
757* Shutdown a Secure App
758*
759* @param int handle
760* Handle of the Secure App to be shutdown
761*
762* @return int
763* Status:
764* 0 - Success
765* Negative value indicates failure.
766*/
767int qseecom_shutdown_app(int handle)
768{
769 int ret = GENERIC_ERROR;
770 int ref_cnt = 0;
771 struct qseecom_registered_app_list *entry = NULL;
772 struct tzdbg_log_t *log = NULL;
773 uint32_t QseeLogStart = 0;
774 uint32_t QseeLogNewStart = 0;
775
776 if (handle <= 0) {
777 dprintf(CRITICAL, "%s: Invalid Handle %d\n", __func__, handle);
778 goto err;
779 }
780 dprintf(SPEW, "%s called\n", __func__);
781 mutex_acquire(&qseecom.global_data_lock);
782 if ((!qseecom.qseecom_init_done)
783 || (!qseecom.qseecom_tz_init_done)) {
784 dprintf(CRITICAL, "%s qseecom_init not done\n",
785 __func__);
786 mutex_release(&qseecom.global_data_lock);
787 return ret;
788 }
789 entry = __qseecom_check_handle_exists(handle);
790 if (!entry) {
791 dprintf(CRITICAL, "%s: Shutdown on an app that was never loaded handle:%d\n",
792 __func__, handle);
793 ret = GENERIC_ERROR;
794 mutex_release(&qseecom.global_data_lock);
795 goto err;
796 }
797
798 /* Decrement ref_cnt by 1, if ref_cnt is 0 after
799 * decrementing unload the app by calling into
800 * TZ else just return.
801 */
802
803 if(entry->ref_cnt != 0)
804 entry->ref_cnt--;
805 ref_cnt = entry->ref_cnt;
806 mutex_release(&qseecom.global_data_lock);
807 if (ref_cnt == 0) {
808 log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
809 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
810 QseeLogStart = (uint32_t) log->log_pos.offset;
811
812 ret = qseecom_unload_app(entry->app_id);
813 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
814 QseeLogNewStart = (uint32_t) log->log_pos.offset;
815
816 _disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
817 QseeLogStart, QseeLogNewStart);
818 if(ret) {
819 dprintf(CRITICAL, "%s: qseecom_unload_app failed with err:%d for handle:%d\n",
820 __func__, ret, handle);
821 goto err;
822 }
823 mutex_acquire(&qseecom.global_data_lock);
824 ret = __qseecom_remove_app_entry(entry);
825 mutex_release(&qseecom.global_data_lock);
826 if(ret) {
827 dprintf(CRITICAL, "%s: __qseecom_remove_app_entry failed with err:%d for handle:%d\n",
828 __func__, ret, handle);
829 goto err;
830 }
831 }
832 ret = 0;
833err:
834 return ret;
835}
836
837/**
838* Send cmd to a Secure App
839*
840* @param int handle
841* Handle of the Secure App to send the cmd
842*
843* @param void *send_buf
844* Pointer to the App request buffer
845*
846* @param uint32_t sbuf_len
847* Size of the request buffer
848*
849* @param void *resp_buf
850* Pointer to the App response buffer
851*
852* @param uint32_t rbuf_len
853* Size of the response buffer
854*
855* @return int
856* Status:
857* 0 - Success
858* Negative value indicates failure.
859*/
860int qseecom_send_command(int handle, void *send_buf,
861 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
862{
863 int ret = GENERIC_ERROR;
864 uint32_t app_id = 0;
865 struct qseecom_registered_app_list *entry = NULL;
866 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
867 struct tzdbg_log_t *log = NULL;
868 uint32_t QseeLogStart = 0;
869 uint32_t QseeLogNewStart = 0;
870
871 if (handle <= 0) {
872 dprintf(CRITICAL, "%s Handle is Invalid\n", __func__);
873 return GENERIC_ERROR;
874 }
875
876 if((!send_buf) || (!resp_buf)) {
877 dprintf(CRITICAL, "%s: Input Buffers invalid\n", __func__);
878 return GENERIC_ERROR;
879 }
880 dprintf(SPEW, "%s called\n", __func__);
881 mutex_acquire(&qseecom.global_data_lock);
882 if ((!qseecom.qseecom_init_done)
883 || (!qseecom.qseecom_tz_init_done)) {
884 dprintf(CRITICAL, "%s qseecom_init not done\n",
885 __func__);
886 mutex_release(&qseecom.global_data_lock);
887 return ret;
888 }
889 entry = __qseecom_check_handle_exists(handle);
890 if (!entry) {
891 dprintf(CRITICAL, "%s: Send cmd on an app that was never loaded handle:%d\n",
892 __func__, handle);
893 ret = GENERIC_ERROR;
894 mutex_release(&qseecom.global_data_lock);
895 goto err;
896 }
897
898 app_id = entry->app_id;
899 mutex_release(&qseecom.global_data_lock);
900
901 req.cmd_req_len = sbuf_len;
902 req.resp_len = rbuf_len;
903 req.cmd_req_buf = send_buf;
904 req.resp_buf = resp_buf;
905
906 log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
907 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
908 QseeLogStart = (uint32_t) log->log_pos.offset;
909
910 ret = __qseecom_send_cmd(app_id, &req);
911 if (ret) {
912 dprintf(CRITICAL, "%s __qseecom_send_cmd failed with err:%d for handle:%d\n",
913 __func__, ret, handle);
914 goto err;
915 }
916 arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
917 QseeLogNewStart = (uint32_t) log->log_pos.offset;
918
919 _disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
920 QseeLogStart, QseeLogNewStart);
921 ret = 0;
922 dprintf(SPEW, "sending cmd_req->rsp size: %u, ptr: 0x%p\n",
923 req.resp_len, req.resp_buf);
924err:
925 return ret;
926}
927
928/**
929* Registers a Listener Service with QSEE
930*
931* @param uint32_t listnr_id
932* Pre-defined Listener ID to be registered
933*
934* @param uint32_t sb_size
935* Shared buffer size required for the listener
936* service.
937*
938* @return int
939* Status:
940* 0 - Success
941* Negative value indicates failure.
942*/
943int qseecom_register_listener(struct qseecom_listener_services *listnr)
944{
945 int ret = GENERIC_ERROR;
946 struct qseecom_registered_listener_list *new_entry = NULL;
947 struct qseecom_register_listener_ireq req;
948 struct qseecom_command_scm_resp resp;
949
950 mutex_acquire(&qseecom.global_data_lock);
951 if (!qseecom.qseecom_init_done) {
952 dprintf(CRITICAL, "%s qseecom_init not done\n",
953 __func__);
954 mutex_release(&qseecom.global_data_lock);
955 return ret;
956 }
957 mutex_release(&qseecom.global_data_lock);
958
959 mutex_acquire(&qseecom.registered_listener_list_lock);
960
961 if ((!listnr)) {
962 dprintf(CRITICAL, "%s Invalid Input listnr\n", __func__);
963 return GENERIC_ERROR;
964 }
965
966 if ((!listnr->id) || (!listnr->sb_size) || (!listnr->service_cmd_handler)) {
967 dprintf(CRITICAL, "%s Invalid Input listnr_id:%d sb_size:%d\n",
968 __func__, listnr->id, listnr->sb_size);
969 return GENERIC_ERROR;
970 }
971 dprintf(SPEW, "%s called\n", __func__);
972 new_entry = __qseecom_check_listener_exists(listnr->id);
973 if (new_entry) {
974 dprintf(CRITICAL, "Service is not unique and is already registered\n");
975 ret = LISTENER_ALREADY_PRESENT_ERROR;
976 goto err;
977 }
978
979 new_entry = malloc(sizeof(*new_entry));
980 if (!new_entry) {
981 dprintf(CRITICAL, "%s new_entry malloc failed for size:%d\n", __func__, sizeof(*new_entry));
982 ret = GENERIC_ERROR;
983 goto err;
984 }
985 memset(new_entry, 0, sizeof(*new_entry));
986 new_entry->svc.listener_id = listnr->id;
987 new_entry->svc.sb_size = listnr->sb_size;
988 new_entry->CallbackFn = listnr->service_cmd_handler;
989
990 new_entry->svc.virt_sb_base = memalign(PAGE_SIZE, ROUNDUP(listnr->sb_size, PAGE_SIZE));
991 if (!new_entry->svc.virt_sb_base) {
992 dprintf(CRITICAL, "%s virt_sb_base malloc failed for size:%d\n", __func__, listnr->sb_size);
993 ret = GENERIC_ERROR;
994 goto err;
995 }
996 memset(new_entry->svc.virt_sb_base, 0, ROUNDUP(listnr->sb_size, PAGE_SIZE));
997 arch_clean_invalidate_cache_range((addr_t) new_entry->svc.virt_sb_base, ROUNDUP(listnr->sb_size, PAGE_SIZE));
998
999 req.qsee_cmd_id = QSEE_REGISTER_LISTENER;
1000 req.listener_id = new_entry->svc.listener_id;
1001 req.sb_len = new_entry->svc.sb_size;
1002 /* convert to 32bit addr for tz */
1003 req.sb_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) new_entry->svc.virt_sb_base);
1004
1005 resp.result = QSEOS_RESULT_INCOMPLETE;
1006
1007 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1008 sizeof(req), &resp, sizeof(resp));
1009 if (ret) {
1010 dprintf(CRITICAL, "qseecom_scm_call failed with err: %d\n", ret);
1011 ret = GENERIC_ERROR;
1012 goto err;
1013 }
1014 /* Add entry to Listener list */
1015 list_add_tail(&qseecom.registered_listener_list_head, &new_entry->node);
1016err:
1017 if ((ret) &&
1018 (ret != LISTENER_ALREADY_PRESENT_ERROR)) {
1019 if ((new_entry) &&
1020 (new_entry->svc.virt_sb_base))
1021 free(new_entry->svc.virt_sb_base);
1022 if (new_entry)
1023 free(new_entry);
1024 }
1025 mutex_release(&qseecom.registered_listener_list_lock);
1026 return ret;
1027}
1028
1029/**
1030* De-Registers a Listener Service with QSEE
1031*
1032* @param uint32_t listnr_id
1033* Pre-defined Listener ID to be de-registered
1034*
1035* @return int
1036* Status:
1037* 0 - Success
1038* Negative value indicates failure.
1039*/
1040int qseecom_deregister_listener(uint32_t listnr_id)
1041{
1042 int ret = GENERIC_ERROR;
1043 struct qseecom_registered_listener_list *new_entry = NULL;
1044 struct qseecom_unregister_listener_ireq req;
1045 struct qseecom_command_scm_resp resp;
1046
1047 mutex_acquire(&qseecom.global_data_lock);
1048 if (!qseecom.qseecom_init_done) {
1049 dprintf(CRITICAL, "%s qseecom_init not done\n",
1050 __func__);
1051 mutex_release(&qseecom.global_data_lock);
1052 return ret;
1053 }
1054 mutex_release(&qseecom.global_data_lock);
1055
1056 mutex_acquire(&qseecom.registered_listener_list_lock);
1057 dprintf(SPEW, "%s called\n", __func__);
1058 new_entry = __qseecom_check_listener_exists(listnr_id);
1059 if (!new_entry) {
1060 dprintf(CRITICAL, "Service not present\n");
1061 ret = GENERIC_ERROR;
1062 goto err;
1063 }
1064
1065 req.qsee_cmd_id = QSEE_DEREGISTER_LISTENER;
1066 req.listener_id = listnr_id;
1067 resp.result = QSEOS_RESULT_INCOMPLETE;
1068
1069 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1070 sizeof(req), &resp, sizeof(resp));
1071 if (ret) {
1072 dprintf(CRITICAL, "scm_call() failed with err: %d (lstnr id=%d)\n",
1073 ret, req.listener_id);
1074 ret = GENERIC_ERROR;
1075 goto err;
1076 }
1077
1078 list_delete(&new_entry->node);
1079
1080err:
1081 if (ret == 0) {
1082 if (new_entry)
1083 free(new_entry);
1084 }
1085 mutex_release(&qseecom.registered_listener_list_lock);
1086 return ret;
1087}
1088
1089int qseecom_tz_init()
1090{
1091 struct qsee_apps_region_info_ireq req;
1092 struct qseecom_command_scm_resp resp;
1093 int rc = GENERIC_ERROR;
1094 /* register log buffer scm request */
1095 void *buf = NULL;
1096 /* Register app region with TZ */
1097 req.qsee_cmd_id = QSEE_APP_REGION_NOTIFICATION;
1098 req.addr = APP_REGION_ADDR;
1099 req.size = APP_REGION_SIZE;
1100 dprintf(ALWAYS, "secure app region addr=0x%x size=0x%x",
1101 req.addr, req.size);
1102 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1103 &req, sizeof(req),
1104 &resp, sizeof(resp));
1105 dprintf(ALWAYS, "TZ App region notif returned with status:%d addr:%x size:%d\n",
1106 rc, req.addr, req.size);
1107 if (rc)
1108 goto err;
1109 buf = memalign(PAGE_SIZE, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
1110 if (!buf) {
1111 rc = GENERIC_ERROR;
1112 goto err;
1113 }
1114 memset(buf, 0, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
1115 logbuf_req.qsee_cmd_id = QSEE_REGISTER_LOG_BUF_COMMAND;
1116 logbuf_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
1117 logbuf_req.len = QSEE_LOG_BUF_SIZE;
1118
1119 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1120 &logbuf_req, sizeof(logbuf_req),
1121 &resp, sizeof(resp));
1122 dprintf(ALWAYS, "TZ App log region register returned with status:%d addr:%x size:%d\n",
1123 rc, logbuf_req.phy_addr, logbuf_req.len);
1124 if (rc)
1125 goto err;
1126err:
1127 if (!rc) {
1128 qseecom.qseecom_tz_init_done = 1;
1129 dprintf(ALWAYS, "Qseecom TZ Init Done in Appsbl\n");
1130 }
1131 return rc;
1132}
1133
1134int qseecom_init()
1135{
1136 int rc = GENERIC_ERROR;
1137
1138 memset (&qseecom, 0, sizeof(struct qseecom_control));
1139 dprintf(SPEW, "%s called\n", __func__);
1140 mutex_init(&(qseecom.global_data_lock));
1141 mutex_init(&(qseecom.registered_app_list_lock));
1142 mutex_init(&(qseecom.registered_listener_list_lock));
1143
1144 list_initialize(&(qseecom.registered_app_list_head));
1145 list_initialize(&(qseecom.registered_listener_list_head));
1146
1147 qseecom.qseos_version = QSEOS_VERSION_14;
1148 rc = 0;
1149
1150 if (!rc) {
1151 qseecom.qseecom_init_done = 1;
1152 dprintf(ALWAYS, "Qseecom Init Done in Appsbl\n");
1153 }
1154 return rc;
1155}
1156
1157int qseecom_exit()
1158{
1159 dprintf(SPEW, "%s called\n", __func__);
1160
1161 if (logbuf_req.phy_addr)
1162 free((void *)logbuf_req.phy_addr);
1163 qseecom.qseecom_init_done = 0;
1164 dprintf(ALWAYS, "Qseecom De-Init Done in Appsbl\n");
1165 return 0;
1166}