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